File manager - Edit - /home/opticamezl/www/newok/com_workflow.tar
Back
forms/transition.xml 0000644 00000003250 15172633314 0010613 0 ustar 00 <?xml version="1.0" encoding="UTF-8"?> <form> <fieldset name="transition" addfieldprefix="Joomla\Component\Workflow\Administrator\Field"> <field name="id" type="hidden" label="JGLOBAL_FIELD_ID_LABEL" default="0" class="readonly" readonly="true" /> <field name="title" type="text" label="COM_WORKFLOW_FIELD_NAME_LABEL" required="true" /> <field name="from_stage_id" type="sql" label="COM_WORKFLOW_FROM_STAGE" required="true" sql_select="id as value, title as from_stage_id" sql_from="#__workflow_stages" sql_order="ordering" translate="true" > <option value="-1">JALL</option> </field> <field name="to_stage_id" type="sql" label="COM_WORKFLOW_TO_STAGE" required="true" sql_select="id as value, title as to_stage_id" sql_from="#__workflow_stages" sql_order="ordering" translate="true" /> <field name="description" type="textarea" label="COM_WORKFLOW_TRANSITION_NOTE" rows="3" cols="60" /> </fieldset> <fieldset name="params" label="COM_WORKFLOW_PARAMS_LABEL"> <field name="published" type="list" label="COM_WORKFLOW_PUBLISHED_LABEL" required="true" class="form-select-color-state" default="1" validate="options" > <option value="1">JENABLED</option> <option value="0">JDISABLED</option> <option value="-2">JTRASHED</option> </field> </fieldset> <fieldset name="permissions" label="JCONFIG_PERMISSIONS_LABEL"> <field name="asset_id" type="hidden" filter="unset" /> <field name="rules" type="rules" label="JCONFIG_PERMISSIONS_LABEL" validate="rules" filter="rules" section="transition" /> </fieldset> </form> forms/stage.xml 0000644 00000002603 15172633314 0007525 0 ustar 00 <?xml version="1.0" encoding="UTF-8"?> <form> <fieldset name="stage" addfieldprefix="Joomla\Component\Workflow\Administrator\Field"> <field name="id" type="text" label="JGLOBAL_FIELD_ID_LABEL" default="0" class="readonly" readonly="true" /> <field name="title" type="text" label="COM_WORKFLOW_FIELD_NAME_LABEL" required="true" /> <field name="description" type="textarea" label="COM_WORKFLOW_STAGE_NOTE" rows="3" cols="60" /> </fieldset> <fieldset name="params" label="COM_WORKFLOW_PARAMS_LABEL"> <field name="published" type="list" label="COM_WORKFLOW_PUBLISHED_LABEL" required="true" class="form-select-color-state" default="1" validate="options" > <option value="1">JENABLED</option> <option value="0">JDISABLED</option> <option value="-2">JTRASHED</option> </field> <field name="default" type="radio" label="COM_WORKFLOW_FIELD_IS_DEFAULT_LABEL" layout="joomla.form.field.radio.switcher" default="0" > <option value="0">JNO</option> <option value="1">JYES</option> </field> </fieldset> <fieldset name="permissions" label="JCONFIG_PERMISSIONS_LABEL"> <field name="asset_id" type="hidden" filter="unset" /> <field name="rules" type="rules" label="JCONFIG_PERMISSIONS_LABEL" validate="rules" filter="rules" section="stage" /> </fieldset> </form> forms/filter_stages.xml 0000644 00000002431 15172633314 0011254 0 ustar 00 <?xml version="1.0" encoding="UTF-8"?> <form> <fields name="filter"> <field name="search" type="text" inputmode="search" label="COM_WORKFLOW_FILTER_SEARCH_LABEL" hint="JSEARCH_FILTER" /> <field name="published" type="status" label="JSTATUS" class="js-select-submit-on-change" optionsFilter="-2,0,1" > <option value="">JOPTION_SELECT_PUBLISHED</option> </field> </fields> <fields name="list"> <field name="fullordering" type="list" label="JGLOBAL_SORT_BY" default="s.ordering ASC" class="js-select-submit-on-change" validate="options" > <option value="">JGLOBAL_SORT_BY</option> <option value="s.ordering ASC">JGRID_HEADING_ORDERING_ASC</option> <option value="s.ordering DESC">JGRID_HEADING_ORDERING_DESC</option> <option value="s.published ASC">JSTATUS_ASC</option> <option value="s.published DESC">JSTATUS_DESC</option> <option value="s.title ASC">JGLOBAL_NAME_ASC</option> <option value="s.title DESC">JGLOBAL_NAME_DESC</option> <option value="s.id ASC">JGRID_HEADING_ID_ASC</option> <option value="s.id DESC">JGRID_HEADING_ID_DESC</option> </field> <field name="limit" type="limitbox" label="JGLOBAL_LIST_LIMIT" default="25" class="js-select-submit-on-change" /> </fields> </form> forms/filter_transitions.xml 0000644 00000004224 15172633314 0012345 0 ustar 00 <?xml version="1.0" encoding="UTF-8"?> <form> <fields name="filter"> <field name="search" type="text" inputmode="search" label="COM_WORKFLOW_FILTER_SEARCH_LABEL" hint="JSEARCH_FILTER" /> <field name="published" type="status" label="JSTATUS" class="js-select-submit-on-change" optionsFilter="-2,0,1" > <option value="">JOPTION_SELECT_PUBLISHED</option> </field> <field name="from_stage" type="sql" label="COM_WORKFLOW_FROM_STAGE" class="js-select-submit-on-change" sql_select="id as value, title as from_stage" sql_from="#__workflow_stages" translate="true" > <option value="">COM_WORKFLOW_SELECT_FROM_STAGE</option> </field> <field name="to_stage" type="sql" label="COM_WORKFLOW_TO_STAGE" class="js-select-submit-on-change" sql_select="id as value, title as to_stage" sql_from="#__workflow_stages" translate="true" > <option value="">COM_WORKFLOW_SELECT_TO_STAGE</option> </field> </fields> <fields name="list"> <field name="fullordering" type="list" label="JGLOBAL_SORT_BY" default="t.ordering ASC" class="js-select-submit-on-change" validate="options" > <option value="">JGLOBAL_SORT_BY</option> <option value="t.ordering ASC">JGRID_HEADING_ORDERING_ASC</option> <option value="t.ordering DESC">JGRID_HEADING_ORDERING_DESC</option> <option value="t.published ASC">JSTATUS_ASC</option> <option value="t.published DESC">JSTATUS_DESC</option> <option value="t.title ASC">JGLOBAL_NAME_ASC</option> <option value="t.title DESC">JGLOBAL_NAME_DESC</option> <option value="from_stage ASC">COM_WORKFLOW_FROM_STAGE_FILTER_ASC</option> <option value="from_stage DESC">COM_WORKFLOW_FROM_STAGE_FILTER_DESC</option> <option value="to_stage ASC">COM_WORKFLOW_TO_STAGE_FILTER_ASC</option> <option value="to_stage DESC">COM_WORKFLOW_TO_STAGE_FILTER_DESC</option> <option value="t.id ASC">JGRID_HEADING_ID_ASC</option> <option value="t.id DESC">JGRID_HEADING_ID_DESC</option> </field> <field name="limit" type="limitbox" label="JGLOBAL_LIST_LIMIT" default="25" class="js-select-submit-on-change" /> </fields> </form> forms/filter_workflows.xml 0000644 00000003053 15172633314 0012024 0 ustar 00 <?xml version="1.0" encoding="UTF-8"?> <form addfieldprefix="Joomla\Component\Workflow\Administrator\Field"> <fieldset name="group"> <field name="extension" type="workflowcontexts" filtermode="selector" class="js-select-submit-on-change" /> </fieldset> <fields name="filter"> <field name="search" type="text" inputmode="search" label="COM_WORKFLOW_FILTER_SEARCH_LABEL" description="COM_WORKFLOW_FILTER_SEARCH_DESC" hint="JSEARCH_FILTER" /> <field name="published" type="status" label="JSTATUS" class="js-select-submit-on-change" optionsFilter="-2,0,1" > <option value="">JOPTION_SELECT_PUBLISHED</option> </field> </fields> <fields name="list"> <field name="fullordering" type="list" label="JGLOBAL_SORT_BY" default="w.ordering ASC" class="js-select-submit-on-change" validate="options" > <option value="">JGLOBAL_SORT_BY</option> <option value="w.ordering ASC">JGRID_HEADING_ORDERING_ASC</option> <option value="w.ordering DESC">JGRID_HEADING_ORDERING_DESC</option> <option value="w.published ASC">JSTATUS_ASC</option> <option value="w.published DESC">JSTATUS_DESC</option> <option value="w.title ASC">JGLOBAL_NAME_ASC</option> <option value="w.title DESC">JGLOBAL_NAME_DESC</option> <option value="w.id ASC">JGRID_HEADING_ID_ASC</option> <option value="w.id DESC">JGRID_HEADING_ID_DESC</option> </field> <field name="limit" type="limitbox" label="JGLOBAL_LIST_LIMIT" default="25" class="js-select-submit-on-change" /> </fields> </form> forms/workflow.xml 0000644 00000003227 15172633314 0010277 0 ustar 00 <?xml version="1.0" encoding="UTF-8"?> <form> <fieldset name="workflow" addfieldprefix="Joomla\Component\Workflow\Administrator\Field"> <field name="id" type="hidden" label="JGLOBAL_FIELD_ID_LABEL" default="0" class="readonly" readonly="true" /> <field name="extension" type="hidden" /> <field name="title" type="text" label="COM_WORKFLOW_FIELD_NAME_LABEL" required="true" /> <field name="description" type="textarea" label="COM_WORKFLOW_WORKFLOW_NOTE" rows="3" cols="60" /> </fieldset> <fieldset name="params" label="COM_WORKFLOW_PARAMS_LABEL"> <field name="published" type="list" label="COM_WORKFLOW_PUBLISHED_LABEL" required="true" class="form-select-color-state" default="1" validate="options" > <option value="1">JENABLED</option> <option value="0">JDISABLED</option> <option value="-2">JTRASHED</option> </field> <field name="default" type="radio" label="COM_WORKFLOW_FIELD_IS_DEFAULT_LABEL" layout="joomla.form.field.radio.switcher" default="0" > <option value="0">JNO</option> <option value="1">JYES</option> </field> <field name="created" type="hidden" label="COM_WORKFLOW_CREATED_LABEL" readonly="true" /> <field name="modified" type="hidden" label="COM_WORKFLOW_MODIFIED_LABEL" readonly="true" /> </fieldset> <fieldset name="permissions" label="JCONFIG_PERMISSIONS_LABEL"> <field name="asset_id" type="hidden" filter="unset" /> <field name="rules" type="rules" label="JCONFIG_PERMISSIONS_LABEL" validate="rules" filter="rules" section="workflow" /> </fieldset> </form> services/provider.php 0000644 00000003105 15172633314 0010736 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ defined('_JEXEC') or die; use Joomla\CMS\Dispatcher\ComponentDispatcherFactoryInterface; use Joomla\CMS\Extension\ComponentInterface; use Joomla\CMS\Extension\MVCComponent; use Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory; use Joomla\CMS\Extension\Service\Provider\MVCFactory; use Joomla\CMS\MVC\Factory\MVCFactoryInterface; use Joomla\DI\Container; use Joomla\DI\ServiceProviderInterface; /** * The workflow service provider. * * @since 4.0.0 */ return new class () implements ServiceProviderInterface { /** * Registers the service provider with a DI container. * * @param Container $container The DI container. * * @return void * * @since 4.0.0 */ public function register(Container $container) { $container->registerServiceProvider(new MVCFactory('\\Joomla\\Component\\Workflow')); $container->registerServiceProvider(new ComponentDispatcherFactory('\\Joomla\\Component\\Workflow')); $container->set( ComponentInterface::class, function (Container $container) { $component = new MVCComponent($container->get(ComponentDispatcherFactoryInterface::class)); $component->setMVCFactory($container->get(MVCFactoryInterface::class)); return $component; } ); } }; workflow.xml 0000644 00000002004 15172633314 0007141 0 ustar 00 <?xml version="1.0" encoding="UTF-8"?> <extension type="component" method="upgrade"> <name>com_workflow</name> <author>Joomla! Project</author> <creationDate>2017-06</creationDate> <copyright>(C) 2018 Open Source Matters, Inc.</copyright> <license>GNU General Public License version 2 or later; see LICENSE.txt</license> <authorEmail>admin@joomla.org</authorEmail> <authorUrl>www.joomla.org</authorUrl> <version>4.0.0</version> <description>COM_WORKFLOW_XML_DESCRIPTION</description> <namespace path="src">Joomla\Component\Workflow</namespace> <administration> <menu>COM_WORKFLOW</menu> <files folder="admin"> <filename>access.xml</filename> <filename>workflow.xml</filename> <folder>forms</folder> <folder>services</folder> <folder>src</folder> <folder>tmpl</folder> </files> <languages folder="admin"> <language tag="en-GB">language/en-GB/com_workflow.ini</language> <language tag="en-GB">language/en-GB/com_workflow.sys.ini</language> </languages> </administration> </extension> src/Controller/StageController.php 0000644 00000012103 15172633314 0013300 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Workflow\Administrator\Controller; use Joomla\CMS\Application\CMSApplication; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\Controller\FormController; use Joomla\CMS\MVC\Factory\MVCFactoryInterface; use Joomla\Input\Input; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * The stage controller * * @since 4.0.0 */ class StageController extends FormController { /** * The workflow in where the stage belongs to * * @var integer * @since 4.0.0 */ protected $workflowId; /** * The extension * * @var string * @since 4.0.0 */ protected $extension; /** * The section of the current extension * * @var string * @since 4.0.0 */ protected $section; /** * Constructor. * * @param array $config An optional associative array of configuration settings. * @param MVCFactoryInterface $factory The factory. * @param CMSApplication $app The Application for the dispatcher * @param Input $input Input * * @since 4.0.0 * @throws \InvalidArgumentException when no extension or workflow id is set */ public function __construct($config = [], MVCFactoryInterface $factory = null, $app = null, $input = null) { parent::__construct($config, $factory, $app, $input); // If workflow id is not set try to get it from input or throw an exception if (empty($this->workflowId)) { $this->workflowId = $this->input->getInt('workflow_id'); if (empty($this->workflowId)) { throw new \InvalidArgumentException(Text::_('COM_WORKFLOW_ERROR_WORKFLOW_ID_NOT_SET')); } } // If extension is not set try to get it from input or throw an exception if (empty($this->extension)) { $extension = $this->input->getCmd('extension'); $parts = explode('.', $extension); $this->extension = array_shift($parts); if (!empty($parts)) { $this->section = array_shift($parts); } if (empty($this->extension)) { throw new \InvalidArgumentException(Text::_('COM_WORKFLOW_ERROR_EXTENSION_NOT_SET')); } } } /** * Method to check if you can add a new record. * * @param array $data An array of input data. * * @return boolean * * @since 4.0.0 */ protected function allowAdd($data = []) { return $this->app->getIdentity()->authorise('core.create', $this->extension . '.workflow.' . (int) $this->workflowId); } /** * Method to check if you can edit a record. * * @param array $data An array of input data. * @param string $key The name of the key for the primary key. * * @return boolean * * @since 4.0.0 */ protected function allowEdit($data = [], $key = 'id') { $recordId = isset($data[$key]) ? (int) $data[$key] : 0; $user = $this->app->getIdentity(); $record = $this->getModel()->getItem($recordId); if (empty($record->id)) { return false; } // Check "edit" permission on record asset (explicit or inherited) if ($user->authorise('core.edit', $this->extension . '.stage.' . $recordId)) { return true; } // Check "edit own" permission on record asset (explicit or inherited) if ($user->authorise('core.edit.own', $this->extension . '.stage.' . $recordId)) { return !empty($record) && $record->created_by == $user->id; } return false; } /** * Gets the URL arguments to append to an item redirect. * * @param integer $recordId The primary key id for the item. * @param string $urlVar The name of the URL variable for the id. * * @return string The arguments to append to the redirect URL. * * @since 4.0.0 */ protected function getRedirectToItemAppend($recordId = null, $urlVar = 'id') { $append = parent::getRedirectToItemAppend($recordId); $append .= '&workflow_id=' . $this->workflowId . '&extension=' . $this->extension . ($this->section ? '.' . $this->section : ''); return $append; } /** * Gets the URL arguments to append to a list redirect. * * @return string The arguments to append to the redirect URL. * * @since 4.0.0 */ protected function getRedirectToListAppend() { $append = parent::getRedirectToListAppend(); $append .= '&workflow_id=' . $this->workflowId . '&extension=' . $this->extension . ($this->section ? '.' . $this->section : ''); return $append; } } src/Controller/TransitionController.php 0000644 00000012011 15172633314 0014365 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Workflow\Administrator\Controller; use Joomla\CMS\Application\CMSApplication; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\Controller\FormController; use Joomla\CMS\MVC\Factory\MVCFactoryInterface; use Joomla\Input\Input; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Transition controller * * @since 4.0.0 */ class TransitionController extends FormController { /** * The workflow where the transition takes place * * @var integer * @since 4.0.0 */ protected $workflowId; /** * The extension * * @var string * @since 4.0.0 */ protected $extension; /** * The section of the current extension * * @var string * @since 4.0.0 */ protected $section; /** * Constructor. * * @param array $config An optional associative array of configuration settings. * @param MVCFactoryInterface $factory The factory. * @param CMSApplication $app The Application for the dispatcher * @param Input $input Input * * @since 4.0.0 * @throws \InvalidArgumentException when no extension or workflow id is set */ public function __construct($config = [], MVCFactoryInterface $factory = null, $app = null, $input = null) { parent::__construct($config, $factory, $app, $input); // If workflow id is not set try to get it from input or throw an exception if (empty($this->workflowId)) { $this->workflowId = $this->input->getInt('workflow_id'); if (empty($this->workflowId)) { throw new \InvalidArgumentException(Text::_('COM_WORKFLOW_ERROR_WORKFLOW_ID_NOT_SET')); } } // If extension is not set try to get it from input or throw an exception if (empty($this->extension)) { $extension = $this->input->getCmd('extension'); $parts = explode('.', $extension); $this->extension = array_shift($parts); if (!empty($parts)) { $this->section = array_shift($parts); } if (empty($this->extension)) { throw new \InvalidArgumentException(Text::_('COM_WORKFLOW_ERROR_EXTENSION_NOT_SET')); } } } /** * Method to check if you can add a new record. * * @param array $data An array of input data. * * @return boolean * * @since 4.0.0 */ protected function allowAdd($data = []) { return $this->app->getIdentity()->authorise('core.create', $this->extension . '.workflow.' . (int) $this->workflowId); } /** * Method to check if you can edit a record. * * @param array $data An array of input data. * @param string $key The name of the key for the primary key. * * @return boolean * * @since 4.0.0 */ protected function allowEdit($data = [], $key = 'id') { $recordId = isset($data[$key]) ? (int) $data[$key] : 0; $user = $this->app->getIdentity(); $model = $this->getModel(); $item = $model->getItem($recordId); if (empty($item->id)) { return false; } // Check "edit" permission on record asset (explicit or inherited) if ($user->authorise('core.edit', $this->extension . '.transition.' . $recordId)) { return true; } // Check "edit own" permission on record asset (explicit or inherited) if ($user->authorise('core.edit.own', $this->extension . '.transition.' . $recordId)) { return !empty($item) && $item->created_by == $user->id; } return false; } /** * Gets the URL arguments to append to an item redirect. * * @param integer $recordId The primary key id for the item. * @param string $urlVar The name of the URL variable for the id. * * @return string The arguments to append to the redirect URL. * * @since 4.0.0 */ protected function getRedirectToItemAppend($recordId = null, $urlVar = 'id') { $append = parent::getRedirectToItemAppend($recordId); $append .= '&workflow_id=' . $this->workflowId . '&extension=' . $this->extension; return $append; } /** * Gets the URL arguments to append to a list redirect. * * @return string The arguments to append to the redirect URL. * * @since 4.0.0 */ protected function getRedirectToListAppend() { $append = parent::getRedirectToListAppend(); $append .= '&workflow_id=' . $this->workflowId . '&extension=' . $this->extension; return $append; } } src/Controller/StagesController.php 0000644 00000013332 15172633314 0013470 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Workflow\Administrator\Controller; use Joomla\CMS\Application\CMSApplication; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\Controller\AdminController; use Joomla\CMS\MVC\Factory\MVCFactoryInterface; use Joomla\CMS\Router\Route; use Joomla\Input\Input; use Joomla\Utilities\ArrayHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * The workflow stages controller * * @since 4.0.0 */ class StagesController extends AdminController { /** * The workflow in where the stage belongs to * * @var integer * @since 4.0.0 */ protected $workflowId; /** * The extension * * @var string * @since 4.0.0 */ protected $extension; /** * The section of the current extension * * @var string * @since 4.0.0 */ protected $section; /** * The prefix to use with controller messages. * * @var string * @since 4.0.0 */ protected $text_prefix = 'COM_WORKFLOW_STAGES'; /** * Constructor. * * @param array $config An optional associative array of configuration settings. * @param MVCFactoryInterface $factory The factory. * @param CMSApplication $app The Application for the dispatcher * @param Input $input Input * * @since 4.0.0 * @throws \InvalidArgumentException when no extension or workflow id is set */ public function __construct(array $config = [], MVCFactoryInterface $factory = null, $app = null, $input = null) { parent::__construct($config, $factory, $app, $input); // If workflow id is not set try to get it from input or throw an exception if (empty($this->workflowId)) { $this->workflowId = $this->input->getInt('workflow_id'); if (empty($this->workflowId)) { throw new \InvalidArgumentException(Text::_('COM_WORKFLOW_ERROR_WORKFLOW_ID_NOT_SET')); } } // If extension is not set try to get it from input or throw an exception if (empty($this->extension)) { $extension = $this->input->getCmd('extension'); $parts = explode('.', $extension); $this->extension = array_shift($parts); if (!empty($parts)) { $this->section = array_shift($parts); } if (empty($this->extension)) { throw new \InvalidArgumentException(Text::_('COM_WORKFLOW_ERROR_EXTENSION_NOT_SET')); } } $this->registerTask('unsetDefault', 'setDefault'); } /** * Proxy for getModel * * @param string $name The model name. Optional. * @param string $prefix The class prefix. Optional. * @param array $config The array of possible config values. Optional. * * @return \Joomla\CMS\MVC\Model\BaseDatabaseModel The model. * * @since 4.0.0 */ public function getModel($name = 'Stage', $prefix = 'Administrator', $config = ['ignore_request' => true]) { return parent::getModel($name, $prefix, $config); } /** * Method to set the home property for a list of items * * @return void * * @since 4.0.0 */ public function setDefault() { // Check for request forgeries $this->checkToken(); // Get items to publish from the request. $cid = (array) $this->input->get('cid', [], 'int'); $data = ['setDefault' => 1, 'unsetDefault' => 0]; $task = $this->getTask(); $value = ArrayHelper::getValue($data, $task, 0, 'int'); if (!$value) { $this->setMessage(Text::_('COM_WORKFLOW_DISABLE_DEFAULT'), 'warning'); $this->setRedirect( Route::_( 'index.php?option=' . $this->option . '&view=' . $this->view_list . '&extension=' . $this->extension, false ) ); return; } // Remove zero values resulting from input filter $cid = array_filter($cid); if (empty($cid)) { $this->setMessage(Text::_('COM_WORKFLOW_NO_ITEM_SELECTED'), 'warning'); } elseif (count($cid) > 1) { $this->setMessage(Text::_('COM_WORKFLOW_TOO_MANY_STAGES'), 'error'); } else { // Get the model. $model = $this->getModel(); // Make sure the item ids are integers $id = reset($cid); // Publish the items. if (!$model->setDefault($id, $value)) { $this->setMessage($model->getError(), 'warning'); } else { $this->setMessage(Text::_('COM_WORKFLOW_STAGE_SET_DEFAULT')); } } $this->setRedirect( Route::_( 'index.php?option=' . $this->option . '&view=' . $this->view_list . '&extension=' . $this->extension . '&workflow_id=' . $this->workflowId, false ) ); } /** * Gets the URL arguments to append to a list redirect. * * @return string The arguments to append to the redirect URL. * * @since 4.0.0 */ protected function getRedirectToListAppend() { return '&extension=' . $this->extension . ($this->section ? '.' . $this->section : '') . '&workflow_id=' . $this->workflowId; } } src/Controller/WorkflowController.php 0000644 00000016130 15172633314 0014053 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Workflow\Administrator\Controller; use Joomla\CMS\Application\CMSApplication; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\Controller\FormController; use Joomla\CMS\MVC\Factory\MVCFactoryInterface; use Joomla\CMS\MVC\Model\BaseDatabaseModel; use Joomla\Database\ParameterType; use Joomla\Input\Input; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Workflow controller * * @since 4.0.0 */ class WorkflowController extends FormController { /** * The extension for which the workflows apply. * * @var string * @since 4.0.0 */ protected $extension; /** * The section of the current extension * * @var string * @since 4.0.0 */ protected $section; /** * Constructor. * * @param array $config An optional associative array of configuration settings. * @param MVCFactoryInterface $factory The factory. * @param CMSApplication $app The Application for the dispatcher * @param Input $input Input * * @since 4.0.0 * @throws \InvalidArgumentException when no extension is set */ public function __construct($config = [], MVCFactoryInterface $factory = null, $app = null, $input = null) { parent::__construct($config, $factory, $app, $input); // If extension is not set try to get it from input or throw an exception if (empty($this->extension)) { $extension = $this->input->getCmd('extension'); $parts = explode('.', $extension); $this->extension = array_shift($parts); if (!empty($parts)) { $this->section = array_shift($parts); } if (empty($this->extension)) { throw new \InvalidArgumentException(Text::_('COM_WORKFLOW_ERROR_EXTENSION_NOT_SET')); } } } /** * Method to check if you can add a new record. * * @param array $data An array of input data. * * @return boolean * * @since 4.0.0 */ protected function allowAdd($data = []) { return $this->app->getIdentity()->authorise('core.create', $this->extension); } /** * Method to check if you can edit a record. * * @param array $data An array of input data. * @param string $key The name of the key for the primary key. * * @return boolean * * @since 4.0.0 */ protected function allowEdit($data = [], $key = 'id') { $recordId = isset($data[$key]) ? (int) $data[$key] : 0; $user = $this->app->getIdentity(); $record = $this->getModel()->getItem($recordId); if (empty($record->id)) { return false; } // Check "edit" permission on record asset (explicit or inherited) if ($user->authorise('core.edit', $this->extension . '.workflow.' . $recordId)) { return true; } // Check "edit own" permission on record asset (explicit or inherited) if ($user->authorise('core.edit.own', $this->extension . '.workflow.' . $recordId)) { return !empty($record) && $record->created_by == $user->id; } return false; } /** * Gets the URL arguments to append to an item redirect. * * @param integer $recordId The primary key id for the item. * @param string $urlVar The name of the URL variable for the id. * * @return string The arguments to append to the redirect URL. * * @since 4.0.0 */ protected function getRedirectToItemAppend($recordId = null, $urlVar = 'id') { $append = parent::getRedirectToItemAppend($recordId); $append .= '&extension=' . $this->extension . ($this->section ? '.' . $this->section : ''); return $append; } /** * Gets the URL arguments to append to a list redirect. * * @return string The arguments to append to the redirect URL. * * @since 4.0.0 */ protected function getRedirectToListAppend() { $append = parent::getRedirectToListAppend(); $append .= '&extension=' . $this->extension . ($this->section ? '.' . $this->section : ''); return $append; } /** * Function that allows child controller access to model data * after the data has been saved. * * @param BaseDatabaseModel $model The data model object. * @param array $validData The validated data. * * @return void * * @since 4.0.0 */ public function postSaveHook(BaseDatabaseModel $model, $validData = []) { $task = $this->getTask(); // The save2copy task needs to be handled slightly differently. if ($task === 'save2copy') { $table = $model->getTable(); $key = $table->getKeyName(); $recordId = (int) $this->input->getInt($key); // @todo Moves queries out of the controller. $db = $model->getDbo(); $query = $db->getQuery(true); $query->select('*') ->from($db->quoteName('#__workflow_stages')) ->where($db->quoteName('workflow_id') . ' = :id') ->bind(':id', $recordId, ParameterType::INTEGER); $statuses = $db->setQuery($query)->loadAssocList(); $smodel = $this->getModel('Stage'); $workflowID = (int) $model->getState($model->getName() . '.id'); $mapping = []; foreach ($statuses as $status) { $table = $smodel->getTable(); $oldID = $status['id']; $status['workflow_id'] = $workflowID; $status['id'] = 0; unset($status['asset_id']); $table->save($status); $mapping[$oldID] = (int) $table->id; } $query = $db->getQuery(true) ->select('*') ->from($db->quoteName('#__workflow_transitions')) ->where($db->quoteName('workflow_id') . ' = :id') ->bind(':id', $recordId, ParameterType::INTEGER); $transitions = $db->setQuery($query)->loadAssocList(); $tmodel = $this->getModel('Transition'); foreach ($transitions as $transition) { $table = $tmodel->getTable(); $transition['from_stage_id'] = $transition['from_stage_id'] != -1 ? $mapping[$transition['from_stage_id']] : -1; $transition['to_stage_id'] = $mapping[$transition['to_stage_id']]; $transition['workflow_id'] = $workflowID; $transition['id'] = 0; unset($transition['asset_id']); $table->save($transition); } } } } src/Controller/DisplayController.php 0000644 00000007127 15172633314 0013654 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Workflow\Administrator\Controller; use Joomla\CMS\Application\CMSApplication; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\Controller\BaseController; use Joomla\CMS\MVC\Factory\MVCFactoryInterface; use Joomla\CMS\Router\Route; use Joomla\Input\Input; use Joomla\String\Inflector; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Workflow base controller package. * * @since 4.0.0 */ class DisplayController extends BaseController { /** * The default view. * * @var string * @since 4.0.0 */ protected $default_view = 'workflows'; /** * The extension for which the workflow apply. * * @var string * @since 4.0.0 */ protected $extension; /** * The section of the current extension * * @var string * @since 4.0.0 */ protected $section; /** * Constructor. * * @param array $config An optional associative array of configuration settings. * @param MVCFactoryInterface $factory The factory. * @param CMSApplication $app The Application for the dispatcher * @param Input $input Input * * @since 4.0.0 * @throws \InvalidArgumentException when no extension is set */ public function __construct($config = [], MVCFactoryInterface $factory = null, $app = null, $input = null) { parent::__construct($config, $factory, $app, $input); // If extension is not set try to get it from input or throw an exception if (empty($this->extension)) { $extension = $this->input->getCmd('extension'); $parts = explode('.', $extension); $this->extension = array_shift($parts); if (!empty($parts)) { $this->section = array_shift($parts); } if (empty($this->extension)) { throw new \InvalidArgumentException(Text::_('COM_WORKFLOW_ERROR_EXTENSION_NOT_SET')); } } } /** * Method to display a view. * * @param boolean $cachable If true, the view output will be cached * @param array $urlparams An array of safe URL parameters and their variable types, for valid values see {@link JFilterInput::clean()}. * * @return BaseController|boolean This object to support chaining. * * @since 1.5 */ public function display($cachable = false, $urlparams = []) { $view = $this->input->get('view'); $layout = $this->input->get('layout'); $id = $this->input->getInt('id'); // Check for edit form. if (in_array($view, ['workflow', 'stage', 'transition']) && $layout == 'edit' && !$this->checkEditId('com_workflow.edit.' . $view, $id)) { // Somehow the person just went to the form - we don't allow that. if (!\count($this->app->getMessageQueue())) { $this->setMessage(Text::sprintf('JLIB_APPLICATION_ERROR_UNHELD_ID', $id), 'error'); } $url = 'index.php?option=com_workflow&view=' . Inflector::pluralize($view) . '&extension=' . $this->input->getCmd('extension'); $this->setRedirect(Route::_($url, false)); return false; } return parent::display(); } } src/Controller/TransitionsController.php 0000644 00000007432 15172633314 0014563 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Workflow\Administrator\Controller; use Joomla\CMS\Application\CMSApplication; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\Controller\AdminController; use Joomla\CMS\MVC\Factory\MVCFactoryInterface; use Joomla\Input\Input; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Workflow Transitions controller * * @since 4.0.0 */ class TransitionsController extends AdminController { /** * The workflow where the transition takes place * * @var integer * @since 4.0.0 */ protected $workflowId; /** * The extension * * @var string * @since 4.0.0 */ protected $extension; /** * The section of the current extension * * @var string * @since 4.0.0 */ protected $section; /** * The prefix to use with controller messages. * * @var string * @since 4.0.0 */ protected $text_prefix = 'COM_WORKFLOW_TRANSITIONS'; /** * Constructor. * * @param array $config An optional associative array of configuration settings. * @param MVCFactoryInterface $factory The factory. * @param CMSApplication $app The Application for the dispatcher * @param Input $input Input * * @since 4.0.0 * @throws \InvalidArgumentException when no extension or workflow id is set */ public function __construct($config = [], MVCFactoryInterface $factory = null, $app = null, $input = null) { parent::__construct($config, $factory, $app, $input); // If workflow id is not set try to get it from input or throw an exception if (empty($this->workflowId)) { $this->workflowId = $this->input->getInt('workflow_id'); if (empty($this->workflowId)) { throw new \InvalidArgumentException(Text::_('COM_WORKFLOW_ERROR_WORKFLOW_ID_NOT_SET')); } } // If extension is not set try to get it from input or throw an exception if (empty($this->extension)) { $extension = $this->input->getCmd('extension'); $parts = explode('.', $extension); $this->extension = array_shift($parts); if (!empty($parts)) { $this->section = array_shift($parts); } if (empty($this->extension)) { throw new \InvalidArgumentException(Text::_('COM_WORKFLOW_ERROR_EXTENSION_NOT_SET')); } } } /** * Proxy for getModel * * @param string $name The model name. Optional. * @param string $prefix The class prefix. Optional. * @param array $config The array of possible config values. Optional. * * @return \Joomla\CMS\MVC\Model\BaseDatabaseModel The model. * * @since 4.0.0 */ public function getModel($name = 'Transition', $prefix = 'Administrator', $config = ['ignore_request' => true]) { return parent::getModel($name, $prefix, $config); } /** * Gets the URL arguments to append to a list redirect. * * @return string The arguments to append to the redirect URL. * * @since 4.0.0 */ protected function getRedirectToListAppend() { $append = parent::getRedirectToListAppend(); $append .= '&extension=' . $this->extension . ($this->section ? '.' . $this->section : '') . '&workflow_id=' . $this->workflowId; return $append; } } src/Controller/WorkflowsController.php 0000644 00000012367 15172633314 0014246 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Workflow\Administrator\Controller; use Joomla\CMS\Application\CMSApplication; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\Controller\AdminController; use Joomla\CMS\MVC\Factory\MVCFactoryInterface; use Joomla\CMS\Router\Route; use Joomla\Input\Input; use Joomla\Utilities\ArrayHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Workflows controller * * @since 4.0.0 */ class WorkflowsController extends AdminController { /** * The extension for which the workflows apply. * * @var string * @since 4.0.0 */ protected $extension; /** * The section of the current extension * * @var string * @since 4.0.0 */ protected $section; /** * Constructor. * * @param array $config An optional associative array of configuration settings. * @param MVCFactoryInterface $factory The factory. * @param CMSApplication $app The Application for the dispatcher * @param Input $input Input * * @since 4.0.0 * @throws \InvalidArgumentException when no extension is set */ public function __construct($config = [], MVCFactoryInterface $factory = null, $app = null, $input = null) { parent::__construct($config, $factory, $app, $input); // If extension is not set try to get it from input or throw an exception if (empty($this->extension)) { $extension = $this->input->getCmd('extension'); $parts = explode('.', $extension); $this->extension = array_shift($parts); if (!empty($parts)) { $this->section = array_shift($parts); } if (empty($this->extension)) { throw new \InvalidArgumentException(Text::_('COM_WORKFLOW_ERROR_EXTENSION_NOT_SET')); } } $this->registerTask('unsetDefault', 'setDefault'); } /** * Proxy for getModel * * @param string $name The model name. Optional. * @param string $prefix The class prefix. Optional. * @param array $config The array of possible config values. Optional. * * @return \Joomla\CMS\MVC\Model\BaseDatabaseModel The model. * * @since 4.0.0 */ public function getModel($name = 'Workflow', $prefix = 'Administrator', $config = ['ignore_request' => true]) { return parent::getModel($name, $prefix, $config); } /** * Method to set the home property for a list of items * * @return void * * @since 4.0.0 */ public function setDefault() { // Check for request forgeries $this->checkToken(); // Get items to publish from the request. $cid = (array) $this->input->get('cid', [], 'int'); $data = ['setDefault' => 1, 'unsetDefault' => 0]; $task = $this->getTask(); $value = ArrayHelper::getValue($data, $task, 0, 'int'); if (!$value) { $this->setMessage(Text::_('COM_WORKFLOW_DISABLE_DEFAULT'), 'warning'); $this->setRedirect( Route::_( 'index.php?option=' . $this->option . '&view=' . $this->view_list . '&extension=' . $this->extension . ($this->section ? '.' . $this->section : ''), false ) ); return; } // Remove zero values resulting from input filter $cid = array_filter($cid); if (empty($cid)) { $this->setMessage(Text::_('COM_WORKFLOW_NO_ITEM_SELECTED'), 'warning'); } elseif (count($cid) > 1) { $this->setMessage(Text::_('COM_WORKFLOW_TOO_MANY_WORKFLOWS'), 'error'); } else { // Get the model. $model = $this->getModel(); // Make sure the item ids are integers $id = reset($cid); // Publish the items. if (!$model->setDefault($id, $value)) { $this->setMessage($model->getError(), 'warning'); } else { if ($value === 1) { $ntext = 'COM_WORKFLOW_SET_DEFAULT'; } else { $ntext = 'COM_WORKFLOW_ITEM_UNSET_DEFAULT'; } $this->setMessage(Text::_($ntext, count($cid))); } } $this->setRedirect( Route::_( 'index.php?option=' . $this->option . '&view=' . $this->view_list . '&extension=' . $this->extension . ($this->section ? '.' . $this->section : ''), false ) ); } /** * Gets the URL arguments to append to a list redirect. * * @return string The arguments to append to the redirect URL. * * @since 4.0.0 */ protected function getRedirectToListAppend() { return '&extension=' . $this->extension . ($this->section ? '.' . $this->section : ''); } } src/View/Workflows/HtmlView.php 0000644 00000011434 15172633314 0012522 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Workflow\Administrator\View\Workflows; use Joomla\CMS\Factory; use Joomla\CMS\Helper\ContentHelper; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\View\GenericDataException; use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView; use Joomla\CMS\Toolbar\Button\DropdownButton; use Joomla\CMS\Toolbar\Toolbar; use Joomla\CMS\Toolbar\ToolbarHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Workflows view class for the Workflow package. * * @since 4.0.0 */ class HtmlView extends BaseHtmlView { /** * An array of workflows * * @var array * @since 4.0.0 */ protected $workflows; /** * The model state * * @var object * @since 4.0.0 */ protected $state; /** * The pagination object * * @var \Joomla\CMS\Pagination\Pagination * @since 4.0.0 */ protected $pagination; /** * The HTML for displaying sidebar * * @var string * @since 4.0.0 */ protected $sidebar; /** * Form object for search filters * * @var \Joomla\CMS\Form\Form * @since 4.0.0 */ public $filterForm; /** * The active search filters * * @var array * @since 4.0.0 */ public $activeFilters; /** * The name of current extension * * @var string * @since 4.0.0 */ protected $extension; /** * The section of the current extension * * @var string * @since 4.0.0 */ protected $section; /** * Display the view * * @param string $tpl The name of the template file to parse; automatically searches through the template paths. * * @return void * * @since 4.0.0 */ public function display($tpl = null) { $this->state = $this->get('State'); $this->workflows = $this->get('Items'); $this->pagination = $this->get('Pagination'); $this->filterForm = $this->get('FilterForm'); $this->activeFilters = $this->get('ActiveFilters'); // Check for errors. if (count($errors = $this->get('Errors'))) { throw new GenericDataException(implode("\n", $errors), 500); } $extension = $this->state->get('filter.extension'); $parts = explode('.', $extension); $this->extension = array_shift($parts); if (!empty($parts)) { $this->section = array_shift($parts); } $this->addToolbar(); parent::display($tpl); } /** * Add the page title and toolbar. * * @return void * * @since 4.0.0 */ protected function addToolbar() { $canDo = ContentHelper::getActions($this->extension, $this->section); $user = Factory::getApplication()->getIdentity(); $toolbar = Toolbar::getInstance(); ToolbarHelper::title(Text::_('COM_WORKFLOW_WORKFLOWS_LIST'), 'file-alt contact'); if ($canDo->get('core.create')) { $toolbar->addNew('workflow.add'); } if ($canDo->get('core.edit.state') || $user->authorise('core.admin')) { /** @var DropdownButton $dropdown */ $dropdown = $toolbar->dropdownButton('status-group', 'JTOOLBAR_CHANGE_STATUS') ->toggleSplit(false) ->icon('icon-ellipsis-h') ->buttonClass('btn btn-action') ->listCheck(true); $childBar = $dropdown->getChildToolbar(); $childBar->publish('workflows.publish', 'JTOOLBAR_ENABLE'); $childBar->unpublish('workflows.unpublish', 'JTOOLBAR_DISABLE'); $childBar->makeDefault('workflows.setDefault', 'COM_WORKFLOW_TOOLBAR_DEFAULT'); if ($canDo->get('core.admin')) { $childBar->checkin('workflows.checkin')->listCheck(true); } if ($canDo->get('core.edit.state') && $this->state->get('filter.published') != -2) { $childBar->trash('workflows.trash'); } } if ($this->state->get('filter.published') === '-2' && $canDo->get('core.delete')) { $toolbar->delete('workflows.delete', 'JTOOLBAR_EMPTY_TRASH') ->message('JGLOBAL_CONFIRM_DELETE') ->listCheck(true); } if ($canDo->get('core.admin') || $canDo->get('core.options')) { $toolbar->preferences($this->extension); } $toolbar->help('Workflows_List'); } } src/View/Stages/HtmlView.php 0000644 00000012453 15172633314 0011755 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Workflow\Administrator\View\Stages; use Joomla\CMS\Helper\ContentHelper; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\View\GenericDataException; use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView; use Joomla\CMS\Router\Route; use Joomla\CMS\Toolbar\Button\DropdownButton; use Joomla\CMS\Toolbar\Toolbar; use Joomla\CMS\Toolbar\ToolbarHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Stages view class for the Workflow package. * * @since 4.0.0 */ class HtmlView extends BaseHtmlView { /** * An array of stages * * @var array * @since 4.0.0 */ protected $stages; /** * The model stage * * @var object * @since 4.0.0 */ protected $stage; /** * The HTML for displaying sidebar * * @var string * @since 4.0.0 */ protected $sidebar; /** * The pagination object * * @var \Joomla\CMS\Pagination\Pagination * * @since 4.0.0 */ protected $pagination; /** * Form object for search filters * * @var \Joomla\CMS\Form\Form * * @since 4.0.0 */ public $filterForm; /** * The active search filters * * @var array * @since 4.0.0 */ public $activeFilters; /** * The current workflow * * @var object * @since 4.0.0 */ protected $workflow; /** * The ID of current workflow * * @var integer * @since 4.0.0 */ protected $workflowID; /** * The name of current extension * * @var string * @since 4.0.0 */ protected $extension; /** * The section of the current extension * * @var string * @since 4.0.0 */ protected $section; /** * Display the view * * @param string $tpl The name of the template file to parse; automatically searches through the template paths. * * @return void * * @since 4.0.0 */ public function display($tpl = null) { $this->state = $this->get('State'); $this->stages = $this->get('Items'); $this->pagination = $this->get('Pagination'); $this->filterForm = $this->get('FilterForm'); $this->activeFilters = $this->get('ActiveFilters'); $this->workflow = $this->get('Workflow'); // Check for errors. if (count($errors = $this->get('Errors'))) { throw new GenericDataException(implode("\n", $errors), 500); } $this->workflowID = $this->workflow->id; $parts = explode('.', $this->workflow->extension); $this->extension = array_shift($parts); if (!empty($parts)) { $this->section = array_shift($parts); } $this->addToolbar(); parent::display($tpl); } /** * Add the page title and toolbar. * * @return void * * @since 4.0.0 */ protected function addToolbar() { $canDo = ContentHelper::getActions($this->extension, 'workflow', $this->workflowID); $user = $this->getCurrentUser(); $toolbar = Toolbar::getInstance('toolbar'); ToolbarHelper::title(Text::sprintf('COM_WORKFLOW_STAGES_LIST', Text::_($this->state->get('active_workflow', ''))), 'address contact'); $arrow = $this->getLanguage()->isRtl() ? 'arrow-right' : 'arrow-left'; $toolbar->link( 'JTOOLBAR_BACK', Route::_('index.php?option=com_workflow&view=workflows&extension=' . $this->escape($this->workflow->extension)) ) ->icon('icon-' . $arrow); if ($canDo->get('core.create')) { $toolbar->addNew('stage.add'); } if ($canDo->get('core.edit.state') || $user->authorise('core.admin')) { /** @var DropdownButton $dropdown */ $dropdown = $toolbar->dropdownButton('status-group', 'JTOOLBAR_CHANGE_STATUS') ->toggleSplit(false) ->icon('icon-ellipsis-h') ->buttonClass('btn btn-action') ->listCheck(true); $childBar = $dropdown->getChildToolbar(); $childBar->publish('stages.publish', 'JTOOLBAR_ENABLE')->listCheck(true); $childBar->unpublish('stages.unpublish', 'JTOOLBAR_DISABLE')->listCheck(true); $childBar->makeDefault('stages.setDefault', 'COM_WORKFLOW_TOOLBAR_DEFAULT'); if ($canDo->get('core.admin')) { $childBar->checkin('stages.checkin')->listCheck(true); } if ($this->state->get('filter.published') !== '-2') { $childBar->trash('stages.trash'); } } if ($this->state->get('filter.published') === '-2' && $canDo->get('core.delete')) { $toolbar->delete('stages.delete', 'JTOOLBAR_EMPTY_TRASH') ->message('JGLOBAL_CONFIRM_DELETE') ->listCheck(true); } $toolbar->help('Stages_List:_Basic_Workflow'); } } src/View/Transitions/HtmlView.php 0000644 00000012364 15172633314 0013045 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Workflow\Administrator\View\Transitions; use Joomla\CMS\Helper\ContentHelper; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\View\GenericDataException; use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView; use Joomla\CMS\Router\Route; use Joomla\CMS\Toolbar\Button\DropdownButton; use Joomla\CMS\Toolbar\Toolbar; use Joomla\CMS\Toolbar\ToolbarHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Transitions view class for the Workflow package. * * @since 4.0.0 */ class HtmlView extends BaseHtmlView { /** * An array of transitions * * @var array * @since 4.0.0 */ protected $transitions; /** * The model state * * @var object * @since 4.0.0 */ protected $state; /** * The HTML for displaying sidebar * * @var string * @since 4.0.0 */ protected $sidebar; /** * The pagination object * * @var \Joomla\CMS\Pagination\Pagination * * @since 4.0.0 */ protected $pagination; /** * Form object for search filters * * @var \Joomla\CMS\Form\Form * * @since 4.0.0 */ public $filterForm; /** * The active search filters * * @var array * @since 4.0.0 */ public $activeFilters; /** * The current workflow * * @var object * @since 4.0.0 */ protected $workflow; /** * The ID of current workflow * * @var integer * @since 4.0.0 */ protected $workflowID; /** * The name of current extension * * @var string * @since 4.0.0 */ protected $extension; /** * The section of the current extension * * @var string * @since 4.0.0 */ protected $section; /** * Display the view * * @param string $tpl The name of the template file to parse; automatically searches through the template paths. * * @return void * * @since 4.0.0 */ public function display($tpl = null) { $this->state = $this->get('State'); $this->transitions = $this->get('Items'); $this->pagination = $this->get('Pagination'); $this->filterForm = $this->get('FilterForm'); $this->activeFilters = $this->get('ActiveFilters'); $this->workflow = $this->get('Workflow'); // Check for errors. if (count($errors = $this->get('Errors'))) { throw new GenericDataException(implode("\n", $errors), 500); } $this->workflowID = $this->workflow->id; $parts = explode('.', $this->workflow->extension); $this->extension = array_shift($parts); if (!empty($parts)) { $this->section = array_shift($parts); } $this->addToolbar(); parent::display($tpl); } /** * Add the page title and toolbar. * * @return void * * @since 4.0.0 */ protected function addToolbar() { $canDo = ContentHelper::getActions($this->extension, 'workflow', $this->workflowID); $user = $this->getCurrentUser(); $toolbar = Toolbar::getInstance(); ToolbarHelper::title(Text::sprintf('COM_WORKFLOW_TRANSITIONS_LIST', Text::_($this->state->get('active_workflow'))), 'address contact'); $arrow = $this->getLanguage()->isRtl() ? 'arrow-right' : 'arrow-left'; $toolbar->link( 'JTOOLBAR_BACK', Route::_('index.php?option=com_workflow&view=workflows&extension=' . $this->escape($this->workflow->extension)) ) ->icon('icon-' . $arrow); if ($canDo->get('core.create')) { $toolbar->addNew('transition.add'); } if ($canDo->get('core.edit.state') || $user->authorise('core.admin')) { /** @var DropdownButton $dropdown */ $dropdown = $toolbar->dropdownButton('status-group', 'JTOOLBAR_CHANGE_STATUS') ->toggleSplit(false) ->icon('icon-ellipsis-h') ->buttonClass('btn btn-action') ->listCheck(true); $childBar = $dropdown->getChildToolbar(); $childBar->publish('transitions.publish', 'JTOOLBAR_ENABLE'); $childBar->unpublish('transitions.unpublish', 'JTOOLBAR_DISABLE'); if ($canDo->get('core.admin')) { $childBar->checkin('transitions.checkin')->listCheck(true); } if ($this->state->get('filter.published') !== '-2') { $childBar->trash('transitions.trash'); } } if ($this->state->get('filter.published') === '-2' && $canDo->get('core.delete')) { $toolbar->delete('transitions.delete', 'JTOOLBAR_EMPTY_TRASH') ->message('JGLOBAL_CONFIRM_DELETE') ->listCheck(true); } $toolbar->help('Transitions_List:_Basic_Workflow'); } } src/View/Workflow/HtmlView.php 0000644 00000011237 15172633314 0012340 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Workflow\Administrator\View\Workflow; use Joomla\CMS\Factory; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\View\GenericDataException; use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView; use Joomla\CMS\Toolbar\Toolbar; use Joomla\CMS\Toolbar\ToolbarHelper; use Joomla\Component\Workflow\Administrator\Helper\WorkflowHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * View class to add or edit a workflow * * @since 4.0.0 */ class HtmlView extends BaseHtmlView { /** * The model state * * @var object * @since 4.0.0 */ protected $state; /** * The Form object * * @var \Joomla\CMS\Form\Form */ protected $form; /** * The active item * * @var object */ protected $item; /** * The ID of current workflow * * @var integer * @since 4.0.0 */ protected $workflowID; /** * The name of current extension * * @var string * @since 4.0.0 */ protected $extension; /** * The section of the current extension * * @var string * @since 4.0.0 */ protected $section; /** * Display item view * * @param string $tpl The name of the template file to parse; automatically searches through the template paths. * * @return void * * @since 4.0.0 */ public function display($tpl = null) { // Get the Data $this->state = $this->get('State'); $this->form = $this->get('Form'); $this->item = $this->get('Item'); // Check for errors. if (count($errors = $this->get('Errors'))) { throw new GenericDataException(implode("\n", $errors), 500); } $extension = $this->state->get('filter.extension'); $parts = explode('.', $extension); $this->extension = array_shift($parts); if (!empty($parts)) { $this->section = array_shift($parts); } // Set the toolbar $this->addToolbar(); // Display the template parent::display($tpl); } /** * Add the page title and toolbar. * * @return void * * @since 4.0.0 */ protected function addToolbar() { Factory::getApplication()->getInput()->set('hidemainmenu', true); $user = $this->getCurrentUser(); $userId = $user->id; $isNew = empty($this->item->id); $toolbar = Toolbar::getInstance(); $canDo = WorkflowHelper::getActions($this->extension, 'workflow', $this->item->id); ToolbarHelper::title(empty($this->item->id) ? Text::_('COM_WORKFLOW_WORKFLOWS_ADD') : Text::_('COM_WORKFLOW_WORKFLOWS_EDIT'), 'address'); if ($isNew) { // For new records, check the create permission. if ($canDo->get('core.create')) { $toolbar->apply('workflow.apply'); $saveGroup = $toolbar->dropdownButton('save-group'); $saveGroup->configure( function (Toolbar $childBar) { $childBar->save('workflow.save'); $childBar->save2new('workflow.save2new'); } ); } $toolbar->cancel('workflow.cancel', 'JTOOLBAR_CANCEL'); } else { // Since it's an existing record, check the edit permission, or fall back to edit own if the owner. $itemEditable = $canDo->get('core.edit') || ($canDo->get('core.edit.own') && $this->item->created_by == $userId); if ($itemEditable) { $toolbar->apply('workflow.apply'); $saveGroup = $toolbar->dropdownButton('save-group'); $saveGroup->configure( function (Toolbar $childBar) use ($canDo) { $childBar->save('workflow.save'); // We can save this record, but check the create permission to see if we can return to make a new one. if ($canDo->get('core.create')) { $childBar->save2new('workflow.save2new'); $childBar->save2copy('workflow.save2copy'); } } ); } $toolbar->cancel('workflow.cancel'); } } } src/View/Stage/HtmlView.php 0000644 00000011340 15172633314 0011564 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Workflow\Administrator\View\Stage; use Joomla\CMS\Factory; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\View\GenericDataException; use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView; use Joomla\CMS\Toolbar\Toolbar; use Joomla\CMS\Toolbar\ToolbarHelper; use Joomla\Component\Workflow\Administrator\Helper\StageHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * View class to add or edit a stage of a workflow * * @since 4.0.0 */ class HtmlView extends BaseHtmlView { /** * The model state * * @var object * @since 4.0.0 */ protected $state; /** * From object to generate fields * * @var \Joomla\CMS\Form\Form * * @since 4.0.0 */ protected $form; /** * Items array * * @var object * @since 4.0.0 */ protected $item; /** * The name of current extension * * @var string * @since 4.0.0 */ protected $extension; /** * The section of the current extension * * @var string * @since 4.0.0 */ protected $section; /** * Display item view * * @param string $tpl The name of the template file to parse; automatically searches through the template paths. * * @return void * * @since 4.0.0 */ public function display($tpl = null) { // Get the Data $this->state = $this->get('State'); $this->form = $this->get('Form'); $this->item = $this->get('Item'); // Check for errors. if (count($errors = $this->get('Errors'))) { throw new GenericDataException(implode("\n", $errors), 500); } $extension = $this->state->get('filter.extension'); $parts = explode('.', $extension); $this->extension = array_shift($parts); if (!empty($parts)) { $this->section = array_shift($parts); } // Set the toolbar $this->addToolbar(); // Display the template parent::display($tpl); } /** * Add the page title and toolbar. * * @return void * * @since 4.0.0 */ protected function addToolbar() { Factory::getApplication()->getInput()->set('hidemainmenu', true); $user = $this->getCurrentUser(); $userId = $user->id; $isNew = empty($this->item->id); $toolbar = Toolbar::getInstance(); $canDo = StageHelper::getActions($this->extension, 'stage', $this->item->id); ToolbarHelper::title(empty($this->item->id) ? Text::_('COM_WORKFLOW_STAGE_ADD') : Text::_('COM_WORKFLOW_STAGE_EDIT'), 'address'); if ($isNew) { // For new records, check the create permission. if ($canDo->get('core.create')) { $toolbar->apply('stage.apply'); } $saveGroup = $toolbar->dropdownButton('save-group'); $saveGroup->configure( function (Toolbar $childBar) use ($canDo) { // For new records, check the create permission. if ($canDo->get('core.create')) { $childBar->save('stage.save'); $childBar->save2new('stage.save2new'); } } ); $toolbar->cancel('stage.cancel', 'JTOOLBAR_CANCEL'); } else { // Since it's an existing record, check the edit permission, or fall back to edit own if the owner. $itemEditable = $canDo->get('core.edit') || ($canDo->get('core.edit.own') && $this->item->created_by == $userId); if ($itemEditable) { $toolbar->apply('stage.apply'); $saveGroup = $toolbar->dropdownButton('save-group'); $saveGroup->configure( function (Toolbar $childBar) use ($canDo) { $childBar->save('stage.save'); // We can save this record, but check the create permission to see if we can return to make a new one. if ($canDo->get('core.create')) { $childBar->save2new('stage.save2new'); $childBar->save2copy('stage.save2copy'); } } ); } $toolbar->cancel('stage.cancel'); } $toolbar->divider(); } } src/View/Transition/HtmlView.php 0000644 00000012615 15172633314 0012661 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Workflow\Administrator\View\Transition; use Joomla\CMS\Factory; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\View\GenericDataException; use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView; use Joomla\CMS\Toolbar\Toolbar; use Joomla\CMS\Toolbar\ToolbarHelper; use Joomla\Component\Workflow\Administrator\Helper\StageHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * View class to add or edit a transition of a workflow * * @since 4.0.0 */ class HtmlView extends BaseHtmlView { /** * The model state * * @var object * @since 4.0.0 */ protected $state; /** * Form object to generate fields * * @var \Joomla\CMS\Form\Form * * @since 4.0.0 */ protected $form; /** * Items array * * @var object * @since 4.0.0 */ protected $item; /** * That is object of Application * * @var \Joomla\CMS\Application\CMSApplication * @since 4.0.0 */ protected $app; /** * The application input object. * * @var \Joomla\CMS\Input\Input * @since 4.0.0 */ protected $input; /** * The ID of current workflow * * @var integer * @since 4.0.0 */ protected $workflowID; /** * The name of current extension * * @var string * @since 4.0.0 */ protected $extension; /** * The section of the current extension * * @var string * @since 4.0.0 */ protected $section; /** * Display item view * * @param string $tpl The name of the template file to parse; automatically searches through the template paths. * * @return void * * @since 4.0.0 */ public function display($tpl = null) { $this->app = Factory::getApplication(); $this->input = $this->app->getInput(); // Get the Data $this->state = $this->get('State'); $this->form = $this->get('Form'); $this->item = $this->get('Item'); // Check for errors. if (count($errors = $this->get('Errors'))) { throw new GenericDataException(implode("\n", $errors), 500); } $extension = $this->state->get('filter.extension'); $parts = explode('.', $extension); $this->extension = array_shift($parts); if (!empty($parts)) { $this->section = array_shift($parts); } // Get the ID of workflow $this->workflowID = $this->input->getCmd("workflow_id"); // Set the toolbar $this->addToolbar(); // Display the template parent::display($tpl); } /** * Add the page title and toolbar. * * @return void * * @since 4.0.0 */ protected function addToolbar() { Factory::getApplication()->getInput()->set('hidemainmenu', true); $user = $this->getCurrentUser(); $userId = $user->id; $isNew = empty($this->item->id); $toolbar = Toolbar::getInstance(); $canDo = StageHelper::getActions($this->extension, 'transition', $this->item->id); $canCreate = $canDo->get('core.create'); ToolbarHelper::title(empty($this->item->id) ? Text::_('COM_WORKFLOW_TRANSITION_ADD') : Text::_('COM_WORKFLOW_TRANSITION_EDIT'), 'address'); if ($isNew) { // For new records, check the create permission. if ($canCreate) { $toolbar->apply('transition.apply'); $saveGroup = $toolbar->dropdownButton('save-group'); $saveGroup->configure( function (Toolbar $childBar) { // For new records, check the create permission. $childBar->save('transition.save'); $childBar->save2new('transition.save2new'); } ); } $toolbar->cancel('transition.cancel', 'JTOOLBAR_CANCEL'); } else { // Since it's an existing record, check the edit permission, or fall back to edit own if the owner. $itemEditable = $canDo->get('core.edit') || ($canDo->get('core.edit.own') && $this->item->created_by == $userId); if ($itemEditable) { $toolbar->apply('transition.apply'); } else { $toolbar->save('transition.save'); } $saveGroup = $toolbar->dropdownButton('save-group'); $saveGroup->configure( function (Toolbar $childBar) use ($canCreate) { $childBar->save('transition.save'); // We can save this record, but check the create permission to see if we can return to make a new one. if ($canCreate) { $childBar->save2new('transition.save2new'); $childBar->save2copy('transition.save2copy'); } } ); $toolbar->cancel('transition.cancel'); } $toolbar->divider(); } } src/Field/WorkflowcontextsField.php 0000644 00000003074 15172633314 0013446 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2020 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Workflow\Administrator\Field; use Joomla\CMS\Factory; use Joomla\CMS\Form\Field\ListField; use Joomla\CMS\Workflow\WorkflowServiceInterface; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Fields Contexts * * @since 4.0.0 */ class WorkflowcontextsField extends ListField { /** * Type of the field * * @var string */ public $type = 'Workflowcontexts'; /** * Method to get the field input markup for a generic list. * Use the multiple attribute to enable multiselect. * * @return string The field input markup. * * @since 4.0.0 */ protected function getInput() { if (count($this->getOptions()) < 2) { $this->layout = 'joomla.form.field.hidden'; } return parent::getInput(); } /** * Method to get the field options. * * @return array The field option objects. * * @since 4.0.0 */ protected function getOptions() { $parts = explode('.', $this->value); $component = Factory::getApplication()->bootComponent($parts[0]); if ($component instanceof WorkflowServiceInterface) { return $component->getWorkflowContexts(); } return []; } } src/Field/ComponentsWorkflowField.php 0000644 00000006770 15172633314 0013732 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Workflow\Administrator\Field; use Joomla\CMS\Access\Access; use Joomla\CMS\Factory; use Joomla\CMS\Form\Field\ListField; use Joomla\CMS\Language\Text; use Joomla\CMS\Workflow\WorkflowServiceInterface; use Joomla\Utilities\ArrayHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Components Workflow field. * * @since 1.6 */ class ComponentsWorkflowField extends ListField { /** * The form field type. * * @var string * @since 3.7.0 */ protected $type = 'ComponentsWorkflow'; /** * Method to get a list of options for a list input. * * @return array An array of JHtml options. * * @since 3.7.0 */ protected function getOptions() { // Initialise variable. $db = $this->getDatabase(); $query = $db->getQuery(true) ->select('DISTINCT a.name AS text, a.element AS value') ->from('#__extensions as a') ->where('a.enabled >= 1') ->where('a.type =' . $db->quote('component')); $items = $db->setQuery($query)->loadObjectList(); $options = []; if (count($items)) { $lang = Factory::getLanguage(); $components = []; // Search for components supporting Fieldgroups - suppose that these components support fields as well foreach ($items as &$item) { $availableActions = Access::getActionsFromFile( JPATH_ADMINISTRATOR . '/components/' . $item->value . '/access.xml', "/access/section[@name='workflow']/" ); if (!empty($availableActions)) { // Load language $source = JPATH_ADMINISTRATOR . '/components/' . $item->value; $lang->load($item->value . 'sys', JPATH_ADMINISTRATOR) || $lang->load($item->value . 'sys', $source); // Translate component name $item->text = Text::_($item->text); $components[] = $item; } } if (empty($components)) { return []; } foreach ($components as $component) { // Search for different contexts $c = Factory::getApplication()->bootComponent($component->value); if ($c instanceof WorkflowServiceInterface) { $contexts = $c->getContexts(); foreach ($contexts as $context) { $newOption = new \stdClass(); $newOption->value = strtolower($component->value . '.' . $context); $newOption->text = $component->text . ' - ' . Text::_($context); $options[] = $newOption; } } else { $options[] = $component; } } // Sort by name $items = ArrayHelper::sortObjects($options, 'text', 1, true, true); } // Merge any additional options in the XML definition. $options = array_merge(parent::getOptions(), $items); return $options; } } src/Dispatcher/Dispatcher.php 0000644 00000002276 15172633314 0012234 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Workflow\Administrator\Dispatcher; use Joomla\CMS\Access\Exception\NotAllowed; use Joomla\CMS\Dispatcher\ComponentDispatcher; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * ComponentDispatcher class for com_workflow * * @since 4.0.0 */ class Dispatcher extends ComponentDispatcher { /** * Workflows have to check for extension permission * * @return void */ protected function checkAccess() { $extension = $this->getApplication()->getInput()->getCmd('extension'); $parts = explode('.', $extension); // Check the user has permission to access this component if in the backend if ($this->app->isClient('administrator') && !$this->app->getIdentity()->authorise('core.manage.workflow', $parts[0])) { throw new NotAllowed($this->app->getLanguage()->_('JERROR_ALERTNOAUTHOR'), 403); } } } src/Model/TransitionModel.php 0000644 00000023446 15172633314 0012235 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt * @since 4.0.0 */ namespace Joomla\Component\Workflow\Administrator\Model; use Joomla\CMS\Factory; use Joomla\CMS\Form\Form; use Joomla\CMS\MVC\Model\AdminModel; use Joomla\CMS\Plugin\PluginHelper; use Joomla\Registry\Registry; use Joomla\String\StringHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Model class for transition * * @since 4.0.0 */ class TransitionModel extends AdminModel { /** * Auto-populate the model state. * * Note. Calling getState in this method will result in recursion. * * @return void * * @since 4.0.0 */ public function populateState() { parent::populateState(); $app = Factory::getApplication(); $context = $this->option . '.' . $this->name; $extension = $app->getUserStateFromRequest($context . '.filter.extension', 'extension', null, 'cmd'); $this->setState('filter.extension', $extension); } /** * Method to test whether a record can be deleted. * * @param object $record A record object. * * @return boolean True if allowed to delete the record. Defaults to the permission for the component. * * @since 4.0.0 */ protected function canDelete($record) { if (empty($record->id) || $record->published != -2) { return false; } $app = Factory::getApplication(); $extension = $app->getUserStateFromRequest('com_workflow.transition.filter.extension', 'extension', null, 'cmd'); return $this->getCurrentUser()->authorise('core.delete', $extension . '.transition.' . (int) $record->id); } /** * Method to test whether a record can have its state changed. * * @param object $record A record object. * * @return boolean True if allowed to change the state of the record. Defaults to the permission set in the component. * * @since 4.0.0 */ protected function canEditState($record) { $user = $this->getCurrentUser(); $app = Factory::getApplication(); $context = $this->option . '.' . $this->name; $extension = $app->getUserStateFromRequest($context . '.filter.extension', 'extension', null, 'cmd'); if (!\property_exists($record, 'workflow_id')) { $workflowID = $app->getUserStateFromRequest($context . '.filter.workflow_id', 'workflow_id', 0, 'int'); $record->workflow_id = $workflowID; } // Check for existing workflow. if (!empty($record->id)) { return $user->authorise('core.edit.state', $extension . '.transition.' . (int) $record->id); } // Default to component settings if workflow isn't known. return $user->authorise('core.edit.state', $extension); } /** * Method to get a single record. * * @param integer $pk The id of the primary key. * * @return \Joomla\CMS\Object\CMSObject|boolean Object on success, false on failure. * * @since 4.0.0 */ public function getItem($pk = null) { $item = parent::getItem($pk); if (property_exists($item, 'options')) { $registry = new Registry($item->options); $item->options = $registry->toArray(); } return $item; } /** * Method to save the form data. * * @param array $data The form data. * * @return boolean True on success. * * @since 4.0.0 */ public function save($data) { $table = $this->getTable(); $context = $this->option . '.' . $this->name; $app = Factory::getApplication(); $user = $app->getIdentity(); $input = $app->getInput(); $workflowID = $app->getUserStateFromRequest($context . '.filter.workflow_id', 'workflow_id', 0, 'int'); if (empty($data['workflow_id'])) { $data['workflow_id'] = $workflowID; } $workflow = $this->getTable('Workflow'); $workflow->load($data['workflow_id']); $parts = explode('.', $workflow->extension); if (isset($data['rules']) && !$user->authorise('core.admin', $parts[0])) { unset($data['rules']); } // Make sure we use the correct workflow_id when editing an existing transition $key = $table->getKeyName(); $pk = (isset($data[$key])) ? $data[$key] : (int) $this->getState($this->getName() . '.id'); if ($pk > 0) { $table->load($pk); if ((int) $table->workflow_id) { $data['workflow_id'] = (int) $table->workflow_id; } } if ($input->get('task') == 'save2copy') { $origTable = clone $this->getTable(); // Alter the title for save as copy if ($origTable->load(['title' => $data['title']])) { list($title) = $this->generateNewTitle(0, '', $data['title']); $data['title'] = $title; } $data['published'] = 0; } return parent::save($data); } /** * Method to change the title * * @param integer $categoryId The id of the category. * @param string $alias The alias. * @param string $title The title. * * @return array Contains the modified title and alias. * * @since 4.0.0 */ protected function generateNewTitle($categoryId, $alias, $title) { // Alter the title & alias $table = $this->getTable(); while ($table->load(['title' => $title])) { $title = StringHelper::increment($title); } return [$title, $alias]; } /** * Abstract method for getting the form from the model. * * @param array $data Data for the form. * @param boolean $loadData True if the form is to load its own data (default case), false if not. * * @return \Joomla\CMS\Form\Form|boolean A Form object on success, false on failure * * @since 4.0.0 */ public function getForm($data = [], $loadData = true) { // Get the form. $form = $this->loadForm( 'com_workflow.transition', 'transition', [ 'control' => 'jform', 'load_data' => $loadData, ] ); if (empty($form)) { return false; } $id = $data['id'] ?? $form->getValue('id'); $item = $this->getItem($id); $canEditState = $this->canEditState((object) $item); // Modify the form based on access controls. if (!$canEditState) { $form->setFieldAttribute('published', 'disabled', 'true'); $form->setFieldAttribute('published', 'required', 'false'); $form->setFieldAttribute('published', 'filter', 'unset'); } if (!empty($item->workflow_id)) { $data['workflow_id'] = (int) $item->workflow_id; } if (empty($data['workflow_id'])) { $context = $this->option . '.' . $this->name; $data['workflow_id'] = (int) Factory::getApplication()->getUserStateFromRequest( $context . '.filter.workflow_id', 'workflow_id', 0, 'int' ); } $where = $this->getDatabase()->quoteName('workflow_id') . ' = ' . (int) $data['workflow_id']; $where .= ' AND ' . $this->getDatabase()->quoteName('published') . ' = 1'; $form->setFieldAttribute('from_stage_id', 'sql_where', $where); $form->setFieldAttribute('to_stage_id', 'sql_where', $where); return $form; } /** * Method to get the data that should be injected in the form. * * @return mixed The data for the form. * * @since 4.0.0 */ protected function loadFormData() { // Check the session for previously entered form data. $data = Factory::getApplication()->getUserState( 'com_workflow.edit.transition.data', [] ); if (empty($data)) { $data = $this->getItem(); } return $data; } public function getWorkflow() { $app = Factory::getApplication(); $context = $this->option . '.' . $this->name; $workflow_id = (int) $app->getUserStateFromRequest($context . '.filter.workflow_id', 'workflow_id', 0, 'int'); $workflow = $this->getTable('Workflow'); $workflow->load($workflow_id); return (object) $workflow->getProperties(); } /** * Trigger the form preparation for the workflow group * * @param Form $form A Form object. * @param mixed $data The data expected for the form. * @param string $group The name of the plugin group to import (defaults to "content"). * * @return void * * @see FormField * @since 4.0.0 * @throws \Exception if there is an error in the form event. */ protected function preprocessForm(Form $form, $data, $group = 'content') { $extension = Factory::getApplication()->getInput()->get('extension'); $parts = explode('.', $extension); $extension = array_shift($parts); // Set the access control rules field component value. $form->setFieldAttribute('rules', 'component', $extension); // Import the appropriate plugin group. PluginHelper::importPlugin('workflow'); parent::preprocessForm($form, $data, $group); } } src/Model/WorkflowsModel.php 0000644 00000020415 15172633314 0012071 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt * @since 4.0.0 */ namespace Joomla\Component\Workflow\Administrator\Model; use Joomla\CMS\Factory; use Joomla\CMS\MVC\Model\ListModel; use Joomla\Database\DatabaseQuery; use Joomla\Database\ParameterType; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Model class for workflows * * @since 4.0.0 */ class WorkflowsModel extends ListModel { /** * Constructor. * * @param array $config An optional associative array of configuration settings. * * @see JController * @since 4.0.0 */ public function __construct($config = []) { if (empty($config['filter_fields'])) { $config['filter_fields'] = [ 'id', 'w.id', 'title', 'w.title', 'published', 'w.published', 'created_by', 'w.created_by', 'created', 'w.created', 'ordering', 'w.ordering', 'modified', 'w.modified', 'description', 'w.description', ]; } parent::__construct($config); } /** * Method to auto-populate the model state. * * This method should only be called once per instantiation and is designed * to be called on the first call to the getState() method unless the model * configuration flag to ignore the request is set. * * Note. Calling getState in this method will result in recursion. * * @param string $ordering An optional ordering field. * @param string $direction An optional direction (asc|desc). * * @return void * * @since 4.0.0 */ protected function populateState($ordering = 'w.ordering', $direction = 'asc') { $app = Factory::getApplication(); $extension = $app->getUserStateFromRequest($this->context . '.filter.extension', 'extension', null, 'cmd'); $this->setState('filter.extension', $extension); $parts = explode('.', $extension); // Extract the component name $this->setState('filter.component', $parts[0]); // Extract the optional section name $this->setState('filter.section', (count($parts) > 1) ? $parts[1] : null); parent::populateState($ordering, $direction); } /** * Method to get a table object, load it if necessary. * * @param string $type The table name. Optional. * @param string $prefix The class prefix. Optional. * @param array $config Configuration array for model. Optional. * * @return \Joomla\CMS\Table\Table A Table object * * @since 4.0.0 */ public function getTable($type = 'Workflow', $prefix = 'Administrator', $config = []) { return parent::getTable($type, $prefix, $config); } /** * Method to get an array of data items. * * @return mixed An array of data items on success, false on failure. * * @since 4.0.0 */ public function getItems() { $items = parent::getItems(); if ($items) { $this->countItems($items); } return $items; } /** * Get the filter form * * @param array $data data * @param boolean $loadData load current data * * @return \Joomla\CMS\Form\Form|bool the Form object or false * * @since 4.0.0 */ public function getFilterForm($data = [], $loadData = true) { $form = parent::getFilterForm($data, $loadData); if ($form) { $form->setValue('extension', null, $this->getState('filter.extension')); } return $form; } /** * Add the number of transitions and states to all workflow items * * @param array $items The workflow items * * @return void * * @since 4.0.0 */ protected function countItems($items) { $db = $this->getDatabase(); $ids = [0]; foreach ($items as $item) { $ids[] = (int) $item->id; $item->count_states = 0; $item->count_transitions = 0; } $query = $db->getQuery(true); $query->select( [ $db->quoteName('workflow_id'), 'COUNT(*) AS ' . $db->quoteName('count'), ] ) ->from($db->quoteName('#__workflow_stages')) ->whereIn($db->quoteName('workflow_id'), $ids) ->where($db->quoteName('published') . ' >= 0') ->group($db->quoteName('workflow_id')); $status = $db->setQuery($query)->loadObjectList('workflow_id'); $query = $db->getQuery(true); $query->select( [ $db->quoteName('workflow_id'), 'COUNT(*) AS ' . $db->quoteName('count'), ] ) ->from($db->quoteName('#__workflow_transitions')) ->whereIn($db->quoteName('workflow_id'), $ids) ->where($db->quoteName('published') . ' >= 0') ->group($db->quoteName('workflow_id')); $transitions = $db->setQuery($query)->loadObjectList('workflow_id'); foreach ($items as $item) { if (isset($status[$item->id])) { $item->count_states = (int) $status[$item->id]->count; } if (isset($transitions[$item->id])) { $item->count_transitions = (int) $transitions[$item->id]->count; } } } /** * Method to get the data that should be injected in the form. * * @return DatabaseQuery The query to database. * * @since 4.0.0 */ public function getListQuery() { $db = $this->getDatabase(); $query = $db->getQuery(true); $query->select( [ $db->quoteName('w.id'), $db->quoteName('w.title'), $db->quoteName('w.created'), $db->quoteName('w.modified'), $db->quoteName('w.published'), $db->quoteName('w.checked_out'), $db->quoteName('w.checked_out_time'), $db->quoteName('w.ordering'), $db->quoteName('w.default'), $db->quoteName('w.created_by'), $db->quoteName('w.description'), $db->quoteName('u.name'), $db->quoteName('uc.name', 'editor'), ] ) ->from($db->quoteName('#__workflows', 'w')) ->join('LEFT', $db->quoteName('#__users', 'u'), $db->quoteName('u.id') . ' = ' . $db->quoteName('w.created_by')) ->join('LEFT', $db->quoteName('#__users', 'uc'), $db->quoteName('uc.id') . ' = ' . $db->quoteName('w.checked_out')); // Filter by extension if ($extension = $this->getState('filter.extension')) { $query->where($db->quoteName('extension') . ' = :extension') ->bind(':extension', $extension); } $status = (string) $this->getState('filter.published'); // Filter by status if (is_numeric($status)) { $status = (int) $status; $query->where($db->quoteName('w.published') . ' = :published') ->bind(':published', $status, ParameterType::INTEGER); } elseif ($status === '') { $query->where($db->quoteName('w.published') . ' IN (0, 1)'); } // Filter by search in title $search = $this->getState('filter.search'); if (!empty($search)) { $search = '%' . str_replace(' ', '%', trim($search)) . '%'; $query->where('(' . $db->quoteName('w.title') . ' LIKE :search1 OR ' . $db->quoteName('w.description') . ' LIKE :search2)') ->bind([':search1', ':search2'], $search); } // Add the list ordering clause. $orderCol = $this->state->get('list.ordering', 'w.ordering'); $orderDirn = strtoupper($this->state->get('list.direction', 'ASC')); $query->order($db->escape($orderCol) . ' ' . ($orderDirn === 'DESC' ? 'DESC' : 'ASC')); return $query; } } src/Model/StageModel.php 0000644 00000025435 15172633314 0011146 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt * @since 4.0.0 */ namespace Joomla\Component\Workflow\Administrator\Model; use Joomla\CMS\Factory; use Joomla\CMS\Form\Form; use Joomla\CMS\Language\Text; use Joomla\CMS\Log\Log; use Joomla\CMS\MVC\Model\AdminModel; use Joomla\String\StringHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Model class for stage * * @since 4.0.0 */ class StageModel extends AdminModel { /** * Auto-populate the model state. * * Note. Calling getState in this method will result in recursion. * * @return void * * @since 4.0.0 */ public function populateState() { parent::populateState(); $app = Factory::getApplication(); $context = $this->option . '.' . $this->name; $extension = $app->getUserStateFromRequest($context . '.filter.extension', 'extension', null, 'cmd'); $this->setState('filter.extension', $extension); } /** * Method to change the title * * @param integer $categoryId The id of the category. * @param string $alias The alias. * @param string $title The title. * * @return array Contains the modified title and alias. * * @since 4.0.0 */ protected function generateNewTitle($categoryId, $alias, $title) { // Alter the title & alias $table = $this->getTable(); while ($table->load(['title' => $title])) { $title = StringHelper::increment($title); } return [$title, $alias]; } /** * Method to save the form data. * * @param array $data The form data. * * @return boolean True on success. * * @since 4.0.0 */ public function save($data) { $table = $this->getTable(); $context = $this->option . '.' . $this->name; $app = Factory::getApplication(); $user = $app->getIdentity(); $input = $app->getInput(); $workflowID = $app->getUserStateFromRequest($context . '.filter.workflow_id', 'workflow_id', 0, 'int'); if (empty($data['workflow_id'])) { $data['workflow_id'] = $workflowID; } $workflow = $this->getTable('Workflow'); $workflow->load($data['workflow_id']); $parts = explode('.', $workflow->extension); if (isset($data['rules']) && !$user->authorise('core.admin', $parts[0])) { unset($data['rules']); } // Make sure we use the correct extension when editing an existing workflow $key = $table->getKeyName(); $pk = (isset($data[$key])) ? $data[$key] : (int) $this->getState($this->getName() . '.id'); if ($pk > 0) { $table->load($pk); if ((int) $table->workflow_id) { $data['workflow_id'] = (int) $table->workflow_id; } } if ($input->get('task') == 'save2copy') { $origTable = clone $this->getTable(); // Alter the title for save as copy if ($origTable->load(['title' => $data['title']])) { list($title) = $this->generateNewTitle(0, '', $data['title']); $data['title'] = $title; } $data['published'] = 0; $data['default'] = 0; } return parent::save($data); } /** * Method to test whether a record can be deleted. * * @param object $record A record object. * * @return boolean True if allowed to delete the record. Defaults to the permission for the component. * * @since 4.0.0 */ protected function canDelete($record) { $table = $this->getTable('Workflow', 'Administrator'); $table->load($record->workflow_id); if (empty($record->id) || $record->published != -2) { return false; } $app = Factory::getApplication(); $extension = $app->getUserStateFromRequest('com_workflow.stage.filter.extension', 'extension', null, 'cmd'); $parts = explode('.', $extension); $component = reset($parts); if (!$this->getCurrentUser()->authorise('core.delete', $component . '.state.' . (int) $record->id) || $record->default) { $this->setError(Text::_('JLIB_APPLICATION_ERROR_DELETE_NOT_PERMITTED')); return false; } return true; } /** * Method to test whether a record can have its state changed. * * @param object $record A record object. * * @return boolean True if allowed to change the state of the record. Defaults to the permission set in the component. * * @since 4.0.0 */ protected function canEditState($record) { $user = $this->getCurrentUser(); $app = Factory::getApplication(); $context = $this->option . '.' . $this->name; $extension = $app->getUserStateFromRequest($context . '.filter.extension', 'extension', null, 'cmd'); if (!\property_exists($record, 'workflow_id')) { $workflowID = $app->getUserStateFromRequest($context . '.filter.workflow_id', 'workflow_id', 0, 'int'); $record->workflow_id = $workflowID; } // Check for existing workflow. if (!empty($record->id)) { return $user->authorise('core.edit.state', $extension . '.state.' . (int) $record->id); } // Default to component settings if workflow isn't known. return $user->authorise('core.edit.state', $extension); } /** * Abstract method for getting the form from the model. * * @param array $data Data for the form. * @param boolean $loadData True if the form is to load its own data (default case), false if not. * * @return Form|boolean A Form object on success, false on failure * * @since 4.0.0 */ public function getForm($data = [], $loadData = true) { // Get the form. $form = $this->loadForm( 'com_workflow.state', 'stage', [ 'control' => 'jform', 'load_data' => $loadData, ] ); if (empty($form)) { return false; } $id = $data['id'] ?? $form->getValue('id'); $item = $this->getItem($id); $canEditState = $this->canEditState((object) $item); // Modify the form based on access controls. if (!$canEditState || !empty($item->default)) { if (!$canEditState) { $form->setFieldAttribute('published', 'disabled', 'true'); $form->setFieldAttribute('published', 'required', 'false'); $form->setFieldAttribute('published', 'filter', 'unset'); } $form->setFieldAttribute('default', 'disabled', 'true'); $form->setFieldAttribute('default', 'required', 'false'); $form->setFieldAttribute('default', 'filter', 'unset'); } return $form; } /** * Method to get the data that should be injected in the form. * * @return mixed The data for the form. * * @since 4.0.0 */ protected function loadFormData() { // Check the session for previously entered form data. $data = Factory::getApplication()->getUserState( 'com_workflow.edit.state.data', [] ); if (empty($data)) { $data = $this->getItem(); } return $data; } /** * Method to change the home state of one or more items. * * @param array $pk A list of the primary keys to change. * @param integer $value The value of the home state. * * @return boolean True on success. * * @since 4.0.0 */ public function setDefault($pk, $value = 1) { $table = $this->getTable(); if ($table->load($pk)) { if (!$table->published) { $this->setError(Text::_('COM_WORKFLOW_ITEM_MUST_PUBLISHED')); return false; } } if (empty($table->id) || !$this->canEditState($table)) { Log::add(Text::_('JLIB_APPLICATION_ERROR_EDITSTATE_NOT_PERMITTED'), Log::WARNING, 'jerror'); return false; } if ($value) { // Verify that the home page for this language is unique per client id if ($table->load(['default' => '1', 'workflow_id' => $table->workflow_id])) { $table->default = 0; $table->store(); } } if ($table->load($pk)) { $table->default = $value; $table->store(); } // Clean the cache $this->cleanCache(); return true; } /** * Method to change the published state of one or more records. * * @param array &$pks A list of the primary keys to change. * @param integer $value The value of the published state. * * @return boolean True on success. * * @since 4.0.0 */ public function publish(&$pks, $value = 1) { $table = $this->getTable(); $pks = (array) $pks; $app = Factory::getApplication(); $extension = $app->getUserStateFromRequest('com_workflow.state.filter.extension', 'extension', null, 'cmd'); // Default item existence checks. if ($value != 1) { foreach ($pks as $i => $pk) { if ($table->load($pk) && $table->default) { // Prune items that you can't change. $app->enqueueMessage(Text::_('COM_WORKFLOW_MSG_DISABLE_DEFAULT'), 'error'); unset($pks[$i]); } } } return parent::publish($pks, $value); } /** * Method to preprocess the form. * * @param Form $form A Form object. * @param mixed $data The data expected for the form. * @param string $group The name of the plugin group to import (defaults to "content"). * * @return void * * @since 4.0.0 */ protected function preprocessForm(Form $form, $data, $group = 'content') { $extension = Factory::getApplication()->getInput()->get('extension'); $parts = explode('.', $extension); $extension = array_shift($parts); // Set the access control rules field component value. $form->setFieldAttribute('rules', 'component', $extension); parent::preprocessForm($form, $data, $group); } } src/Model/StagesModel.php 0000644 00000014171 15172633314 0011324 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt * @since 4.0.0 */ namespace Joomla\Component\Workflow\Administrator\Model; use Joomla\CMS\Factory; use Joomla\CMS\MVC\Model\ListModel; use Joomla\Database\DatabaseQuery; use Joomla\Database\ParameterType; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Model class for stages * * @since 4.0.0 */ class StagesModel extends ListModel { /** * Constructor. * * @param array $config An optional associative array of configuration settings. * * @see JController * @since 4.0.0 */ public function __construct($config = []) { if (empty($config['filter_fields'])) { $config['filter_fields'] = [ 'id', 's.id', 'title', 's.title', 'ordering','s.ordering', 'published', 's.published', ]; } parent::__construct($config); } /** * Method to auto-populate the model state. * * This method should only be called once per instantiation and is designed * to be called on the first call to the getState() method unless the model * configuration flag to ignore the request is set. * * Note. Calling getState in this method will result in recursion. * * @param string $ordering An optional ordering field. * @param string $direction An optional direction (asc|desc). * * @return void * * @since 4.0.0 */ protected function populateState($ordering = 's.ordering', $direction = 'ASC') { $app = Factory::getApplication(); $workflowID = $app->getUserStateFromRequest($this->context . '.filter.workflow_id', 'workflow_id', 1, 'int'); $extension = $app->getUserStateFromRequest($this->context . '.filter.extension', 'extension', null, 'cmd'); if ($workflowID) { $table = $this->getTable('Workflow', 'Administrator'); if ($table->load($workflowID)) { $this->setState('active_workflow', $table->title); } } $this->setState('filter.workflow_id', $workflowID); $this->setState('filter.extension', $extension); parent::populateState($ordering, $direction); } /** * A protected method to get a set of ordering conditions. * * @param object $table A record object. * * @return array An array of conditions to add to ordering queries. * * @since 4.0.0 */ protected function getReorderConditions($table) { return [ $this->getDatabase()->quoteName('workflow_id') . ' = ' . (int) $table->workflow_id, ]; } /** * Method to get a table object, load it if necessary. * * @param string $type The table name. Optional. * @param string $prefix The class prefix. Optional. * @param array $config Configuration array for model. Optional. * * @return \Joomla\CMS\Table\Table A Table object * * @since 4.0.0 */ public function getTable($type = 'Stage', $prefix = 'Administrator', $config = []) { return parent::getTable($type, $prefix, $config); } /** * Method to get the data that should be injected in the form. * * @return DatabaseQuery The query to database. * * @since 4.0.0 */ public function getListQuery() { $db = $this->getDatabase(); $query = $db->getQuery(true); $query ->select( [ $db->quoteName('s.id'), $db->quoteName('s.title'), $db->quoteName('s.ordering'), $db->quoteName('s.default'), $db->quoteName('s.published'), $db->quoteName('s.checked_out'), $db->quoteName('s.checked_out_time'), $db->quoteName('s.description'), $db->quoteName('uc.name', 'editor'), ] ) ->from($db->quoteName('#__workflow_stages', 's')) ->join('LEFT', $db->quoteName('#__users', 'uc'), $db->quoteName('uc.id') . ' = ' . $db->quoteName('s.checked_out')); // Filter by extension if ($workflowID = (int) $this->getState('filter.workflow_id')) { $query->where($db->quoteName('s.workflow_id') . ' = :id') ->bind(':id', $workflowID, ParameterType::INTEGER); } $status = (string) $this->getState('filter.published'); // Filter by publish state if (is_numeric($status)) { $status = (int) $status; $query->where($db->quoteName('s.published') . ' = :status') ->bind(':status', $status, ParameterType::INTEGER); } elseif ($status === '') { $query->where($db->quoteName('s.published') . ' IN (0, 1)'); } // Filter by search in title $search = $this->getState('filter.search'); if (!empty($search)) { $search = '%' . str_replace(' ', '%', trim($search)) . '%'; $query->where('(' . $db->quoteName('s.title') . ' LIKE :search1 OR ' . $db->quoteName('s.description') . ' LIKE :search2)') ->bind([':search1', ':search2'], $search); } // Add the list ordering clause. $query->order($db->escape($this->getState('list.ordering', 's.ordering')) . ' ' . $db->escape($this->getState('list.direction', 'ASC'))); return $query; } /** * Returns a workflow object * * @return object The workflow * * @since 4.0.0 */ public function getWorkflow() { $table = $this->getTable('Workflow', 'Administrator'); $workflowId = (int) $this->getState('filter.workflow_id'); if ($workflowId > 0) { $table->load($workflowId); } return (object) $table->getProperties(); } } src/Model/WorkflowModel.php 0000644 00000026505 15172633314 0011714 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt * @since 4.0.0 */ namespace Joomla\Component\Workflow\Administrator\Model; use Joomla\CMS\Factory; use Joomla\CMS\Form\Form; use Joomla\CMS\Language\Text; use Joomla\CMS\Log\Log; use Joomla\CMS\MVC\Model\AdminModel; use Joomla\String\StringHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Model class for workflow * * @since 4.0.0 */ class WorkflowModel extends AdminModel { /** * Auto-populate the model state. * * Note. Calling getState in this method will result in recursion. * * @return void * * @since 4.0.0 */ public function populateState() { parent::populateState(); $app = Factory::getApplication(); $context = $this->option . '.' . $this->name; $extension = $app->getUserStateFromRequest($context . '.filter.extension', 'extension', null, 'cmd'); $this->setState('filter.extension', $extension); } /** * Method to change the title * * @param integer $categoryId The id of the category. * @param string $alias The alias. * @param string $title The title. * * @return array Contains the modified title and alias. * * @since 4.0.0 */ protected function generateNewTitle($categoryId, $alias, $title) { // Alter the title & alias $table = $this->getTable(); while ($table->load(['title' => $title])) { $title = StringHelper::increment($title); } return [$title, $alias]; } /** * Method to save the form data. * * @param array $data The form data. * * @return boolean True on success. * * @since 4.0.0 */ public function save($data) { $table = $this->getTable(); $app = Factory::getApplication(); $user = $app->getIdentity(); $input = $app->getInput(); $context = $this->option . '.' . $this->name; $extension = $app->getUserStateFromRequest($context . '.filter.extension', 'extension', null, 'cmd'); $data['extension'] = !empty($data['extension']) ? $data['extension'] : $extension; // Make sure we use the correct extension when editing an existing workflow $key = $table->getKeyName(); $pk = (isset($data[$key])) ? $data[$key] : (int) $this->getState($this->getName() . '.id'); if ($pk > 0) { $table->load($pk); $data['extension'] = $table->extension; } if (isset($data['rules']) && !$user->authorise('core.admin', $data['extension'])) { unset($data['rules']); } if ($input->get('task') == 'save2copy') { $origTable = clone $this->getTable(); // Alter the title for save as copy if ($origTable->load(['title' => $data['title']])) { list($title) = $this->generateNewTitle(0, '', $data['title']); $data['title'] = $title; } // Unpublish new copy $data['published'] = 0; $data['default'] = 0; } $result = parent::save($data); // Create default stage for new workflow if ($result && $input->getCmd('task') !== 'save2copy' && $this->getState($this->getName() . '.new')) { $workflow_id = (int) $this->getState($this->getName() . '.id'); $table = $this->getTable('Stage'); $table->id = 0; $table->title = 'COM_WORKFLOW_BASIC_STAGE'; $table->description = ''; $table->workflow_id = $workflow_id; $table->published = 1; $table->default = 1; $table->store(); } return $result; } /** * Abstract method for getting the form from the model. * * @param array $data Data for the form. * @param boolean $loadData True if the form is to load its own data (default case), false if not. * * @return \Joomla\CMS\Form\Form|boolean A Form object on success, false on failure * * @since 4.0.0 */ public function getForm($data = [], $loadData = true) { // Get the form. $form = $this->loadForm( 'com_workflow.workflow', 'workflow', [ 'control' => 'jform', 'load_data' => $loadData, ] ); if (empty($form)) { return false; } $id = $data['id'] ?? $form->getValue('id'); $item = $this->getItem($id); $canEditState = $this->canEditState((object) $item); // Modify the form based on access controls. if (!$canEditState || !empty($item->default)) { if (!$canEditState) { $form->setFieldAttribute('published', 'disabled', 'true'); $form->setFieldAttribute('published', 'required', 'false'); $form->setFieldAttribute('published', 'filter', 'unset'); } $form->setFieldAttribute('default', 'disabled', 'true'); $form->setFieldAttribute('default', 'required', 'false'); $form->setFieldAttribute('default', 'filter', 'unset'); } $form->setFieldAttribute('created', 'default', Factory::getDate()->format('Y-m-d H:i:s')); $form->setFieldAttribute('modified', 'default', Factory::getDate()->format('Y-m-d H:i:s')); return $form; } /** * Method to get the data that should be injected in the form. * * @return mixed The data for the form. * * @since 4.0.0 */ protected function loadFormData() { // Check the session for previously entered form data. $data = Factory::getApplication()->getUserState( 'com_workflow.edit.workflow.data', [] ); if (empty($data)) { $data = $this->getItem(); } return $data; } /** * Method to preprocess the form. * * @param Form $form Form object. * @param mixed $data The data expected for the form. * @param string $group The name of the plugin group to import (defaults to "content"). * * @return void * * @since 4.0.0 */ protected function preprocessForm(Form $form, $data, $group = 'content') { $extension = Factory::getApplication()->getInput()->get('extension'); $parts = explode('.', $extension); $extension = array_shift($parts); // Set the access control rules field component value. $form->setFieldAttribute('rules', 'component', $extension); parent::preprocessForm($form, $data, $group); } /** * A protected method to get a set of ordering conditions. * * @param object $table A record object. * * @return array An array of conditions to add to ordering queries. * * @since 4.0.0 */ protected function getReorderConditions($table) { $db = $this->getDatabase(); return [ $db->quoteName('extension') . ' = ' . $db->quote($table->extension), ]; } /** * Method to change the default state of one item. * * @param array $pk A list of the primary keys to change. * @param integer $value The value of the home state. * * @return boolean True on success. * * @since 4.0.0 */ public function setDefault($pk, $value = 1) { $table = $this->getTable(); if ($table->load($pk)) { if ($table->published !== 1) { $this->setError(Text::_('COM_WORKFLOW_ITEM_MUST_PUBLISHED')); return false; } } if (empty($table->id) || !$this->canEditState($table)) { Log::add(Text::_('JLIB_APPLICATION_ERROR_EDITSTATE_NOT_PERMITTED'), Log::WARNING, 'jerror'); return false; } $date = Factory::getDate()->toSql(); if ($value) { // Unset other default item if ( $table->load( [ 'default' => '1', 'extension' => $table->get('extension'), ] ) ) { $table->default = 0; $table->modified = $date; $table->store(); } } if ($table->load($pk)) { $table->modified = $date; $table->default = $value; $table->store(); } // Clean the cache $this->cleanCache(); return true; } /** * Method to test whether a record can be deleted. * * @param object $record A record object. * * @return boolean True if allowed to delete the record. Defaults to the permission for the component. * * @since 4.0.0 */ protected function canDelete($record) { if (empty($record->id) || $record->published != -2) { return false; } return $this->getCurrentUser()->authorise('core.delete', $record->extension . '.workflow.' . (int) $record->id); } /** * Method to test whether a record can have its state changed. * * @param object $record A record object. * * @return boolean True if allowed to change the state of the record. Defaults to the permission set in the component. * * @since 4.0.0 */ protected function canEditState($record) { $user = $this->getCurrentUser(); // Check for existing workflow. if (!empty($record->id)) { return $user->authorise('core.edit.state', $record->extension . '.workflow.' . (int) $record->id); } // Default to component settings if workflow isn't known. return $user->authorise('core.edit.state', $record->extension); } /** * Method to change the published state of one or more records. * * @param array &$pks A list of the primary keys to change. * @param integer $value The value of the published state. * * @return boolean True on success. * * @since 4.0.0 */ public function publish(&$pks, $value = 1) { $table = $this->getTable(); $pks = (array) $pks; $date = Factory::getDate()->toSql(); // Default workflow item check. foreach ($pks as $i => $pk) { if ($table->load($pk) && $value != 1 && $table->default) { // Prune items that you can't change. Factory::getApplication()->enqueueMessage(Text::_('COM_WORKFLOW_UNPUBLISH_DEFAULT_ERROR'), 'error'); unset($pks[$i]); break; } } // Clean the cache. $this->cleanCache(); // Ensure that previous checks don't empty the array. if (empty($pks)) { return true; } $table->load($pk); $table->modified = $date; $table->store(); return parent::publish($pks, $value); } } src/Model/TransitionsModel.php 0000644 00000020203 15172633314 0012404 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt * @since 4.0.0 */ namespace Joomla\Component\Workflow\Administrator\Model; use Joomla\CMS\Factory; use Joomla\CMS\MVC\Model\ListModel; use Joomla\Database\DatabaseQuery; use Joomla\Database\ParameterType; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Model class for transitions * * @since 4.0.0 */ class TransitionsModel extends ListModel { /** * Constructor. * * @param array $config An optional associative array of configuration settings. * * @see JController * @since 4.0.0 */ public function __construct($config = []) { if (empty($config['filter_fields'])) { $config['filter_fields'] = [ 'id', 't.id', 'published', 't.published', 'ordering', 't.ordering', 'title', 't.title', 'from_stage', 't.from_stage_id', 'to_stage', 't.to_stage_id', ]; } parent::__construct($config); } /** * Method to auto-populate the model state. * * This method should only be called once per instantiation and is designed * to be called on the first call to the getState() method unless the model * configuration flag to ignore the request is set. * * Note. Calling getState in this method will result in recursion. * * @param string $ordering An optional ordering field. * @param string $direction An optional direction (asc|desc). * * @return void * * @since 4.0.0 */ protected function populateState($ordering = 't.ordering', $direction = 'ASC') { $app = Factory::getApplication(); $workflowID = $app->getUserStateFromRequest($this->context . '.filter.workflow_id', 'workflow_id', 1, 'int'); $extension = $app->getUserStateFromRequest($this->context . '.filter.extension', 'extension', null, 'cmd'); if ($workflowID) { $table = $this->getTable('Workflow', 'Administrator'); if ($table->load($workflowID)) { $this->setState('active_workflow', $table->title); } } $this->setState('filter.workflow_id', $workflowID); $this->setState('filter.extension', $extension); parent::populateState($ordering, $direction); } /** * Method to get a table object, load it if necessary. * * @param string $type The table name. Optional. * @param string $prefix The class prefix. Optional. * @param array $config Configuration array for model. Optional. * * @return \Joomla\CMS\Table\Table A Table object * * @since 4.0.0 */ public function getTable($type = 'Transition', $prefix = 'Administrator', $config = []) { return parent::getTable($type, $prefix, $config); } /** * A protected method to get a set of ordering conditions. * * @param object $table A record object. * * @return array An array of conditions to add to ordering queries. * * @since 4.0.0 */ protected function getReorderConditions($table) { return [ $this->getDatabase()->quoteName('workflow_id') . ' = ' . (int) $table->workflow_id, ]; } /** * Method to get the data that should be injected in the form. * * @return DatabaseQuery The query to database. * * @since 4.0.0 */ public function getListQuery() { $db = $this->getDatabase(); $query = $db->getQuery(true); $query ->select( [ $db->quoteName('t.id'), $db->quoteName('t.title'), $db->quoteName('t.from_stage_id'), $db->quoteName('t.to_stage_id'), $db->quoteName('t.published'), $db->quoteName('t.checked_out'), $db->quoteName('t.checked_out_time'), $db->quoteName('t.ordering'), $db->quoteName('t.description'), $db->quoteName('f_stage.title', 'from_stage'), $db->quoteName('t_stage.title', 'to_stage'), $db->quoteName('uc.name', 'editor'), ] ) ->from($db->quoteName('#__workflow_transitions', 't')) ->join('LEFT', $db->quoteName('#__workflow_stages', 'f_stage'), $db->quoteName('f_stage.id') . ' = ' . $db->quoteName('t.from_stage_id')) ->join('LEFT', $db->quoteName('#__workflow_stages', 't_stage'), $db->quoteName('t_stage.id') . ' = ' . $db->quoteName('t.to_stage_id')) ->join('LEFT', $db->quoteName('#__users', 'uc'), $db->quoteName('uc.id') . ' = ' . $db->quoteName('t.checked_out')); // Filter by extension if ($workflowID = (int) $this->getState('filter.workflow_id')) { $query->where($db->quoteName('t.workflow_id') . ' = :id') ->bind(':id', $workflowID, ParameterType::INTEGER); } $status = (string) $this->getState('filter.published'); // Filter by status if (is_numeric($status)) { $status = (int) $status; $query->where($db->quoteName('t.published') . ' = :status') ->bind(':status', $status, ParameterType::INTEGER); } elseif ($status === '') { $query->where($db->quoteName('t.published') . ' IN (0, 1)'); } // Filter by column from_stage_id if ($fromStage = (int) $this->getState('filter.from_stage')) { $query->where($db->quoteName('from_stage_id') . ' = :fromStage') ->bind(':fromStage', $fromStage, ParameterType::INTEGER); } // Filter by column to_stage_id if ($toStage = (int) $this->getState('filter.to_stage')) { $query->where($db->quoteName('to_stage_id') . ' = :toStage') ->bind(':toStage', $toStage, ParameterType::INTEGER); } // Filter by search in title $search = $this->getState('filter.search'); if (!empty($search)) { $search = '%' . str_replace(' ', '%', trim($search)) . '%'; $query->where('(' . $db->quoteName('t.title') . ' LIKE :search1 OR ' . $db->quoteName('t.description') . ' LIKE :search2)') ->bind([':search1', ':search2'], $search); } // Add the list ordering clause. $orderCol = $this->state->get('list.ordering', 't.id'); $orderDirn = strtoupper($this->state->get('list.direction', 'ASC')); $query->order($db->escape($orderCol) . ' ' . ($orderDirn === 'DESC' ? 'DESC' : 'ASC')); return $query; } /** * Get the filter form * * @param array $data data * @param boolean $loadData load current data * * @return \Joomla\CMS\Form\Form|boolean The Form object or false on error * * @since 4.0.0 */ public function getFilterForm($data = [], $loadData = true) { $form = parent::getFilterForm($data, $loadData); $id = (int) $this->getState('filter.workflow_id'); if ($form) { $where = $this->getDatabase()->quoteName('workflow_id') . ' = ' . $id . ' AND ' . $this->getDatabase()->quoteName('published') . ' = 1'; $form->setFieldAttribute('from_stage', 'sql_where', $where, 'filter'); $form->setFieldAttribute('to_stage', 'sql_where', $where, 'filter'); } return $form; } /** * Returns a workflow object * * @return object The workflow * * @since 4.0.0 */ public function getWorkflow() { $table = $this->getTable('Workflow', 'Administrator'); $workflowId = (int) $this->getState('filter.workflow_id'); if ($workflowId > 0) { $table->load($workflowId); } return (object) $table->getProperties(); } } src/Helper/StageHelper.php 0000644 00000001215 15172633314 0011472 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Workflow\Administrator\Helper; use Joomla\CMS\Helper\ContentHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * The first example class, this is in the same * package as declared at the start of file but * this example has a defined subpackage * * @since 4.0.0 */ class StageHelper extends ContentHelper { } src/Helper/WorkflowHelper.php 0000644 00000001042 15172633314 0012237 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Workflow\Administrator\Helper; use Joomla\CMS\Helper\ContentHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Workflows component helper * @since 4.0.0 */ class WorkflowHelper extends ContentHelper { } src/Table/StageTable.php 0000644 00000017060 15172633314 0011117 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Workflow\Administrator\Table; use Joomla\CMS\Access\Rules; use Joomla\CMS\Factory; use Joomla\CMS\Language\Text; use Joomla\CMS\Table\Table; use Joomla\Database\DatabaseDriver; use Joomla\Database\ParameterType; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Stage table * * @since 4.0.0 */ class StageTable extends Table { /** * Indicates that columns fully support the NULL value in the database * * @var boolean * * @since 4.0.0 */ protected $_supportNullValue = true; /** * @param DatabaseDriver $db Database connector object * * @since 4.0.0 */ public function __construct(DatabaseDriver $db) { parent::__construct('#__workflow_stages', 'id', $db); } /** * Deletes workflow with transition and stages. * * @param int $pk Extension ids to delete. * * @return boolean True on success. * * @since 4.0.0 * * @throws \UnexpectedValueException */ public function delete($pk = null) { $db = $this->getDbo(); $app = Factory::getApplication(); $pk = (int) $pk; $query = $db->getQuery(true) ->select($db->quoteName('default')) ->from($db->quoteName('#__workflow_stages')) ->where($db->quoteName('id') . ' = :id') ->bind(':id', $pk, ParameterType::INTEGER); $isDefault = $db->setQuery($query)->loadResult(); if ($isDefault) { $app->enqueueMessage(Text::_('COM_WORKFLOW_MSG_DELETE_IS_DEFAULT'), 'error'); return false; } try { $query = $db->getQuery(true) ->delete($db->quoteName('#__workflow_transitions')) ->where( [ $db->quoteName('to_stage_id') . ' = :idTo', $db->quoteName('from_stage_id') . ' = :idFrom', ], 'OR' ) ->bind([':idTo', ':idFrom'], $pk, ParameterType::INTEGER); $db->setQuery($query)->execute(); return parent::delete($pk); } catch (\RuntimeException $e) { $app->enqueueMessage(Text::sprintf('COM_WORKFLOW_MSG_WORKFLOWS_DELETE_ERROR', $e->getMessage()), 'error'); } return false; } /** * Overloaded check function * * @return boolean True on success * * @see Table::check() * @since 4.0.0 */ public function check() { try { parent::check(); } catch (\Exception $e) { $this->setError($e->getMessage()); return false; } if (trim($this->title) === '') { $this->setError(Text::_('JLIB_DATABASE_ERROR_MUSTCONTAIN_A_TITLE_STATE')); return false; } if (!empty($this->default)) { if ((int) $this->published !== 1) { $this->setError(Text::_('COM_WORKFLOW_ITEM_MUST_PUBLISHED')); return false; } } else { $db = $this->getDbo(); $query = $db->getQuery(true); $query ->select($db->quoteName('id')) ->from($db->quoteName('#__workflow_stages')) ->where( [ $db->quoteName('workflow_id') . ' = :id', $db->quoteName('default') . ' = 1', ] ) ->bind(':id', $this->workflow_id, ParameterType::INTEGER); $id = $db->setQuery($query)->loadResult(); // If there is no default stage => set the current to default to recover if (empty($id)) { $this->default = '1'; } elseif ($id === $this->id) { // This stage is the default, but someone has tried to disable it => not allowed $this->setError(Text::_('COM_WORKFLOW_DISABLE_DEFAULT')); return false; } } return true; } /** * Overloaded store function * * @param boolean $updateNulls True to update fields even if they are null. * * @return mixed False on failure, positive integer on success. * * @see Table::store() * @since 4.0.0 */ public function store($updateNulls = true) { $table = new StageTable($this->getDbo()); if ($this->default == '1') { // Verify that the default is unique for this workflow if ($table->load(['default' => '1', 'workflow_id' => (int) $this->workflow_id])) { $table->default = 0; $table->store(); } } return parent::store($updateNulls); } /** * Method to bind an associative array or object to the Table instance. * This method only binds properties that are publicly accessible and optionally * takes an array of properties to ignore when binding. * * @param array|object $src An associative array or object to bind to the Table instance. * @param array|string $ignore An optional array or space separated list of properties to ignore while binding. * * @return boolean True on success. * * @since 4.0.0 * @throws \InvalidArgumentException */ public function bind($src, $ignore = []) { // Bind the rules. if (isset($src['rules']) && \is_array($src['rules'])) { $rules = new Rules($src['rules']); $this->setRules($rules); } return parent::bind($src, $ignore); } /** * Method to compute the default name of the asset. * The default name is in the form table_name.id * where id is the value of the primary key of the table. * * @return string * * @since 4.0.0 */ protected function _getAssetName() { $k = $this->_tbl_key; $workflow = new WorkflowTable($this->getDbo()); $workflow->load($this->workflow_id); $parts = explode('.', $workflow->extension); $extension = array_shift($parts); return $extension . '.stage.' . (int) $this->$k; } /** * Method to return the title to use for the asset table. * * @return string * * @since 4.0.0 */ protected function _getAssetTitle() { return $this->title; } /** * Get the parent asset id for the record * * @param Table|null $table A Table object for the asset parent. * @param integer|null $id The id for the asset * * @return integer The id of the asset's parent * * @since 4.0.0 */ protected function _getAssetParentId(Table $table = null, $id = null) { $asset = self::getInstance('Asset', 'JTable', ['dbo' => $this->getDbo()]); $workflow = new WorkflowTable($this->getDbo()); $workflow->load($this->workflow_id); $parts = explode('.', $workflow->extension); $extension = array_shift($parts); $name = $extension . '.workflow.' . (int) $workflow->id; $asset->loadByName($name); $assetId = $asset->id; return !empty($assetId) ? $assetId : parent::_getAssetParentId($table, $id); } } src/Table/WorkflowTable.php 0000644 00000021103 15172633314 0011657 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Workflow\Administrator\Table; use Joomla\CMS\Access\Rules; use Joomla\CMS\Factory; use Joomla\CMS\Language\Text; use Joomla\CMS\Table\Table; use Joomla\Database\DatabaseDriver; use Joomla\Database\ParameterType; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Workflow table * * @since 4.0.0 */ class WorkflowTable extends Table { /** * Indicates that columns fully support the NULL value in the database * * @var boolean * * @since 4.0.0 */ protected $_supportNullValue = true; /** * @param DatabaseDriver $db Database connector object * * @since 4.0.0 */ public function __construct(DatabaseDriver $db) { $this->typeAlias = '{extension}.workflow'; parent::__construct('#__workflows', 'id', $db); } /** * Deletes workflow with transition and states. * * @param int $pk Extension ids to delete. * * @return boolean * * @since 4.0.0 * * @throws \Exception on ACL error */ public function delete($pk = null) { $db = $this->getDbo(); $app = Factory::getApplication(); $pk = (int) $pk; // Gets the workflow information that is going to be deleted. $query = $db->getQuery(true) ->select($db->quoteName('default')) ->from($db->quoteName('#__workflows')) ->where($db->quoteName('id') . ' = :id') ->bind(':id', $pk, ParameterType::INTEGER); $isDefault = $db->setQuery($query)->loadResult(); if ($isDefault) { $app->enqueueMessage(Text::_('COM_WORKFLOW_MSG_DELETE_DEFAULT'), 'error'); return false; } // Delete the workflow states, then transitions from all tables. try { $query = $db->getQuery(true) ->delete($db->quoteName('#__workflow_stages')) ->where($db->quoteName('workflow_id') . ' = :id') ->bind(':id', $pk, ParameterType::INTEGER); $db->setQuery($query)->execute(); $query = $db->getQuery(true) ->delete($db->quoteName('#__workflow_transitions')) ->where($db->quoteName('workflow_id') . ' = :id') ->bind(':id', $pk, ParameterType::INTEGER); $db->setQuery($query)->execute(); return parent::delete($pk); } catch (\RuntimeException $e) { $app->enqueueMessage(Text::sprintf('COM_WORKFLOW_MSG_WORKFLOWS_DELETE_ERROR', $e->getMessage()), 'error'); return false; } } /** * Overloaded check function * * @return boolean True on success * * @see Table::check() * @since 4.0.0 */ public function check() { try { parent::check(); } catch (\Exception $e) { $this->setError($e->getMessage()); return false; } if (trim($this->title) === '') { $this->setError(Text::_('JLIB_DATABASE_ERROR_MUSTCONTAIN_A_TITLE_WORKFLOW')); return false; } if (!empty($this->default)) { if ((int) $this->published !== 1) { $this->setError(Text::_('COM_WORKFLOW_ITEM_MUST_PUBLISHED')); return false; } } else { $db = $this->getDbo(); $query = $db->getQuery(true); $query ->select($db->quoteName('id')) ->from($db->quoteName('#__workflows')) ->where($db->quoteName('default') . ' = 1'); $id = $db->setQuery($query)->loadResult(); // If there is no default workflow => set the current to default to recover if (empty($id)) { $this->default = '1'; } elseif ($id === $this->id) { // This workflow is the default, but someone has tried to disable it => not allowed $this->setError(Text::_('COM_WORKFLOW_DISABLE_DEFAULT')); return false; } } return true; } /** * Overloaded store function * * @param boolean $updateNulls True to update fields even if they are null. * * @return mixed False on failure, positive integer on success. * * @see Table::store() * @since 4.0.0 */ public function store($updateNulls = true) { $date = Factory::getDate(); $user = Factory::getUser(); $table = new WorkflowTable($this->getDbo()); if ($this->id) { // Existing item $this->modified_by = $user->id; $this->modified = $date->toSql(); } else { $this->modified_by = 0; } if (!(int) $this->created) { $this->created = $date->toSql(); } if (empty($this->created_by)) { $this->created_by = $user->id; } if (!(int) $this->modified) { $this->modified = $this->created; } if (empty($this->modified_by)) { $this->modified_by = $this->created_by; } if ((int) $this->default === 1) { // Verify that the default is unique for this workflow if ( $table->load( [ 'default' => '1', 'extension' => $this->extension, ] ) ) { $table->default = 0; $table->store(); } } return parent::store($updateNulls); } /** * Method to bind an associative array or object to the Table instance. * This method only binds properties that are publicly accessible and optionally * takes an array of properties to ignore when binding. * * @param array|object $src An associative array or object to bind to the Table instance. * @param array|string $ignore An optional array or space separated list of properties to ignore while binding. * * @return boolean True on success. * * @since 4.0.0 * @throws \InvalidArgumentException */ public function bind($src, $ignore = []) { // Bind the rules. if (isset($src['rules']) && \is_array($src['rules'])) { $rules = new Rules($src['rules']); $this->setRules($rules); } return parent::bind($src, $ignore); } /** * Method to compute the default name of the asset. * The default name is in the form table_name.id * where id is the value of the primary key of the table. * * @return string * * @since 4.0.0 */ protected function _getAssetName() { $k = $this->_tbl_key; $parts = explode('.', $this->extension); $extension = array_shift($parts); return $extension . '.workflow.' . (int) $this->$k; } /** * Method to return the title to use for the asset table. * * @return string * * @since 4.0.0 */ protected function _getAssetTitle() { return $this->title; } /** * Get the parent asset id for the record * * @param Table $table A Table object for the asset parent. * @param integer $id The id for the asset * * @return integer The id of the asset's parent * * @since 4.0.0 */ protected function _getAssetParentId(Table $table = null, $id = null) { $assetId = null; $parts = explode('.', $this->extension); $extension = array_shift($parts); // Build the query to get the asset id for the parent category. $query = $this->getDbo()->getQuery(true) ->select($this->getDbo()->quoteName('id')) ->from($this->getDbo()->quoteName('#__assets')) ->where($this->getDbo()->quoteName('name') . ' = :extension') ->bind(':extension', $extension); // Get the asset id from the database. $this->getDbo()->setQuery($query); if ($result = $this->getDbo()->loadResult()) { $assetId = (int) $result; } // Return the asset id. if ($assetId) { return $assetId; } else { return parent::_getAssetParentId($table, $id); } } } src/Table/TransitionTable.php 0000644 00000007273 15172633314 0012213 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Workflow\Administrator\Table; use Joomla\CMS\Access\Rules; use Joomla\CMS\Table\Table; use Joomla\Database\DatabaseDriver; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Transition table * * @since 4.0.0 */ class TransitionTable extends Table { /** * Indicates that columns fully support the NULL value in the database * * @var boolean * * @since 4.0.0 */ protected $_supportNullValue = true; /** * An array of key names to be json encoded in the bind function * * @var array * * @since 4.0.0 */ protected $_jsonEncode = [ 'options', ]; /** * @param DatabaseDriver $db Database connector object * * @since 4.0.0 */ public function __construct(DatabaseDriver $db) { parent::__construct('#__workflow_transitions', 'id', $db); } /** * Method to bind an associative array or object to the Table instance. * This method only binds properties that are publicly accessible and optionally * takes an array of properties to ignore when binding. * * @param array|object $src An associative array or object to bind to the Table instance. * @param array|string $ignore An optional array or space separated list of properties to ignore while binding. * * @return boolean True on success. * * @since 4.0.0 * @throws \InvalidArgumentException */ public function bind($src, $ignore = []) { // Bind the rules. if (isset($src['rules']) && \is_array($src['rules'])) { $rules = new Rules($src['rules']); $this->setRules($rules); } return parent::bind($src, $ignore); } /** * Method to compute the default name of the asset. * The default name is in the form table_name.id * where id is the value of the primary key of the table. * * @return string * * @since 4.0.0 */ protected function _getAssetName() { $k = $this->_tbl_key; $workflow = new WorkflowTable($this->getDbo()); $workflow->load($this->workflow_id); $parts = explode('.', $workflow->extension); $extension = array_shift($parts); return $extension . '.transition.' . (int) $this->$k; } /** * Method to return the title to use for the asset table. * * @return string * * @since 4.0.0 */ protected function _getAssetTitle() { return $this->title; } /** * Get the parent asset id for the record * * @param Table $table A Table object for the asset parent. * @param integer $id The id for the asset * * @return integer The id of the asset's parent * * @since 4.0.0 */ protected function _getAssetParentId(Table $table = null, $id = null) { $asset = self::getInstance('Asset', 'JTable', ['dbo' => $this->getDbo()]); $workflow = new WorkflowTable($this->getDbo()); $workflow->load($this->workflow_id); $parts = explode('.', $workflow->extension); $extension = array_shift($parts); $name = $extension . '.workflow.' . (int) $workflow->id; $asset->loadByName($name); $assetId = $asset->id; return !empty($assetId) ? $assetId : parent::_getAssetParentId($table, $id); } } tmpl/stages/default.php 0000644 00000022300 15172633314 0011145 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt * @since 4.0.0 */ defined('_JEXEC') or die; use Joomla\CMS\Factory; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; use Joomla\CMS\Session\Session; /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('table.columns') ->useScript('multiselect'); $user = Factory::getUser(); $userId = $user->id; $listOrder = $this->escape($this->state->get('list.ordering')); $listDirn = $this->escape($this->state->get('list.direction')); $saveOrderingUrl = ''; $saveOrder = ($listOrder == 's.ordering'); if ($saveOrder) { $saveOrderingUrl = 'index.php?option=com_workflow&task=stages.saveOrderAjax&workflow_id=' . (int) $this->workflowID . '&extension=' . $this->escape($this->extension) . '&' . Session::getFormToken() . '=1'; HTMLHelper::_('draggablelist.draggable'); } ?> <form action="<?php echo Route::_('index.php?option=com_workflow&view=stages&workflow_id=' . (int) $this->workflowID . '&extension=' . $this->extension); ?>" method="post" name="adminForm" id="adminForm"> <div class="row"> <?php if (!empty($this->sidebar)) : ?> <div id="j-sidebar-container" class="col-md-2"> <?php echo $this->sidebar; ?> </div> <?php endif; ?> <div class="<?php if (!empty($this->sidebar)) { echo 'col-md-10'; } else { echo 'col-md-12'; } ?>"> <div id="j-main-container" class="j-main-container"> <?php // Search tools bar echo LayoutHelper::render('joomla.searchtools.default', ['view' => $this]); ?> <?php if (empty($this->stages)) : ?> <div class="alert alert-info"> <span class="icon-info-circle" aria-hidden="true"></span><span class="visually-hidden"><?php echo Text::_('INFO'); ?></span> <?php echo Text::_('JGLOBAL_NO_MATCHING_RESULTS'); ?> </div> <?php else : ?> <table class="table"> <caption class="visually-hidden"> <?php echo Text::_('COM_WORKFLOW_STAGES_TABLE_CAPTION'); ?>, <span id="orderedBy"><?php echo Text::_('JGLOBAL_SORTED_BY'); ?> </span>, <span id="filteredBy"><?php echo Text::_('JGLOBAL_FILTERED_BY'); ?></span> </caption> <thead> <tr> <td class="w-1 text-center d-none d-md-table-cell"> <?php echo HTMLHelper::_('grid.checkall'); ?> </td> <th scope="col" class="w-1 text-center d-none d-md-table-cell"> <?php echo HTMLHelper::_('searchtools.sort', '', 's.ordering', $listDirn, $listOrder, null, 'asc', 'JGRID_HEADING_ORDERING', 'icon-menu-2'); ?> </th> <th scope="col" class="w-1 text-center"> <?php echo HTMLHelper::_('searchtools.sort', 'JSTATUS', 's.published', $listDirn, $listOrder); ?> </th> <th scope="col" class="w-1 text-center"> <?php echo Text::_('COM_WORKFLOW_DEFAULT'); ?> </th> <th scope="col"> <?php echo HTMLHelper::_('searchtools.sort', 'COM_WORKFLOW_NAME', 's.title', $listDirn, $listOrder); ?> </th> <th scope="col" class="w-5 d-none d-md-table-cell"> <?php echo HTMLHelper::_('searchtools.sort', 'COM_WORKFLOW_ID', 's.id', $listDirn, $listOrder); ?> </th> </tr> </thead> <tbody class="js-draggable" data-url="<?php echo $saveOrderingUrl; ?>" data-direction="<?php echo strtolower($listDirn); ?>"> <?php foreach ($this->stages as $i => $item) : $edit = Route::_('index.php?option=com_workflow&task=stage.edit&id=' . $item->id . '&workflow_id=' . (int) $this->workflowID . '&extension=' . $this->extension); $canEdit = $user->authorise('core.edit', $this->extension . '.stage.' . $item->id); $canCheckin = $user->authorise('core.admin', 'com_workflow') || $item->checked_out == $userId || is_null($item->checked_out); $canChange = $user->authorise('core.edit.state', $this->extension . '.stage.' . $item->id) && $canCheckin; ?> <tr class="row<?php echo $i % 2; ?>"> <td class="text-center d-none d-md-table-cell"> <?php echo HTMLHelper::_('grid.id', $i, $item->id, false, 'cid', 'cb', Text::_($item->title)); ?> </td> <td class="text-center d-none d-md-table-cell"> <?php $iconClass = ''; if (!$canChange) { $iconClass = ' inactive'; } elseif (!$saveOrder) { $iconClass = ' inactive" title="' . Text::_('JORDERINGDISABLED'); } ?> <span class="sortable-handler<?php echo $iconClass ?>"> <span class="icon-ellipsis-v" aria-hidden="true"></span> </span> <?php if ($canChange && $saveOrder) : ?> <input type="text" name="order[]" size="5" value="<?php echo $item->ordering; ?>" class="width-20 text-area-order hidden"> <?php endif; ?> </td> <td class="text-center"> <?php echo HTMLHelper::_('jgrid.published', $item->published, $i, 'stages.', $canChange); ?> </td> <td class="text-center"> <?php echo HTMLHelper::_('jgrid.isdefault', $item->default, $i, 'stages.', $canChange); ?> </td> <th scope="row"> <?php if ($item->checked_out) : ?> <?php echo HTMLHelper::_('jgrid.checkedout', $i, $item->editor, $item->checked_out_time, 'stages.', $canCheckin); ?> <?php endif; ?> <?php if ($canEdit) : ?> <a href="<?php echo $edit; ?>" title="<?php echo Text::_('JACTION_EDIT'); ?> <?php echo $this->escape(Text::_($item->title)); ?>"> <?php echo $this->escape(Text::_($item->title)); ?> </a> <div class="small"><?php echo $this->escape(Text::_($item->description)); ?></div> <?php else : ?> <?php echo $this->escape(Text::_($item->title)); ?> <div class="small"><?php echo $this->escape(Text::_($item->description)); ?></div> <?php endif; ?> </th> <td class="d-none d-md-table-cell"> <?php echo (int) $item->id; ?> </td> </tr> <?php endforeach ?> </tbody> </table> <?php // load the pagination. ?> <?php echo $this->pagination->getListFooter(); ?> <?php endif; ?> <input type="hidden" name="task" value=""> <input type="hidden" name="boxchecked" value="0"> <input type="hidden" name="workflow_id" value="<?php echo (int) $this->workflowID ?>"> <input type="hidden" name="extension" value="<?php echo $this->extension ?>"> <?php echo HTMLHelper::_('form.token'); ?> </div> </div> </div> </form> tmpl/transitions/default.php 0000644 00000024030 15172633314 0012236 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt * @since 4.0.0 */ defined('_JEXEC') or die; use Joomla\CMS\Factory; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; use Joomla\CMS\Session\Session; /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('table.columns') ->useScript('multiselect'); $user = Factory::getUser(); $listOrder = $this->escape($this->state->get('list.ordering')); $listDirn = $this->escape($this->state->get('list.direction')); $saveOrderingUrl = ''; $saveOrder = ($listOrder == 't.ordering'); if ($saveOrder) { $saveOrderingUrl = 'index.php?option=com_workflow&task=transitions.saveOrderAjax&workflow_id=' . (int) $this->workflowID . '&extension=' . $this->escape($this->workflow->extension) . '&' . Session::getFormToken() . '=1'; HTMLHelper::_('draggablelist.draggable'); } ?> <form action="<?php echo Route::_('index.php?option=com_workflow&view=transitions&workflow_id=' . (int) $this->workflowID . '&extension=' . $this->escape($this->workflow->extension)); ?>" method="post" name="adminForm" id="adminForm"> <div class="row"> <?php if (!empty($this->sidebar)) : ?> <div id="j-sidebar-container" class="col-md-2"> <?php echo $this->sidebar; ?> </div> <?php endif; ?> <div class="<?php if (!empty($this->sidebar)) { echo 'col-md-10'; } else { echo 'col-md-12'; } ?>"> <div id="j-main-container" class="j-main-container"> <?php // Search tools bar echo LayoutHelper::render('joomla.searchtools.default', ['view' => $this]); ?> <?php if (empty($this->transitions)) : ?> <div class="alert alert-info"> <span class="icon-info-circle" aria-hidden="true"></span><span class="visually-hidden"><?php echo Text::_('INFO'); ?></span> <?php echo Text::_('JGLOBAL_NO_MATCHING_RESULTS'); ?> </div> <?php else : ?> <table class="table"> <caption class="visually-hidden"> <?php echo Text::_('COM_WORKFLOW_TRANSITIONS_TABLE_CAPTION'); ?>, <span id="orderedBy"><?php echo Text::_('JGLOBAL_SORTED_BY'); ?> </span>, <span id="filteredBy"><?php echo Text::_('JGLOBAL_FILTERED_BY'); ?></span> </caption> <thead> <tr> <td class="w-1 text-center d-none d-md-table-cell"> <?php echo HTMLHelper::_('grid.checkall'); ?> </td> <th scope="col" class="w-1 text-center d-none d-md-table-cell"> <?php echo HTMLHelper::_('searchtools.sort', '', 't.ordering', $listDirn, $listOrder, null, 'asc', 'JGRID_HEADING_ORDERING', 'icon-menu-2'); ?> </th> <th scope="col" class="w-1 text-center"> <?php echo HTMLHelper::_('searchtools.sort', 'JSTATUS', 't.published', $listDirn, $listOrder); ?> </th> <th scope="col" class="w-20"> <?php echo HTMLHelper::_('searchtools.sort', 'COM_WORKFLOW_NAME', 't.title', $listDirn, $listOrder); ?> </th> <th scope="col" class="w-20"> <?php echo HTMLHelper::_('searchtools.sort', 'COM_WORKFLOW_FROM_STAGE', 'from_stage', $listDirn, $listOrder); ?> </th> <th scope="col" class="w-20"> <?php echo HTMLHelper::_('searchtools.sort', 'COM_WORKFLOW_TO_STAGE', 'to_stage', $listDirn, $listOrder); ?> </th> <th scope="col" class="w-3 d-none d-md-table-cell"> <?php echo HTMLHelper::_('searchtools.sort', 'COM_WORKFLOW_ID', 't.id', $listDirn, $listOrder); ?> </th> </tr> </thead> <tbody class="js-draggable" data-url="<?php echo $saveOrderingUrl; ?>" data-direction="<?php echo strtolower($listDirn); ?>"> <?php foreach ($this->transitions as $i => $item) : $edit = Route::_('index.php?option=com_workflow&task=transition.edit&id=' . $item->id . '&workflow_id=' . (int) $this->workflowID . '&extension=' . $this->escape($this->workflow->extension)); $canEdit = $user->authorise('core.edit', $this->extension . '.transition.' . $item->id); $canCheckin = $user->authorise('core.admin', 'com_workflow') || $item->checked_out == $user->id || is_null($item->checked_out); $canChange = $user->authorise('core.edit.state', $this->extension . '.transition.' . $item->id) && $canCheckin; ?> <tr class="row<?php echo $i % 2; ?>"> <td class="text-center d-none d-md-table-cell"> <?php echo HTMLHelper::_('grid.id', $i, $item->id, false, 'cid', 'cb', Text::_($item->title)); ?> </td> <td class="text-center d-none d-md-table-cell"> <?php $iconClass = ''; if (!$canChange) { $iconClass = ' inactive'; } elseif (!$saveOrder) { $iconClass = ' inactive" title="' . Text::_('JORDERINGDISABLED'); } ?> <span class="sortable-handler<?php echo $iconClass ?>"> <span class="icon-ellipsis-v" aria-hidden="true"></span> </span> <?php if ($canChange && $saveOrder) : ?> <input type="text" name="order[]" size="5" value="<?php echo $item->ordering; ?>" class="width-20 text-area-order hidden"> <?php endif; ?> </td> <td class="text-center"> <?php echo HTMLHelper::_('jgrid.published', $item->published, $i, 'transitions.', $canChange); ?> </td> <th scope="row"> <?php if ($item->checked_out) : ?> <?php echo HTMLHelper::_('jgrid.checkedout', $i, $item->editor, $item->checked_out_time, 'transitions.', $canCheckin); ?> <?php endif; ?> <?php if ($canEdit) : ?> <a href="<?php echo $edit; ?>" title="<?php echo Text::_('JACTION_EDIT'); ?> <?php echo $this->escape(Text::_($item->title)); ?>"> <?php echo $this->escape(Text::_($item->title)); ?> </a> <div class="small"><?php echo $this->escape(Text::_($item->description)); ?></div> <?php else : ?> <?php echo $this->escape(Text::_($item->title)); ?> <div class="small"><?php echo $this->escape(Text::_($item->description)); ?></div> <?php endif; ?> </th> <td class="nowrap"> <?php if ($item->from_stage_id < 0) : ?> <?php echo Text::_('JALL'); ?> <?php else : ?> <?php echo ' ' . $this->escape(Text::_($item->from_stage)); ?> <?php endif; ?> </td> <td class="nowrap"> <?php echo ' ' . $this->escape(Text::_($item->to_stage)); ?> </td> <td class="d-none d-md-table-cell"> <?php echo (int) $item->id; ?> </td> </tr> <?php endforeach ?> </tbody> </table> <?php // load the pagination. ?> <?php echo $this->pagination->getListFooter(); ?> <?php endif; ?> <input type="hidden" name="task" value=""> <input type="hidden" name="boxchecked" value="0"> <input type="hidden" name="workflow_id" value="<?php echo (int) $this->workflowID ?>"> <input type="hidden" name="extension" value="<?php echo $this->escape($this->workflow->extension); ?>"> <?php echo HTMLHelper::_('form.token'); ?> </div> </div> </div> </form> tmpl/transition/edit.php 0000644 00000005755 15172633314 0011371 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ defined('_JEXEC') or die; use Joomla\CMS\Factory; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('keepalive') ->useScript('form.validate'); $app = Factory::getApplication(); $user = $app->getIdentity(); $this->ignore_fieldsets = ['params', 'transition', 'permissions']; $this->useCoreUI = true; // In case of modal $isModal = $this->input->get('layout') === 'modal'; $layout = $isModal ? 'modal' : 'edit'; $tmpl = $isModal || $this->input->get('tmpl', '', 'cmd') === 'component' ? '&tmpl=component' : ''; ?> <form action="<?php echo Route::_('index.php?option=com_workflow&view=transition&workflow_id=' . $this->workflowID . '&extension=' . $this->input->getCmd('extension') . '&layout=' . $layout . $tmpl . '&id=' . (int) $this->item->id); ?>" method="post" name="adminForm" id="workflow-form" aria-label="<?php echo Text::_('COM_WORKFLOW_TRANSITION_FORM_' . ((int) $this->item->id === 0 ? 'NEW' : 'EDIT'), true); ?>" class="form-validate"> <?php echo LayoutHelper::render('joomla.edit.title_alias', $this); ?> <div class="main-card"> <?php echo HTMLHelper::_('uitab.startTabSet', 'myTab', ['active' => 'details', 'recall' => true, 'breakpoint' => 768]); ?> <?php echo HTMLHelper::_('uitab.addTab', 'myTab', 'details', Text::_('COM_WORKFLOW_TRANSITION')); ?> <div class="row"> <div class="col-lg-9"> <?php echo $this->form->renderField('from_stage_id'); ?> <?php echo $this->form->renderField('to_stage_id'); ?> <?php echo $this->form->renderField('description'); ?> </div> <div class="col-lg-3"> <?php echo LayoutHelper::render('joomla.edit.global', $this); ?> </div> </div> <?php echo HTMLHelper::_('uitab.endTab'); ?> <?php echo LayoutHelper::render('joomla.edit.params', $this); ?> <?php if ($user->authorise('core.admin', $this->extension)) : ?> <?php echo HTMLHelper::_('uitab.addTab', 'myTab', 'permissions', Text::_('COM_WORKFLOW_RULES_TAB')); ?> <fieldset id="fieldset-rules" class="options-form"> <legend><?php echo Text::_('COM_WORKFLOW_RULES_TAB'); ?></legend> <?php echo $this->form->getInput('rules'); ?> </fieldset> <?php echo HTMLHelper::_('uitab.endTab'); ?> <?php endif; ?> <?php echo HTMLHelper::_('uitab.endTabSet'); ?> </div> <?php echo $this->form->getInput('workflow_id'); ?> <input type="hidden" name="task" value="transition.edit" /> <?php echo HTMLHelper::_('form.token'); ?> </form> tmpl/workflows/default.php 0000644 00000027063 15172633314 0011727 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt * @since 4.0.0 */ defined('_JEXEC') or die; use Joomla\CMS\Factory; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; use Joomla\CMS\Session\Session; /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('table.columns') ->useScript('multiselect'); $listOrder = $this->escape($this->state->get('list.ordering')); $listDirn = $this->escape($this->state->get('list.direction')); $saveOrder = $listOrder == 'w.ordering'; $orderingColumn = 'created'; $saveOrderingUrl = ''; if (strpos($listOrder, 'modified') !== false) { $orderingColumn = 'modified'; } if ($saveOrder) { $saveOrderingUrl = 'index.php?option=com_workflow&task=workflows.saveOrderAjax&tmpl=component&extension=' . $this->escape($this->extension) . '&' . Session::getFormToken() . '=1'; HTMLHelper::_('draggablelist.draggable'); } $extension = $this->escape($this->state->get('filter.extension')); $user = Factory::getUser(); $userId = $user->id; ?> <form action="<?php echo Route::_('index.php?option=com_workflow&view=workflows&extension=' . $extension); ?>" method="post" name="adminForm" id="adminForm"> <div class="row"> <?php if (!empty($this->sidebar)) : ?> <div id="j-sidebar-container" class="col-md-2"> <?php echo $this->sidebar; ?> </div> <?php endif; ?> <div class="<?php if (!empty($this->sidebar)) { echo 'col-md-10'; } else { echo 'col-md-12'; } ?>"> <div id="j-main-container" class="j-main-container"> <?php // Search tools bar echo LayoutHelper::render('joomla.searchtools.default', ['view' => $this, 'options' => ['selectorFieldName' => 'extension']]); ?> <?php if (empty($this->workflows)) : ?> <div class="alert alert-info"> <span class="icon-info-circle" aria-hidden="true"></span><span class="visually-hidden"><?php echo Text::_('INFO'); ?></span> <?php echo Text::_('JGLOBAL_NO_MATCHING_RESULTS'); ?> </div> <?php else : ?> <table class="table"> <caption class="visually-hidden"> <?php echo Text::_('COM_WORKFLOW_WORKFLOWS_TABLE_CAPTION'); ?>, <span id="orderedBy"><?php echo Text::_('JGLOBAL_SORTED_BY'); ?> </span>, <span id="filteredBy"><?php echo Text::_('JGLOBAL_FILTERED_BY'); ?></span> </caption> <thead> <tr> <td class="w-1 text-center d-none d-md-table-cell"> <?php echo HTMLHelper::_('grid.checkall'); ?> </td> <th scope="col" class="w-1 text-center d-none d-md-table-cell"> <?php echo HTMLHelper::_('searchtools.sort', '', 'w.ordering', $listDirn, $listOrder, null, 'asc', 'JGRID_HEADING_ORDERING', 'icon-sort'); ?> </th> <th scope="col" class="w-1 text-center"> <?php echo HTMLHelper::_('searchtools.sort', 'JSTATUS', 'w.published', $listDirn, $listOrder); ?> </th> <th scope="col"> <?php echo HTMLHelper::_('searchtools.sort', 'COM_WORKFLOW_NAME', 'w.title', $listDirn, $listOrder); ?> </th> <th scope="col" class="w-10 text-center d-none d-md-table-cell"> <?php echo Text::_('COM_WORKFLOW_DEFAULT'); ?> </th> <th scope="col" class="w-10 text-center d-none d-md-table-cell"> <?php echo Text::_('COM_WORKFLOW_COUNT_STAGES'); ?> </th> <th scope="col" class="w-10 text-center d-none d-md-table-cell"> <?php echo Text::_('COM_WORKFLOW_COUNT_TRANSITIONS'); ?> </th> <th scope="col" class="w-10 d-none d-md-table-cell"> <?php echo HTMLHelper::_('searchtools.sort', 'COM_WORKFLOW_ID', 'w.id', $listDirn, $listOrder); ?> </th> </tr> </thead> <tbody <?php if ($saveOrder) : ?> class="js-draggable" data-url="<?php echo $saveOrderingUrl; ?>" data-direction="<?php echo strtolower($listDirn); ?>" data-nested="false"<?php endif; ?>> <?php foreach ($this->workflows as $i => $item) : $states = Route::_('index.php?option=com_workflow&view=stages&workflow_id=' . $item->id . '&extension=' . $extension); $transitions = Route::_('index.php?option=com_workflow&view=transitions&workflow_id=' . $item->id . '&extension=' . $extension); $edit = Route::_('index.php?option=com_workflow&task=workflow.edit&id=' . $item->id . '&extension=' . $extension); $canEdit = $user->authorise('core.edit', $extension . '.workflow.' . $item->id); $canCheckin = $user->authorise('core.admin', 'com_workflow') || $item->checked_out == $userId || is_null($item->checked_out); $canEditOwn = $user->authorise('core.edit.own', $extension . '.workflow.' . $item->id) && $item->created_by == $userId; $canChange = $user->authorise('core.edit.state', $extension . '.workflow.' . $item->id) && $canCheckin; ?> <tr class="row<?php echo $i % 2; ?>" data-draggable-group="0"> <td class="text-center d-none d-md-table-cell"> <?php echo HTMLHelper::_('grid.id', $i, $item->id, false, 'cid', 'cb', Text::_($item->title)); ?> </td> <td class="text-center d-none d-md-table-cell"> <?php $iconClass = ''; if (!$canChange) { $iconClass = ' inactive'; } elseif (!$saveOrder) { $iconClass = ' inactive" title="' . Text::_('JORDERINGDISABLED'); } ?> <span class="sortable-handler<?php echo $iconClass ?>"> <span class="icon-ellipsis-v" aria-hidden="true"></span> </span> <?php if ($canChange && $saveOrder) : ?> <input type="text" name="order[]" size="5" value="<?php echo $item->ordering; ?>" class="width-20 text-area-order hidden"> <?php endif; ?> </td> <td class="text-center"> <?php echo HTMLHelper::_('jgrid.published', $item->published, $i, 'workflows.', $canChange); ?> </td> <th scope="row"> <?php if ($item->checked_out) : ?> <?php echo HTMLHelper::_('jgrid.checkedout', $i, $item->editor, $item->checked_out_time, 'workflows.', $canCheckin); ?> <?php endif; ?> <?php if ($canEdit || $canEditOwn) : ?> <a href="<?php echo $edit; ?>" title="<?php echo Text::_('JACTION_EDIT', true); ?> <?php echo Text::_($item->title, true); ?>"> <?php echo $this->escape(Text::_($item->title)); ?> </a> <div class="small"><?php echo $item->description; ?></div> <?php else : ?> <?php echo $this->escape(Text::_($item->title)); ?> <div class="small"><?php echo $item->description; ?></div> <?php endif; ?> </th> <td class="text-center d-none d-md-table-cell"> <?php echo HTMLHelper::_('jgrid.isdefault', $item->default, $i, 'workflows.', $canChange); ?> </td> <td class="text-center btns d-none d-md-table-cell itemnumber"> <a class="btn <?php echo ($item->count_states > 0) ? 'btn-warning' : 'btn-secondary'; ?>" href="<?php echo Route::_('index.php?option=com_workflow&view=stages&workflow_id=' . (int) $item->id . '&extension=' . $extension); ?>" aria-describedby="tip-stages<?php echo $i; ?>"> <?php echo $item->count_states; ?> </a> <div role="tooltip" id="tip-stages<?php echo $i; ?>"> <?php echo Text::_('COM_WORKFLOW_COUNT_STAGES'); ?> </div> </td> <td class="text-center btns d-none d-md-table-cell itemnumber"> <a class="btn <?php echo ($item->count_transitions > 0) ? 'btn-info' : 'btn-secondary'; ?>" href="<?php echo Route::_('index.php?option=com_workflow&view=transitions&workflow_id=' . (int) $item->id . '&extension=' . $extension); ?>" aria-describedby="tip-transitions<?php echo $i; ?>"> <?php echo $item->count_transitions; ?> </a> <div role="tooltip" id="tip-transitions<?php echo $i; ?>"> <?php echo Text::_('COM_WORKFLOW_COUNT_TRANSITIONS'); ?> </div> </td> <td class="d-none d-md-table-cell"> <?php echo $item->id; ?> </td> </tr> <?php endforeach ?> </table> <?php // load the pagination. ?> <?php echo $this->pagination->getListFooter(); ?> <?php endif; ?> <input type="hidden" name="task" value=""> <input type="hidden" name="boxchecked" value="0"> <?php echo HTMLHelper::_('form.token'); ?> </div> </div> </div> </form> tmpl/workflows/default.xml 0000644 00000001066 15172633314 0011733 0 ustar 00 <?xml version="1.0" encoding="UTF-8"?> <metadata> <layout title="COM_WORKFLOW_WORKFLOWS_VIEW_DEFAULT_TITLE"> <message> <![CDATA[COM_WORKFLOW_WORKFLOWS_VIEW_DEFAULT_DESC]]> </message> </layout> <fieldset name="request"> <fields name="request"> <field name="extension" type="ComponentsWorkflow" label="COM_WORKFLOW_CHOOSE_CONTEXT_LABEL" required="true" addfieldprefix="Joomla\Component\Workflow\Administrator\Field" > <option value="">COM_MENUS_OPTION_SELECT_CONTEXT</option> </field> </fields> </fieldset> </metadata> tmpl/workflow/edit.php 0000644 00000007366 15172633314 0011051 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ defined('_JEXEC') or die; use Joomla\CMS\Factory; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('keepalive') ->useScript('form.validate'); $app = Factory::getApplication(); $user = $app->getIdentity(); $input = $app->getInput(); // In case of modal $isModal = $input->get('layout') === 'modal'; $layout = $isModal ? 'modal' : 'edit'; $tmpl = $isModal || $input->get('tmpl', '', 'cmd') === 'component' ? '&tmpl=component' : ''; $clientId = $this->state->get('item.client_id', 0); $lang = $this->getLanguage()->getTag(); ?> <form action="<?php echo Route::_('index.php?option=com_workflow&view=workflow&extension=' . $input->getCmd('extension') . '&layout=' . $layout . $tmpl . '&id=' . (int) $this->item->id); ?>" method="post" name="adminForm" id="workflow-form" aria-label="<?php echo Text::_('COM_WORKFLOW_FORM_' . ((int) $this->item->id === 0 ? 'NEW' : 'EDIT'), true); ?>" class="form-validate"> <?php echo LayoutHelper::render('joomla.edit.title_alias', $this); ?> <?php // Add the translation of the workflow item title when client is administrator ?> <?php if ($clientId === 0 && $this->item->id != 0) : ?> <div class="row title-alias form-vertical mb-3"> <div class="col-md-6"> <div class="control-group"> <div class="control-label"> <label for="workflow_title_translation"><?php echo Text::sprintf('COM_WORKFLOW_TITLE_TRANSLATION', $lang); ?></label> </div> <div class="controls"> <input id="workflow_title_translation" class="form-control" value="<?php echo Text::_($this->item->title); ?>" readonly="readonly" type="text"> </div> </div> </div> </div> <?php endif; ?> <div class="main-card"> <?php echo HTMLHelper::_('uitab.startTabSet', 'myTab', ['active' => 'general', 'recall' => true, 'breakpoint' => 768]); ?> <?php echo HTMLHelper::_('uitab.addTab', 'myTab', 'description', Text::_('COM_WORKFLOW_DESCRIPTION'));?> <div class="row"> <div class="col-lg-9"> <div class="form-vertical"> <?php echo $this->form->renderField('description'); ?> </div> </div> <div class="col-lg-3"> <fieldset class="form-vertical"> <?php echo $this->form->renderField('published'); ?> <?php echo $this->form->renderField('default'); ?> </fieldset> </div> </div> <?php echo HTMLHelper::_('uitab.endTab'); ?> <?php if ($user->authorise('core.admin', $this->extension)) : ?> <?php echo HTMLHelper::_('uitab.addTab', 'myTab', 'permissions', Text::_('COM_WORKFLOW_RULES_TAB')); ?> <fieldset id="fieldset-rules" class="options-form"> <legend><?php echo Text::_('COM_WORKFLOW_RULES_TAB'); ?></legend> <?php echo $this->form->getInput('rules'); ?> </fieldset> <?php echo HTMLHelper::_('uitab.endTab'); ?> <?php endif; ?> <?php echo HTMLHelper::_('uitab.endTabSet'); ?> </div> <?php echo $this->form->getInput('extension'); ?> <input type="hidden" name="task" value="workflow.edit" /> <?php echo HTMLHelper::_('form.token'); ?> </form> tmpl/stage/edit.php 0000644 00000007350 15172633314 0010273 0 ustar 00 <?php /** * @package Joomla.Administrator * @subpackage com_workflow * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ defined('_JEXEC') or die; use Joomla\CMS\Factory; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; /** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); $wa->useScript('keepalive') ->useScript('form.validate'); $app = Factory::getApplication(); $user = $app->getIdentity(); $input = $app->getInput(); // In case of modal $isModal = $input->get('layout') === 'modal'; $layout = $isModal ? 'modal' : 'edit'; $tmpl = $isModal || $input->get('tmpl', '', 'cmd') === 'component' ? '&tmpl=component' : ''; $clientId = $this->state->get('item.client_id', 0); $lang = $this->getLanguage()->getTag(); ?> <form action="<?php echo Route::_('index.php?option=com_workflow&view=stage&workflow_id=' . $input->getCmd('workflow_id') . '&extension=' . $input->getCmd('extension') . '&layout=' . $layout . $tmpl . '&id=' . (int) $this->item->id); ?>" method="post" name="adminForm" id="workflow-form" aria-label="<?php echo Text::_('COM_WORKFLOW_STAGE_FORM_' . ((int) $this->item->id === 0 ? 'NEW' : 'EDIT'), true); ?>" class="form-validate"> <?php echo LayoutHelper::render('joomla.edit.title_alias', $this); ?> <?php // Add the translation of the workflow item title when client is administrator ?> <?php if ($clientId === 0 && $this->item->id != 0) : ?> <div class="row title-alias form-vertical mb-3"> <div class="col-12"> <div class="control-group"> <div class="control-label"> <label for="stage_title_translation"><?php echo Text::sprintf('COM_WORKFLOW_TITLE_TRANSLATION', $lang); ?></label> </div> <div class="controls"> <input id="stage_title_translation" class="form-control" value="<?php echo Text::_($this->item->title); ?>" readonly="readonly" type="text"> </div> </div> </div> </div> <?php endif; ?> <div class="main-card"> <?php echo HTMLHelper::_('uitab.startTabSet', 'myTab', ['active' => 'details', 'recall' => true, 'breakpoint' => 768]); ?> <?php echo HTMLHelper::_('uitab.addTab', 'myTab', 'details', Text::_('COM_WORKFLOW_DESCRIPTION')); ?> <div class="row"> <div class="col-lg-9"> <?php echo $this->form->renderField('description'); ?> </div> <div class="col-lg-3"> <fieldset class="form-vertical"> <?php echo $this->form->renderField('published'); ?> <?php echo $this->form->renderField('default'); ?> </fieldset> </div> </div> <?php echo HTMLHelper::_('uitab.endTab'); ?> <?php if ($user->authorise('core.admin', $this->extension)) : ?> <?php echo HTMLHelper::_('uitab.addTab', 'myTab', 'permissions', Text::_('COM_WORKFLOW_RULES_TAB')); ?> <fieldset id="fieldset-rules" class="options-form"> <legend><?php echo Text::_('COM_WORKFLOW_RULES_TAB'); ?></legend> <?php echo $this->form->getInput('rules'); ?> </fieldset> <?php echo HTMLHelper::_('uitab.endTab'); ?> <?php endif; ?> <?php echo HTMLHelper::_('uitab.endTabSet'); ?> <?php echo $this->form->getInput('workflow_id'); ?> <input type="hidden" name="task" value="stage.edit" /> <?php echo HTMLHelper::_('form.token'); ?> </div> </form>
| ver. 1.4 |
Github
|
.
| PHP 8.3.23 | Generation time: 0 |
proxy
|
phpinfo
|
Settings