From 62e1c9471a7c2e24238e79e3a92b85c7d97416ae Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Thu, 22 Jul 2021 23:51:36 +0530 Subject: [PATCH 01/85] filter workflow associations --- administrator/components/com_content/src/Model/ArticlesModel.php | 1 + 1 file changed, 1 insertion(+) diff --git a/administrator/components/com_content/src/Model/ArticlesModel.php b/administrator/components/com_content/src/Model/ArticlesModel.php index 8c9f46e058746..fa2ecf16cc5b9 100644 --- a/administrator/components/com_content/src/Model/ArticlesModel.php +++ b/administrator/components/com_content/src/Model/ArticlesModel.php @@ -302,6 +302,7 @@ protected function getListQuery() ->join('LEFT', $db->quoteName('#__categories', 'parent'), $db->quoteName('parent.id') . ' = ' . $db->quoteName('c.parent_id')) ->join('LEFT', $db->quoteName('#__users', 'ua'), $db->quoteName('ua.id') . ' = ' . $db->quoteName('a.created_by')) ->join('INNER', $db->quoteName('#__workflow_associations', 'wa'), $db->quoteName('wa.item_id') . ' = ' . $db->quoteName('a.id')) + ->where($db->quoteName('wa.extension') . ' = "com_content.article"') ->join('INNER', $db->quoteName('#__workflow_stages', 'ws'), $db->quoteName('ws.id') . ' = ' . $db->quoteName('wa.stage_id')) ->join('INNER', $db->quoteName('#__workflows', 'w'), $db->quoteName('w.id') . ' = ' . $db->quoteName('ws.workflow_id')); From 95de9b42ccab35b86f5e3531d421e05d071ba65b Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Thu, 22 Jul 2021 23:52:04 +0530 Subject: [PATCH 02/85] add module workflow menu tab --- administrator/components/com_menus/presets/default.xml | 8 ++++++++ administrator/components/com_menus/presets/system.xml | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/administrator/components/com_menus/presets/default.xml b/administrator/components/com_menus/presets/default.xml index 7e8252caf344a..096d5d54a8f6b 100644 --- a/administrator/components/com_menus/presets/default.xml +++ b/administrator/components/com_menus/presets/default.xml @@ -99,6 +99,14 @@ link="index.php?option=com_modules&view=modules&client_id=1" quicktask="index.php?option=com_modules&view=select&client_id=1" /> + + + + Date: Thu, 22 Jul 2021 23:52:20 +0530 Subject: [PATCH 03/85] language constants --- administrator/language/en-GB/com_modules.ini | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/administrator/language/en-GB/com_modules.ini b/administrator/language/en-GB/com_modules.ini index 0a901fa883d66..12767b650dfd2 100644 --- a/administrator/language/en-GB/com_modules.ini +++ b/administrator/language/en-GB/com_modules.ini @@ -21,6 +21,7 @@ COM_MODULES_BATCH_TIP="If choosing to copy a module, any other actions selected COM_MODULES_CHANGE_POSITION_BUTTON="Select" COM_MODULES_CHANGE_POSITION_TITLE="Change" COM_MODULES_COLLAPSE="Collapse" +COM_MODULES_CONFIG_INTEGRATION_SETTINGS_DESC="These settings determine how the Modules Component will integrate with other extensions." COM_MODULES_CONFIGURATION="Module: Options" COM_MODULES_CUSTOM_OUTPUT="Custom Output" COM_MODULES_CUSTOM_POSITION="Active Positions" @@ -87,6 +88,7 @@ COM_MODULES_MENU_ITEM_ALIAS="Alias" COM_MODULES_MENU_ITEM_HEADING="Heading" COM_MODULES_MENU_ITEM_SEPARATOR="Separator" COM_MODULES_MENU_ITEM_URL="URL" +COM_MODULES_MENU_WORKFLOW="Modules Workflows" COM_MODULES_MODULE="Module" COM_MODULES_MODULE_ASSIGN="Module Assignment" COM_MODULES_MODULE_DESCRIPTION="Module Description" @@ -190,6 +192,10 @@ COM_MODULES_SUBITEMS="Sub-items" COM_MODULES_TABLE_CAPTION="Table of Modules" COM_MODULES_TYPE_CHOOSE="Select a Module Type" COM_MODULES_TYPE_OR_SELECT_POSITION="Type or Select a Position" +COM_MODULES_WORKFLOW="Workflow" +COM_MODULES_WORKFLOW_NOT_FOUND="No default workflow available, please define one or contact an administrator." +COM_MODULES_WORKFLOW_TRANSITION_NOT_ALLOWED="You're not allowed to execute this transition" +COM_MODULES_WORKFLOWS="Workflows" COM_MODULES_XML_DESCRIPTION="Component for module management in the Administrator Backend." JLIB_RULES_SETTING_NOTES_COM_MODULES="Changes apply to this component only.
Inherited - a Global Configuration setting or higher level setting is applied.
Denied always wins - whatever is set at the Global or higher level and applies to all child elements.
Allowed will enable the action for this component unless overruled by a Global Configuration setting." ; Alternate language strings for the rules form field From d1a77f7d63f0a66dffed99cc368a39ab579d5de3 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Thu, 22 Jul 2021 23:52:47 +0530 Subject: [PATCH 04/85] modules access perms xml --- .../components/com_modules/access.xml | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/administrator/components/com_modules/access.xml b/administrator/components/com_modules/access.xml index f8bfed5ca8347..9797341f9470f 100644 --- a/administrator/components/com_modules/access.xml +++ b/administrator/components/com_modules/access.xml @@ -7,6 +7,8 @@ + +
@@ -15,4 +17,23 @@
+
+ + + + + + +
+
+ + + + +
+
+ + + +
\ No newline at end of file From 8f63595670c0e80ec7527ea8519510d080e76557 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Thu, 22 Jul 2021 23:53:06 +0530 Subject: [PATCH 05/85] show integrations tag in options --- .../components/com_modules/config.xml | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/administrator/components/com_modules/config.xml b/administrator/components/com_modules/config.xml index d89b170d99c6c..3344d7f60a12d 100644 --- a/administrator/components/com_modules/config.xml +++ b/administrator/components/com_modules/config.xml @@ -53,4 +53,26 @@ section="component" /> + +
+
+ + + + +
+
From f5eeb557a118956797c43d50d26842850f62bc27 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Thu, 22 Jul 2021 23:53:49 +0530 Subject: [PATCH 06/85] filter by stage --- .../components/com_modules/forms/filter_modules.xml | 10 ++++++++++ .../com_modules/forms/filter_modulesadmin.xml | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/administrator/components/com_modules/forms/filter_modules.xml b/administrator/components/com_modules/forms/filter_modules.xml index 6adc9ec4377f8..e60a68da459c9 100644 --- a/administrator/components/com_modules/forms/filter_modules.xml +++ b/administrator/components/com_modules/forms/filter_modules.xml @@ -58,6 +58,16 @@ + + + + + + Date: Thu, 22 Jul 2021 23:54:18 +0530 Subject: [PATCH 07/85] show workflows field in a new tab in com_modules --- .../components/com_modules/forms/module.xml | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/administrator/components/com_modules/forms/module.xml b/administrator/components/com_modules/forms/module.xml index ca92bd2c76782..5072371db8254 100644 --- a/administrator/components/com_modules/forms/module.xml +++ b/administrator/components/com_modules/forms/module.xml @@ -148,4 +148,25 @@ validate="rules" /> + + +
+ +
+
From 11fa022e5eda6b63d807cc44b55ef33a82b60a37 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Thu, 22 Jul 2021 23:55:01 +0530 Subject: [PATCH 08/85] functions used by workflow plugins --- .../src/Extension/ModulesComponent.php | 56 ++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/administrator/components/com_modules/src/Extension/ModulesComponent.php b/administrator/components/com_modules/src/Extension/ModulesComponent.php index 167c8b8ff60fd..5941a144180df 100644 --- a/administrator/components/com_modules/src/Extension/ModulesComponent.php +++ b/administrator/components/com_modules/src/Extension/ModulesComponent.php @@ -11,9 +11,13 @@ \defined('JPATH_PLATFORM') or die; +use Joomla\CMS\Factory; use Joomla\CMS\Extension\BootableExtensionInterface; use Joomla\CMS\Extension\MVCComponent; use Joomla\CMS\HTML\HTMLRegistryAwareTrait; +use Joomla\CMS\Language\Text; +use Joomla\CMS\Workflow\WorkflowServiceInterface; +use Joomla\CMS\Workflow\WorkflowServiceTrait; use Joomla\Component\Modules\Administrator\Service\HTML\Modules; use Psr\Container\ContainerInterface; @@ -22,9 +26,11 @@ * * @since 4.0.0 */ -class ModulesComponent extends MVCComponent implements BootableExtensionInterface +class ModulesComponent extends MVCComponent implements BootableExtensionInterface, +WorkflowServiceInterface { use HTMLRegistryAwareTrait; + use WorkflowServiceTrait; /** * Booting the extension. This is the function to set up the environment of the extension like @@ -43,4 +49,52 @@ public function boot(ContainerInterface $container) { $this->getRegistry()->register('modules', new Modules); } + + /** + * Returns valid contexts + * + * @return array + * + * @since __DEPLOY_VERSION__ + */ + public function getWorkflowContexts(): array + { + Factory::getLanguage()->load('com_modules', JPATH_ADMINISTRATOR); + + $contexts = array( + 'com_modules.module' => Text::_('COM_MODULES') + ); + + return $contexts; + } + + /** + * Returns a table name for the state association + * + * @param string $section An optional section to separate different areas in the component + * + * @return string + * + * @since __DEPLOY_VERSION__ + */ + public function getWorkflowTableBySection(?string $section = null): string + { + return '#__modules'; + } + + /** + * Method to filter transitions by given id of state. + * + * @param array $transitions The Transitions to filter + * @param int $pk Id of the state + * + * @return array + * + * @since __DEPLOY_VERSION__ + */ + public function filterTransitions(array $transitions, int $pk): array + { + return ModuleHelper::filterTransitions($transitions, $pk); + } + } From b96214f24e96db58672bf4aa29438561afb56ade Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Thu, 22 Jul 2021 23:58:57 +0530 Subject: [PATCH 09/85] workflows in modules helper --- .../com_modules/src/Helper/ModulesHelper.php | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/administrator/components/com_modules/src/Helper/ModulesHelper.php b/administrator/components/com_modules/src/Helper/ModulesHelper.php index 6657d2f1b988a..ab6a6fc60aaa9 100644 --- a/administrator/components/com_modules/src/Helper/ModulesHelper.php +++ b/administrator/components/com_modules/src/Helper/ModulesHelper.php @@ -323,4 +323,131 @@ public static function createOptionGroup($label = '', $options = array()) return $group; } + + /** + * Method to filter transitions by given id of state + * + * @param array $transitions Array of transitions + * @param int $pk Id of state + * @param int $workflowId Id of the workflow + * + * @return array + * + * @since __DEPLOY_VERSION__ + */ + public static function filterTransitions(array $transitions, int $pk, int $workflowId = 0): array + { + return array_values( + array_filter( + $transitions, + function ($var) use ($pk, $workflowId) + { + return in_array($var['from_stage_id'], [-1, $pk]) && $workflowId == $var['workflow_id']; + } + ) + ); + } + + /** + * Prepares a form + * + * @param Form $form The form to change + * @param array|object $data The form data + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public static function onPrepareForm(Form $form, $data) + { + $db = Factory::getDbo(); + + $data = (array) $data; + + // Make workflows translatable + Factory::getLanguage()->load('com_workflow', JPATH_ADMINISTRATOR); + + $form->setFieldAttribute('workflow_id', 'default', 'inherit'); + + $query = $db->getQuery(true); + + $query->select($db->quoteName('title')) + ->from($db->quoteName('#__workflows')) + ->where( + [ + $db->quoteName('default') . ' = 1', + $db->quoteName('published') . ' = 1', + ] + ); + + $defaulttitle = $db->setQuery($query)->loadResult(); + + $option = Text::_('COM_WORKFLOW_INHERIT_WORKFLOW_NEW'); + + if (!empty($data['id'])) + { + $category = new Category($db); + + $categories = $category->getPath((int) $data['id']); + + // Remove the current category, because we search for inheritance from parent. + array_pop($categories); + + $option = Text::sprintf('COM_WORKFLOW_INHERIT_WORKFLOW', Text::_($defaulttitle)); + + if (!empty($categories)) + { + $categories = array_reverse($categories); + + $query = $db->getQuery(true); + + $query->select($db->quoteName('title')) + ->from($db->quoteName('#__workflows')) + ->where( + [ + $db->quoteName('id') . ' = :workflowId', + $db->quoteName('published') . ' = 1', + ] + ) + ->bind(':workflowId', $workflow_id, ParameterType::INTEGER); + + $db->setQuery($query); + + foreach ($categories as $cat) + { + $cat->params = new Registry($cat->params); + + $workflow_id = $cat->params->get('workflow_id'); + + if ($workflow_id == 'inherit') + { + continue; + } + elseif ($workflow_id == 'use_default') + { + break; + } + elseif ($workflow_id = (int) $workflow_id) + { + $title = $db->loadResult(); + + if (!is_null($title)) + { + $option = Text::sprintf('COM_WORKFLOW_INHERIT_WORKFLOW', Text::_($title)); + + break; + } + } + } + } + } + + $field = $form->getField('workflow_id', 'params'); + + $field->addOption($option, ['value' => 'inherit']); + + $field->addOption(Text::sprintf('COM_WORKFLOW_USE_DEFAULT_WORKFLOW', Text::_($defaulttitle)), ['value' => 'use_default']); + + $field->addOption('- ' . Text::_('COM_MODULE_WORKFLOWS') . ' -', ['disabled' => 'true']); + } } From 84fb8a1b67edeb7f8e0bfd17ab58eb6fe939f258 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Fri, 23 Jul 2021 00:00:20 +0530 Subject: [PATCH 10/85] call workflow events on save and delete --- .../com_modules/src/Model/ModuleModel.php | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/administrator/components/com_modules/src/Model/ModuleModel.php b/administrator/components/com_modules/src/Model/ModuleModel.php index 59e677842b14e..e6ffc50cb507b 100644 --- a/administrator/components/com_modules/src/Model/ModuleModel.php +++ b/administrator/components/com_modules/src/Model/ModuleModel.php @@ -20,11 +20,14 @@ use Joomla\CMS\Helper\ModuleHelper; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\Model\AdminModel; +use Joomla\CMS\MVC\Model\WorkflowBehaviorTrait; +use Joomla\CMS\MVC\Model\WorkflowModelInterface; use Joomla\CMS\Object\CMSObject; use Joomla\CMS\Plugin\PluginHelper; use Joomla\CMS\Router\Route; use Joomla\CMS\Table\Table; use Joomla\Component\Modules\Administrator\Helper\ModulesHelper; +use Joomla\CMS\Workflow\Workflow; use Joomla\Database\ParameterType; use Joomla\Registry\Registry; use Joomla\String\StringHelper; @@ -35,8 +38,10 @@ * * @since 1.6 */ -class ModuleModel extends AdminModel +class ModuleModel extends AdminModel implements WorkflowModelInterface { + use WorkflowBehaviorTrait; + /** * The type alias for this content type. * @@ -102,6 +107,8 @@ public function __construct($config = array()) ); parent::__construct($config); + + $this->setUpWorkflow('com_modules.module'); } /** @@ -391,6 +398,8 @@ public function delete(&$pks) // Clear module cache parent::cleanCache($table->module); + + $this->workflow->deleteAssociation($pks); } else { @@ -842,6 +851,17 @@ public function getTable($type = 'Module', $prefix = 'JTable', $config = array() */ protected function prepareTable($table) { + // Set the publish date to now + if ($table->state == Workflow::CONDITION_PUBLISHED && (int) $table->publish_up == 0) + { + $table->publish_up = Factory::getDate()->toSql(); + } + + if ($table->state == Workflow::CONDITION_PUBLISHED && intval($table->publish_down) == 0) + { + $table->publish_down = null; + } + $table->title = htmlspecialchars_decode($table->title, ENT_QUOTES); $table->position = trim($table->position); } @@ -941,6 +961,7 @@ protected function preprocessForm(Form $form, $data, $group = 'content') } } } + $this->workflowPreprocessForm($form, $data); // Trigger the default form events. parent::preprocessForm($form, $data, $group); @@ -1047,6 +1068,8 @@ public function save($data) return false; } + $this->workflowBeforeSave(); + // Process the menu link mappings. $assignment = $data['assignment'] ?? 0; @@ -1171,6 +1194,8 @@ public function save($data) // Clean module cache parent::cleanCache($table->module); + $this->workflowAfterSave($data); + return true; } @@ -1205,4 +1230,21 @@ protected function cleanCache($group = null, $clientId = 0) { parent::cleanCache('com_modules'); } + + /** + * 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 __DEPLOY_VERSION__ + */ + public function publish(&$pks, $value = 1) + { + $this->workflowBeforeStageChange(); + + return parent::publish($pks, $value); + } } From ee651eab36e12781985fe0392f6c2f7759085a64 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Fri, 23 Jul 2021 00:01:42 +0530 Subject: [PATCH 11/85] include workflows in modules query --- .../com_modules/src/Model/ModulesModel.php | 169 +++++++++++++++++- 1 file changed, 168 insertions(+), 1 deletion(-) diff --git a/administrator/components/com_modules/src/Model/ModulesModel.php b/administrator/components/com_modules/src/Model/ModulesModel.php index 6509d025f6bc7..a1930a775a532 100644 --- a/administrator/components/com_modules/src/Model/ModulesModel.php +++ b/administrator/components/com_modules/src/Model/ModulesModel.php @@ -229,6 +229,37 @@ protected function _getList($query, $limitstart = 0, $limit = 0) return $result; } + /** + * Get the filter form + * + * @param array $data data + * @param boolean $loadData load current data + * + * @return Form|null The \JForm object or null if the form can't be found + * + * @since __DEPLOY_VERSION__ + */ + public function getFilterForm($data = array(), $loadData = true) + { + $form = parent::getFilterForm($data, $loadData); + + $params = ComponentHelper::getParams('com_modules'); + + if (!$params->get('workflow_enabled')) + { + $form->removeField('stage', 'filter'); + } + else + { + $ordering = $form->getField('fullordering', 'list'); + + $ordering->addOption('JSTAGE_ASC', ['value' => 'ws.title ASC']); + $ordering->addOption('JSTAGE_DESC', ['value' => 'ws.title DESC']); + } + + return $form; + } + /** * Translate a list of objects * @@ -278,6 +309,7 @@ protected function getListQuery() // Create a new query object. $db = $this->getDbo(); $query = $db->getQuery(true); + $params = ComponentHelper::getParams('com_modules'); // Select the required fields. $query->select( @@ -312,6 +344,24 @@ protected function getListQuery() $query->select($db->quoteName('e.name', 'name')) ->join('LEFT', $db->quoteName('#__extensions', 'e') . ' ON ' . $db->quoteName('e.element') . ' = ' . $db->quoteName('a.module')); + // Join over the workflows association + $query->select($db->quoteName('wa.stage_id', 'stage_id')) + ->join('INNER', $db->quoteName('#__workflow_associations', 'wa'), $db->quoteName('wa.item_id') . ' = ' . $db->quoteName('a.id')) + ->where($db->quoteName('wa.extension') . ' = "com_modules.module"'); + + // Join over the workflows stage + $query->select( + [ + $db->quoteName('ws.title', 'stage_title'), + $db->quoteName('ws.workflow_id', 'workflow_id') + ] + ) + ->join('INNER', $db->quoteName('#__workflow_stages', 'ws'), $db->quoteName('ws.id') . ' = ' . $db->quoteName('wa.stage_id')); + + // Join over the workflows + $query->select($db->quoteName('w.title', 'workflow_title')) + ->join('INNER', $db->quoteName('#__workflows', 'w'), $db->quoteName('w.id') . ' = ' . $db->quoteName('ws.workflow_id')); + // Group (careful with PostgreSQL) $query->group( 'a.id, a.title, a.note, a.position, a.module, a.language, a.checked_out, ' @@ -344,6 +394,16 @@ protected function getListQuery() ->bind(':access', $access, ParameterType::INTEGER); } + // Filter by stage + $workflowStage = (string) $this->getState('filter.stage'); + + if ($params->get('workflow_enabled') && is_numeric($workflowStage)) + { + $workflowStage = (int) $workflowStage; + $query->where($db->quoteName('wa.stage_id') . ' = :stage') + ->bind(':stage', $workflowStage, ParameterType::INTEGER); + } + // Filter by published state. $state = $this->getState('filter.state'); @@ -353,7 +413,7 @@ protected function getListQuery() $query->where($db->quoteName('a.published') . ' = :state') ->bind(':state', $state, ParameterType::INTEGER); } - elseif ($state === '') + elseif (!is_numeric($workflowStage)) { $query->whereIn($db->quoteName('a.published'), [0, 1]); } @@ -461,6 +521,113 @@ protected function getListQuery() return $query; } + /** + * Method to get all transitions at once for all articles + * + * @return array|boolean + * + * @since __DEPLOY_VERSION__ + */ + public function getTransitions() + { + // Get a storage key. + $store = $this->getStoreId('getTransitions'); + + // Try to load the data from internal storage. + if (isset($this->cache[$store])) + { + return $this->cache[$store]; + } + + $db = $this->getDbo(); + $user = Factory::getUser(); + + $items = $this->getItems(); + + if ($items === false) + { + return false; + } + + $stage_ids = ArrayHelper::getColumn($items, 'stage_id'); + $stage_ids = ArrayHelper::toInteger($stage_ids); + $stage_ids = array_values(array_unique(array_filter($stage_ids))); + + $workflow_ids = ArrayHelper::getColumn($items, 'workflow_id'); + $workflow_ids = ArrayHelper::toInteger($workflow_ids); + $workflow_ids = array_values(array_unique(array_filter($workflow_ids))); + + $this->cache[$store] = array(); + + try + { + if (count($stage_ids) || count($workflow_ids)) + { + Factory::getLanguage()->load('com_workflow', JPATH_ADMINISTRATOR); + + $query = $db->getQuery(true); + + $query ->select( + [ + $db->quoteName('t.id', 'value'), + $db->quoteName('t.title', 'text'), + $db->quoteName('t.from_stage_id'), + $db->quoteName('t.to_stage_id'), + $db->quoteName('s.id', 'stage_id'), + $db->quoteName('s.title', 'stage_title'), + $db->quoteName('t.workflow_id'), + ] + ) + ->from($db->quoteName('#__workflow_transitions', 't')) + ->innerJoin( + $db->quoteName('#__workflow_stages', 's'), + $db->quoteName('t.to_stage_id') . ' = ' . $db->quoteName('s.id') + ) + ->where( + [ + $db->quoteName('t.published') . ' = 1', + $db->quoteName('s.published') . ' = 1', + ] + ) + ->order($db->quoteName('t.ordering')); + + $where = []; + + if (count($stage_ids)) + { + $where[] = $db->quoteName('t.from_stage_id') . ' IN (' . implode(',', $query->bindArray($stage_ids)) . ')'; + } + + if (count($workflow_ids)) + { + $where[] = '(' . $db->quoteName('t.from_stage_id') . ' = -1 AND ' . $db->quoteName('t.workflow_id') . ' IN (' . implode(',', $query->bindArray($workflow_ids)) . '))'; + } + + $query->where('((' . implode(') OR (', $where) . '))'); + + $transitions = $db->setQuery($query)->loadAssocList(); + + foreach ($transitions as $key => $transition) + { + if (!$user->authorise('core.execute.transition', 'com_modules.transition.' . (int) $transition['value'])) + { + unset($transitions[$key]); + } + } + + $this->cache[$store] = $transitions; + } + } + catch (\RuntimeException $e) + { + $this->setError($e->getMessage()); + + return false; + } + + return $this->cache[$store]; + } + /** * Manipulate the query to be used to evaluate if this is an Empty State to provide specific conditions for this extension. * From 279674402049316833c6af5723a296f97ac7644c Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Fri, 23 Jul 2021 00:02:32 +0530 Subject: [PATCH 12/85] call workflow plugin --- .../components/com_modules/src/View/Modules/HtmlView.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/administrator/components/com_modules/src/View/Modules/HtmlView.php b/administrator/components/com_modules/src/View/Modules/HtmlView.php index 698fed3736e66..d8c72474062b4 100644 --- a/administrator/components/com_modules/src/View/Modules/HtmlView.php +++ b/administrator/components/com_modules/src/View/Modules/HtmlView.php @@ -12,12 +12,14 @@ \defined('_JEXEC') or die; use Joomla\CMS\Factory; +use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Helper\ContentHelper; use Joomla\CMS\Helper\ModuleHelper; use Joomla\CMS\Language\Multilanguage; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\View\GenericDataException; use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView; +use Joomla\CMS\Plugin\PluginHelper; use Joomla\CMS\Toolbar\Toolbar; use Joomla\CMS\Toolbar\ToolbarHelper; @@ -98,6 +100,13 @@ public function display($tpl = null) $this->setLayout('emptystate'); } + if (ComponentHelper::getParams('com_modules')->get('workflow_enabled')) + { + PluginHelper::importPlugin('workflow'); + + $this->transitions = $this->get('Transitions'); + } + /** * The code below make sure the remembered position will be available from filter dropdown even if there are no * modules available for this position. This will make the UI less confusing for users in case there is only one From 821bdb29b0d5020aea00db40d828707dacfa4b9e Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Fri, 23 Jul 2021 00:03:05 +0530 Subject: [PATCH 13/85] display workflow field in batch_body --- .../com_modules/tmpl/modules/default_batch_body.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/administrator/components/com_modules/tmpl/modules/default_batch_body.php b/administrator/components/com_modules/tmpl/modules/default_batch_body.php index 2a52e9c45f60c..ee7764d870ae2 100644 --- a/administrator/components/com_modules/tmpl/modules/default_batch_body.php +++ b/administrator/components/com_modules/tmpl/modules/default_batch_body.php @@ -9,6 +9,8 @@ defined('_JEXEC') or die; +use Joomla\CMS\Component\ComponentHelper; +use Joomla\CMS\Factory; use Joomla\CMS\Helper\ModuleHelper; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; @@ -17,6 +19,10 @@ $clientId = $this->state->get('client_id'); +$params = ComponentHelper::getParams('com_content'); + +$user = Factory::getUser(); + // Show only Module Positions of published Templates $published = 1; $positions = HTMLHelper::_('modules.positions', $clientId, $published); @@ -59,6 +65,13 @@ + authorise('core.admin', 'com_modules') && $params->get('workflow_enabled')) : ?> +
+
+ 'com_modules']); ?> +
+
+
= 0) : ?> From 925cece06669c137bd2ca5cef2d80071298b59d9 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Fri, 23 Jul 2021 00:17:46 +0530 Subject: [PATCH 14/85] fix the language constant for sidebar --- administrator/components/com_menus/presets/default.xml | 2 +- administrator/components/com_menus/presets/system.xml | 2 +- administrator/language/en-GB/com_modules.ini | 1 - administrator/language/en-GB/mod_menu.ini | 1 + 4 files changed, 3 insertions(+), 3 deletions(-) diff --git a/administrator/components/com_menus/presets/default.xml b/administrator/components/com_menus/presets/default.xml index 096d5d54a8f6b..8c62f379d6d93 100644 --- a/administrator/components/com_menus/presets/default.xml +++ b/administrator/components/com_menus/presets/default.xml @@ -101,7 +101,7 @@ /> Date: Fri, 23 Jul 2021 16:35:13 +0530 Subject: [PATCH 15/85] display workflow in all modules view --- .../com_modules/tmpl/modules/default.php | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/administrator/components/com_modules/tmpl/modules/default.php b/administrator/components/com_modules/tmpl/modules/default.php index c3bccaa60f501..53b9260b11ea4 100644 --- a/administrator/components/com_modules/tmpl/modules/default.php +++ b/administrator/components/com_modules/tmpl/modules/default.php @@ -9,6 +9,9 @@ defined('_JEXEC') or die; +use Joomla\CMS\Button\PublishedButton; +use Joomla\CMS\Button\TransitionButton; +use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\Helper\ModuleHelper; use Joomla\CMS\HTML\HTMLHelper; @@ -17,6 +20,8 @@ use Joomla\CMS\Layout\LayoutHelper; use Joomla\CMS\Router\Route; use Joomla\CMS\Session\Session; +use Joomla\Component\Content\Administrator\Helper\ContentHelper; +use Joomla\Utilities\ArrayHelper; /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->document->getWebAssetManager(); @@ -34,6 +39,38 @@ $saveOrderingUrl = 'index.php?option=com_modules&task=modules.saveOrderAjax&tmpl=component&' . Session::getFormToken() . '=1'; HTMLHelper::_('draggablelist.draggable'); } + +$workflow_enabled = ComponentHelper::getParams('com_modules')->get('workflow_enabled'); +$workflow_state = false; + +if ($workflow_enabled) : + +// @todo move the script to a file +$js = <<document->getWebAssetManager(); + +$wa->getRegistry()->addExtensionRegistryFile('com_workflow'); +$wa->useScript('com_workflow.admin-items-workflow-buttons') + ->addInlineScript($js, [], ['type' => 'module']); + +$workflow_state = Factory::getApplication()->bootComponent('com_content')->isFunctionalityUsed('core.state', 'com_content.article'); +$workflow_featured = Factory::getApplication()->bootComponent('com_content')->isFunctionalityUsed('core.featured', 'com_content.article'); + +endif; ?>
@@ -53,6 +90,11 @@ + + + + + @@ -94,6 +136,10 @@ $canEdit = $user->authorise('core.edit', 'com_modules.module.' . $item->id); $canCheckin = $user->authorise('core.manage', 'com_checkin') || $item->checked_out == $user->get('id')|| is_null($item->checked_out); $canChange = $user->authorise('core.edit.state', 'com_modules.module.' . $item->id) && $canCheckin; + $transitions = ContentHelper::filterTransitions($this->transitions, (int) $item->stage_id, (int) $item->workflow_id); + + $transition_ids = ArrayHelper::getColumn($transitions, 'value'); + $transition_ids = ArrayHelper::toInteger($transition_ids); ?> @@ -118,6 +164,32 @@ + + + $transitions, + 'title' => Text::_($item->stage_title), + 'tip_content' => Text::sprintf('JWORKFLOW', Text::_($item->workflow_title)), + 'id' => 'workflow-' . $item->id + ]; + + echo (new TransitionButton($options)) + ->render(0, $i); + ?> + + + 'modules.', + 'disabled' => $workflow_state || !$canChange, + 'id' => 'state-' . $item->id + ]; + + echo (new PublishedButton)->render((int) $item->state, $i, $options, $item->publish_up, $item->publish_down); + ?> + + enabled > 0) : ?> @@ -129,6 +201,7 @@ +
checked_out) : ?> @@ -212,6 +285,11 @@ $this->loadTemplate('batch_body') ); ?> + + + + + From d783a50aa5f37d028ce1373170c8cbebdca59e0c Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Fri, 23 Jul 2021 16:35:48 +0530 Subject: [PATCH 16/85] installation sql --- installation/sql/mysql/base.sql | 37 ++++++++++----- installation/sql/postgresql/base.sql | 67 +++++++++++++++++----------- 2 files changed, 65 insertions(+), 39 deletions(-) diff --git a/installation/sql/mysql/base.sql b/installation/sql/mysql/base.sql index fd35b8d5db4de..6956e6318073e 100644 --- a/installation/sql/mysql/base.sql +++ b/installation/sql/mysql/base.sql @@ -84,8 +84,8 @@ INSERT INTO `#__assets` (`id`, `parent_id`, `lft`, `rgt`, `level`, `name`, `titl (62, 56, 31, 32, 3, 'com_content.transition.5', 'Feature', '{}'), (63, 56, 33, 34, 3, 'com_content.transition.6', 'Unfeature', '{}'), (64, 56, 35, 36, 3, 'com_content.transition.7', 'Publish & Feature', '{}'), -(65, 1, 141, 142, 1, 'com_privacy', 'com_privacy', '{}'), -(66, 1, 143, 144, 1, 'com_actionlogs', 'com_actionlogs', '{}'), +(65, 1, 151, 152, 1, 'com_privacy', 'com_privacy', '{}'), +(66, 1, 153, 154, 1, 'com_actionlogs', 'com_actionlogs', '{}'), (67, 18, 74, 75, 2, 'com_modules.module.88', 'Latest Actions', '{}'), (68, 18, 76, 77, 2, 'com_modules.module.89', 'Privacy Dashboard', '{}'), (70, 18, 88, 89, 2, 'com_modules.module.103', 'Site', '{}'), @@ -107,7 +107,12 @@ INSERT INTO `#__assets` (`id`, `parent_id`, `lft`, `rgt`, `level`, `name`, `titl (87, 18, 124, 125, 2, 'com_modules.module.97', 'Recently Added Articles', '{}'), (88, 18, 126, 127, 2, 'com_modules.module.98', 'Logged-in Users', '{}'), (89, 18, 128, 129, 2, 'com_modules.module.90', 'Login Support', '{}'), -(90, 1, 163, 164, 1, 'com_scheduler', 'com_scheduler', '{}'); +(90, 1, 173, 174, 1, 'com_scheduler', 'com_scheduler', '{}'); +(91, 8, 130, 131, 2, 'com_modules.workflow.1', 'COM_WORKFLOW_BASIC_WORKFLOW', '{}'), +(92, 18, 132, 133, 3, 'com_modules.state.1', 'COM_WORKFLOW_BASIC_STAGE', '{}'), +(93, 18, 134, 135, 3, 'com_modules.transition.1', 'Publish', '{}'), +(94, 18, 136, 137, 3, 'com_modules.transition.2', 'Unpublish', '{}'), +(95, 18, 138, 139, 3, 'com_modules.transition.3', 'Trash', '{}'); -- -------------------------------------------------------- @@ -1089,7 +1094,8 @@ CREATE TABLE IF NOT EXISTS `#__workflows` ( -- INSERT INTO `#__workflows` (`id`, `asset_id`, `published`, `title`, `description`, `extension`, `default`, `ordering`, `created`, `created_by`, `modified`, `modified_by`) VALUES -(1, 56, 1, 'COM_WORKFLOW_BASIC_WORKFLOW', '', 'com_content.article', 1, 1, CURRENT_TIMESTAMP(), 42, CURRENT_TIMESTAMP(), 42); +(1, 56, 1, 'COM_WORKFLOW_BASIC_WORKFLOW', '', 'com_content.article', 1, 1, CURRENT_TIMESTAMP(), 42, CURRENT_TIMESTAMP(), 42), +(2, 89, 1, 'COM_WORKFLOW_BASIC_WORKFLOW', '', 'com_modules.module', 1, 1, CURRENT_TIMESTAMP(), 42, CURRENT_TIMESTAMP(), 42); -- -------------------------------------------------------- @@ -1138,7 +1144,8 @@ CREATE TABLE IF NOT EXISTS `#__workflow_stages` ( -- INSERT INTO `#__workflow_stages` (`id`, `asset_id`, `ordering`, `workflow_id`, `published`, `title`, `description`, `default`) VALUES -(1, 57, 1, 1, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1); +(1, 0, 1, 1, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1), +(2, 18, 1, 2, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1); -- -------------------------------------------------------- @@ -1173,10 +1180,16 @@ CREATE TABLE IF NOT EXISTS `#__workflow_transitions` ( -- INSERT INTO `#__workflow_transitions` (`id`, `asset_id`, `published`, `ordering`, `workflow_id`, `title`, `description`, `from_stage_id`, `to_stage_id`, `options`) VALUES -(1, 58, 1, 1, 1, 'UNPUBLISH', '', -1, 1, '{"publishing":"0"}'), -(2, 59, 1, 2, 1, 'PUBLISH', '', -1, 1, '{"publishing":"1"}'), -(3, 60, 1, 3, 1, 'TRASH', '', -1, 1, '{"publishing":"-2"}'), -(4, 61, 1, 4, 1, 'ARCHIVE', '', -1, 1, '{"publishing":"2"}'), -(5, 62, 1, 5, 1, 'FEATURE', '', -1, 1, '{"featuring":"1"}'), -(6, 63, 1, 6, 1, 'UNFEATURE', '', -1, 1, '{"featuring":"0"}'), -(7, 64, 1, 7, 1, 'PUBLISH_AND_FEATURE', '', -1, 1, '{"publishing":"1","featuring":"1"}'); +(1, 58, 1, 1, 1, 'Unpublish', '', -1, 1, '{"publishing":"0"}'), +(2, 59, 1, 2, 1, 'Publish', '', -1, 1, '{"publishing":"1"}'), +(3, 60, 1, 3, 1, 'Trash', '', -1, 1, '{"publishing":"-2"}'), +(4, 61, 1, 4, 1, 'Archive', '', -1, 1, '{"publishing":"2"}'), +(5, 62, 1, 5, 1, 'Feature', '', -1, 1, '{"featuring":"1"}'), +(6, 63, 1, 6, 1, 'Unfeature', '', -1, 1, '{"featuring":"0"}'), +(7, 64, 1, 7, 1, 'Publish & Feature', '', -1, 1, '{"publishing":"1","featuring":"1"}'), +(8, 92, 1, 1, 2, 'Unpublish', '', -1, 1, '{"publishing":"0"}'), +(9, 91, 1, 2, 2, 'Publish', '', -1, 1, '{"publishing":"1"}'), +(10, 93, 1, 3, 2, 'Trash', '', -1, 1, '{"publishing":"-2"}'); + +INSERT INTO `#__workflow_associations` (`item_id`, `stage_id`, `extension`) +SELECT `id`, 2, 'com_modules.module' FROM `#__modules`; diff --git a/installation/sql/postgresql/base.sql b/installation/sql/postgresql/base.sql index 167bae11512ec..95da91b3640f8 100644 --- a/installation/sql/postgresql/base.sql +++ b/installation/sql/postgresql/base.sql @@ -47,24 +47,24 @@ INSERT INTO "#__assets" ("id", "parent_id", "lft", "rgt", "level", "name", "titl (15, 1, 49, 50, 1, 'com_media', 'com_media', '{"core.admin":{"7":1},"core.manage":{"6":1},"core.create":{"3":1},"core.delete":{"5":1}}'), (16, 1, 51, 54, 1, 'com_menus', 'com_menus', '{"core.admin":{"7":1}}'), (17, 1, 55, 56, 1, 'com_messages', 'com_messages', '{"core.admin":{"7":1},"core.manage":{"7":1}}'), -(18, 1, 57, 130, 1, 'com_modules', 'com_modules', '{"core.admin":{"7":1}}'), -(19, 1, 131, 134, 1, 'com_newsfeeds', 'com_newsfeeds', '{"core.admin":{"7":1},"core.manage":{"6":1}}'), -(20, 1, 135, 136, 1, 'com_plugins', 'com_plugins', '{"core.admin":{"7":1}}'), -(21, 1, 137, 138, 1, 'com_redirect', 'com_redirect', '{"core.admin":{"7":1}}'), -(23, 1, 139, 140, 1, 'com_templates', 'com_templates', '{"core.admin":{"7":1}}'), -(24, 1, 145, 148, 1, 'com_users', 'com_users', '{"core.admin":{"7":1}}'), -(26, 1, 149, 150, 1, 'com_wrapper', 'com_wrapper', '{}'), +(18, 1, 57, 140, 1, 'com_modules', 'com_modules', '{"core.admin":{"7":1}}'), +(19, 1, 141, 144, 1, 'com_newsfeeds', 'com_newsfeeds', '{"core.admin":{"7":1},"core.manage":{"6":1}}'), +(20, 1, 145, 146, 1, 'com_plugins', 'com_plugins', '{"core.admin":{"7":1}}'), +(21, 1, 147, 148, 1, 'com_redirect', 'com_redirect', '{"core.admin":{"7":1}}'), +(23, 1, 149, 150, 1, 'com_templates', 'com_templates', '{"core.admin":{"7":1}}'), +(24, 1, 155, 158, 1, 'com_users', 'com_users', '{"core.admin":{"7":1}}'), +(26, 1, 159, 160, 1, 'com_wrapper', 'com_wrapper', '{}'), (27, 8, 18, 19, 2, 'com_content.category.2', 'Uncategorised', '{}'), (28, 3, 4, 5, 2, 'com_banners.category.3', 'Uncategorised', '{}'), (29, 7, 14, 15, 2, 'com_contact.category.4', 'Uncategorised', '{}'), -(30, 19, 132, 133, 2, 'com_newsfeeds.category.5', 'Uncategorised', '{}'), -(32, 24, 146, 147, 2, 'com_users.category.7', 'Uncategorised', '{}'), -(33, 1, 151, 152, 1, 'com_finder', 'com_finder', '{"core.admin":{"7":1},"core.manage":{"6":1}}'), -(34, 1, 153, 154, 1, 'com_joomlaupdate', 'com_joomlaupdate', '{}'), -(35, 1, 155, 156, 1, 'com_tags', 'com_tags', '{}'), -(36, 1, 157, 158, 1, 'com_contenthistory', 'com_contenthistory', '{}'), -(37, 1, 159, 160, 1, 'com_ajax', 'com_ajax', '{}'), -(38, 1, 161, 162, 1, 'com_postinstall', 'com_postinstall', '{}'), +(30, 19, 142, 143, 2, 'com_newsfeeds.category.5', 'Uncategorised', '{}'), +(32, 24, 156, 157, 2, 'com_users.category.7', 'Uncategorised', '{}'), +(33, 1, 161, 162, 1, 'com_finder', 'com_finder', '{"core.admin":{"7":1},"core.manage":{"6":1}}'), +(34, 1, 163, 164, 1, 'com_joomlaupdate', 'com_joomlaupdate', '{}'), +(35, 1, 165, 166, 1, 'com_tags', 'com_tags', '{}'), +(36, 1, 167, 168, 1, 'com_contenthistory', 'com_contenthistory', '{}'), +(37, 1, 169, 170, 1, 'com_ajax', 'com_ajax', '{}'), +(38, 1, 171, 172, 1, 'com_postinstall', 'com_postinstall', '{}'), (39, 18, 58, 59, 2, 'com_modules.module.1', 'Main Menu', '{}'), (40, 18, 60, 61, 2, 'com_modules.module.2', 'Login', '{}'), (41, 18, 62, 63, 2, 'com_modules.module.3', 'Popular Articles', '{}'), @@ -90,8 +90,8 @@ INSERT INTO "#__assets" ("id", "parent_id", "lft", "rgt", "level", "name", "titl (62, 56, 31, 32, 3, 'com_content.transition.5', 'Feature', '{}'), (63, 56, 33, 34, 3, 'com_content.transition.6', 'Unfeature', '{}'), (64, 56, 35, 36, 3, 'com_content.transition.7', 'Publish & Feature', '{}'), -(65, 1, 141, 142, 1, 'com_privacy', 'com_privacy', '{}'), -(66, 1, 143, 144, 1, 'com_actionlogs', 'com_actionlogs', '{}'), +(65, 1, 151, 152, 1, 'com_privacy', 'com_privacy', '{}'), +(66, 1, 153, 154, 1, 'com_actionlogs', 'com_actionlogs', '{}'), (67, 18, 74, 75, 2, 'com_modules.module.88', 'Latest Actions', '{}'), (68, 18, 76, 77, 2, 'com_modules.module.89', 'Privacy Dashboard', '{}'), (70, 18, 88, 89, 2, 'com_modules.module.103', 'Site', '{}'), @@ -113,7 +113,12 @@ INSERT INTO "#__assets" ("id", "parent_id", "lft", "rgt", "level", "name", "titl (87, 18, 124, 125, 2, 'com_modules.module.97', 'Recently Added Articles', '{}'), (88, 18, 126, 127, 2, 'com_modules.module.98', 'Logged-in Users', '{}'), (89, 18, 128, 129, 2, 'com_modules.module.90', 'Login Support', '{}'), -(90, 1, 163, 164, 1, 'com_scheduler', 'com_scheduler', '{}'); +(90, 1, 173, 174, 1, 'com_scheduler', 'com_scheduler', '{}'); +(91, 8, 130, 131, 2, 'com_modules.workflow.1', 'COM_WORKFLOW_BASIC_WORKFLOW', '{}'), +(92, 18, 132, 133, 3, 'com_modules.state.1', 'COM_WORKFLOW_BASIC_STAGE', '{}'), +(93, 18, 134, 135, 3, 'com_modules.transition.1', 'Publish', '{}'), +(94, 18, 136, 137, 3, 'com_modules.transition.2', 'Unpublish', '{}'), +(95, 18, 138, 139, 3, 'com_modules.transition.3', 'Trash', '{}'); SELECT setval('#__assets_id_seq', 91, false); @@ -1111,7 +1116,8 @@ CREATE INDEX "#__workflows_idx_modified_by" ON "#__workflows" ("modified_by"); CREATE INDEX "#__workflows_idx_checked_out" ON "#__workflows" ("checked_out"); INSERT INTO "#__workflows" ("id", "asset_id", "published", "title", "description", "extension", "default", "ordering", "created", "created_by", "modified", "modified_by") VALUES -(1, 56, 1, 'COM_WORKFLOW_BASIC_WORKFLOW', '', 'com_content.article', 1, 1, CURRENT_TIMESTAMP, 42, CURRENT_TIMESTAMP, 42); +(1, 56, 1, 'COM_WORKFLOW_BASIC_WORKFLOW', '', 'com_content.article', 1, 1, CURRENT_TIMESTAMP, 42, CURRENT_TIMESTAMP, 42), +(2, 89, 1, 'COM_WORKFLOW_BASIC_WORKFLOW', '', 'com_modules.module', 1, 1, CURRENT_TIMESTAMP, 42, CURRENT_TIMESTAMP, 42); SELECT setval('#__workflows_id_seq', 2, false); @@ -1161,7 +1167,8 @@ CREATE INDEX "#__workflow_stages_idx_checked_out" ON "#__workflow_stages" ("chec -- INSERT INTO "#__workflow_stages" ("id", "asset_id", "ordering", "workflow_id", "published", "title", "description", "default") VALUES -(1, 57, 1, 1, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1); +(1, 57, 1, 1, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1), +(2, 90, 1, 2, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1); SELECT setval('#__workflow_stages_id_seq', 2, false); @@ -1192,12 +1199,18 @@ CREATE INDEX "#__workflow_transitions_idx_workflow_id" ON "#__workflow_transitio CREATE INDEX "#__workflow_transitions_idx_checked_out" ON "#__workflow_transitions" ("checked_out"); INSERT INTO "#__workflow_transitions" ("id", "asset_id", "published", "ordering", "workflow_id", "title", "description", "from_stage_id", "to_stage_id", "options") VALUES -(1, 58, 1, 1, 1, 'UNPUBLISH', '', -1, 1, '{"publishing":"0"}'), -(2, 59, 1, 2, 1, 'PUBLISH', '', -1, 1, '{"publishing":"1"}'), -(3, 60, 1, 3, 1, 'TRASH', '', -1, 1, '{"publishing":"-2"}'), -(4, 61, 1, 4, 1, 'ARCHIVE', '', -1, 1, '{"publishing":"2"}'), -(5, 62, 1, 5, 1, 'FEATURE', '', -1, 1, '{"featuring":"1"}'), -(6, 63, 1, 6, 1, 'UNFEATURE', '', -1, 1, '{"featuring":"0"}'), -(7, 64, 1, 7, 1, 'PUBLISH_AND_FEATURE', '', -1, 1, '{"publishing":"1","featuring":"1"}'); +(1, 58, 1, 1, 1, 'Unpublish', '', -1, 1, '{"publishing":"0"}'), +(2, 59, 1, 2, 1, 'Publish', '', -1, 1, '{"publishing":"1"}'), +(3, 60, 1, 3, 1, 'Trash', '', -1, 1, '{"publishing":"-2"}'), +(4, 61, 1, 4, 1, 'Archive', '', -1, 1, '{"publishing":"2"}'), +(5, 62, 1, 5, 1, 'Feature', '', -1, 1, '{"featuring":"1"}'), +(6, 63, 1, 6, 1, 'Unfeature', '', -1, 1, '{"featuring":"0"}'), +(7, 64, 1, 7, 1, 'Publish & Feature', '', -1, 1, '{"publishing":"1","featuring":"1"}'), +(8, 92, 1, 1, 2, 'Unpublish', '', -1, 1, '{"publishing":"0"}'), +(9, 91, 1, 2, 2, 'Publish', '', -1, 1, '{"publishing":"1"}'), +(10, 93, 1, 3, 2, 'Trash', '', -1, 1, '{"publishing":"-2"}'); SELECT setval('#__workflow_transitions_id_seq', 8, false); + +INSERT INTO `#__workflow_associations` (`item_id`, `stage_id`, `extension`) +SELECT `id`, 2, 'com_modules.module' FROM `#__modules`; \ No newline at end of file From 82802961ac6fdbb24c24c18f3558c1391032a4e2 Mon Sep 17 00:00:00 2001 From: Benjamin Trenkle Date: Wed, 23 Jun 2021 13:07:17 +0200 Subject: [PATCH 17/85] Update signature --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index 954b3df2b709c..e6385d0e238a2 100644 --- a/.drone.yml +++ b/.drone.yml @@ -420,6 +420,6 @@ steps: --- kind: signature -hmac: d9707d261edba35bc6b70f09a1babee119cb0a88cebda40171248e5c0a8b135e +hmac: 53e23beca546bde246f812a726320210f33d231106cb154a65cc900ecbf7502e ... From c37492133c8cc1d50f1afd8e0a921e867e82caff Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Sat, 24 Jul 2021 10:31:31 +0530 Subject: [PATCH 18/85] misc workflow bug fixes in modules view --- .../com_modules/tmpl/modules/default.php | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/administrator/components/com_modules/tmpl/modules/default.php b/administrator/components/com_modules/tmpl/modules/default.php index 53b9260b11ea4..5081a115f2645 100644 --- a/administrator/components/com_modules/tmpl/modules/default.php +++ b/administrator/components/com_modules/tmpl/modules/default.php @@ -67,8 +67,8 @@ $wa->useScript('com_workflow.admin-items-workflow-buttons') ->addInlineScript($js, [], ['type' => 'module']); -$workflow_state = Factory::getApplication()->bootComponent('com_content')->isFunctionalityUsed('core.state', 'com_content.article'); -$workflow_featured = Factory::getApplication()->bootComponent('com_content')->isFunctionalityUsed('core.featured', 'com_content.article'); +$workflow_state = Factory::getApplication()->bootComponent('com_content')->isFunctionalityUsed('core.state', 'com_modules.module'); +$workflow_featured = Factory::getApplication()->bootComponent('com_content')->isFunctionalityUsed('core.featured', 'com_modules.module'); endif; ?> @@ -136,10 +136,13 @@ $canEdit = $user->authorise('core.edit', 'com_modules.module.' . $item->id); $canCheckin = $user->authorise('core.manage', 'com_checkin') || $item->checked_out == $user->get('id')|| is_null($item->checked_out); $canChange = $user->authorise('core.edit.state', 'com_modules.module.' . $item->id) && $canCheckin; - $transitions = ContentHelper::filterTransitions($this->transitions, (int) $item->stage_id, (int) $item->workflow_id); + if ($workflow_enabled) + { + $transitions = ContentHelper::filterTransitions($this->transitions, (int) $item->stage_id, (int) $item->workflow_id); - $transition_ids = ArrayHelper::getColumn($transitions, 'value'); - $transition_ids = ArrayHelper::toInteger($transition_ids); + $transition_ids = ArrayHelper::getColumn($transitions, 'value'); + $transition_ids = ArrayHelper::toInteger($transition_ids); + } ?> @@ -165,13 +168,14 @@ - + $transitions, 'title' => Text::_($item->stage_title), 'tip_content' => Text::sprintf('JWORKFLOW', Text::_($item->workflow_title)), - 'id' => 'workflow-' . $item->id + 'id' => 'workflow-' . $item->id, + 'task' => 'modules.runTransition' ]; echo (new TransitionButton($options)) @@ -186,7 +190,7 @@ 'id' => 'state-' . $item->id ]; - echo (new PublishedButton)->render((int) $item->state, $i, $options, $item->publish_up, $item->publish_down); + echo (new PublishedButton)->render((int) $item->published, $i, $options, $item->publish_up, $item->publish_down); ?> From 61b11f688b18b85969eca89df1e7b92c079cd4f1 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Sat, 24 Jul 2021 10:52:22 +0530 Subject: [PATCH 19/85] merge PR https://github.com/joomla/joomla-cms/pull/34882 --- administrator/components/com_content/tmpl/featured/default.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/administrator/components/com_content/tmpl/featured/default.php b/administrator/components/com_content/tmpl/featured/default.php index 5ca431d64fe21..b9a2f19462b65 100644 --- a/administrator/components/com_content/tmpl/featured/default.php +++ b/administrator/components/com_content/tmpl/featured/default.php @@ -226,7 +226,7 @@ 'title' => Text::_($item->stage_title), 'tip_content' => Text::sprintf('JWORKFLOW', Text::_($item->workflow_title)), 'id' => 'workflow-' . $item->id, - 'task' => 'articles.runTransitions' + 'task' => 'articles.runTransition' ]; echo (new TransitionButton($options)) From a99f5cc29c2ef728b708c6b0f08358b14cf2a7e3 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Sat, 24 Jul 2021 10:52:56 +0530 Subject: [PATCH 20/85] correct the to_stage_id in installation sql --- installation/sql/mysql/base.sql | 6 +++--- installation/sql/postgresql/base.sql | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/installation/sql/mysql/base.sql b/installation/sql/mysql/base.sql index 6956e6318073e..dc14ee172ec98 100644 --- a/installation/sql/mysql/base.sql +++ b/installation/sql/mysql/base.sql @@ -1187,9 +1187,9 @@ INSERT INTO `#__workflow_transitions` (`id`, `asset_id`, `published`, `ordering` (5, 62, 1, 5, 1, 'Feature', '', -1, 1, '{"featuring":"1"}'), (6, 63, 1, 6, 1, 'Unfeature', '', -1, 1, '{"featuring":"0"}'), (7, 64, 1, 7, 1, 'Publish & Feature', '', -1, 1, '{"publishing":"1","featuring":"1"}'), -(8, 92, 1, 1, 2, 'Unpublish', '', -1, 1, '{"publishing":"0"}'), -(9, 91, 1, 2, 2, 'Publish', '', -1, 1, '{"publishing":"1"}'), -(10, 93, 1, 3, 2, 'Trash', '', -1, 1, '{"publishing":"-2"}'); +(8, 92, 1, 1, 2, 'Unpublish', '', -1, 2, '{"publishing":"0"}'), +(9, 91, 1, 2, 2, 'Publish', '', -1, 2, '{"publishing":"1"}'), +(10, 93, 1, 3, 2, 'Trash', '', -1, 2, '{"publishing":"-2"}'); INSERT INTO `#__workflow_associations` (`item_id`, `stage_id`, `extension`) SELECT `id`, 2, 'com_modules.module' FROM `#__modules`; diff --git a/installation/sql/postgresql/base.sql b/installation/sql/postgresql/base.sql index 95da91b3640f8..5feaaca36a368 100644 --- a/installation/sql/postgresql/base.sql +++ b/installation/sql/postgresql/base.sql @@ -1206,9 +1206,9 @@ INSERT INTO "#__workflow_transitions" ("id", "asset_id", "published", "ordering" (5, 62, 1, 5, 1, 'Feature', '', -1, 1, '{"featuring":"1"}'), (6, 63, 1, 6, 1, 'Unfeature', '', -1, 1, '{"featuring":"0"}'), (7, 64, 1, 7, 1, 'Publish & Feature', '', -1, 1, '{"publishing":"1","featuring":"1"}'), -(8, 92, 1, 1, 2, 'Unpublish', '', -1, 1, '{"publishing":"0"}'), -(9, 91, 1, 2, 2, 'Publish', '', -1, 1, '{"publishing":"1"}'), -(10, 93, 1, 3, 2, 'Trash', '', -1, 1, '{"publishing":"-2"}'); +(8, 92, 1, 1, 2, 'Unpublish', '', -1, 2, '{"publishing":"0"}'), +(9, 91, 1, 2, 2, 'Publish', '', -1, 2, '{"publishing":"1"}'), +(10, 93, 1, 3, 2, 'Trash', '', -1, 2, '{"publishing":"-2"}'); SELECT setval('#__workflow_transitions_id_seq', 8, false); From 9d40944df3246b6fd09a8a6b14727eb341e0811c Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Sat, 24 Jul 2021 19:01:55 +0530 Subject: [PATCH 21/85] indent conditional statement --- .../com_modules/tmpl/modules/default.php | 37 +++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/administrator/components/com_modules/tmpl/modules/default.php b/administrator/components/com_modules/tmpl/modules/default.php index 5081a115f2645..cff0a19b2dcca 100644 --- a/administrator/components/com_modules/tmpl/modules/default.php +++ b/administrator/components/com_modules/tmpl/modules/default.php @@ -45,30 +45,29 @@ if ($workflow_enabled) : -// @todo move the script to a file -$js = <<document->getWebAssetManager(); + /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ + $wa = $this->document->getWebAssetManager(); -$wa->getRegistry()->addExtensionRegistryFile('com_workflow'); -$wa->useScript('com_workflow.admin-items-workflow-buttons') - ->addInlineScript($js, [], ['type' => 'module']); + $wa->getRegistry()->addExtensionRegistryFile('com_workflow'); + $wa->useScript('com_workflow.admin-items-workflow-buttons') + ->addInlineScript($js, [], ['type' => 'module']); -$workflow_state = Factory::getApplication()->bootComponent('com_content')->isFunctionalityUsed('core.state', 'com_modules.module'); -$workflow_featured = Factory::getApplication()->bootComponent('com_content')->isFunctionalityUsed('core.featured', 'com_modules.module'); + $workflow_state = Factory::getApplication()->bootComponent('com_modules')->isFunctionalityUsed('core.state', 'com_modules.module'); endif; ?> From 669b71a34943e7704a30f561fc819bff5587ce5a Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Sat, 24 Jul 2021 19:02:22 +0530 Subject: [PATCH 22/85] add functionality conditions --- .../src/Extension/ModulesComponent.php | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/administrator/components/com_modules/src/Extension/ModulesComponent.php b/administrator/components/com_modules/src/Extension/ModulesComponent.php index 5941a144180df..4753869730ae1 100644 --- a/administrator/components/com_modules/src/Extension/ModulesComponent.php +++ b/administrator/components/com_modules/src/Extension/ModulesComponent.php @@ -32,6 +32,44 @@ class ModulesComponent extends MVCComponent implements BootableExtensionInterfac use HTMLRegistryAwareTrait; use WorkflowServiceTrait; + /** @var array Supported functionality */ + protected $supportedFunctionality = [ + 'core.state' => true, + ]; + + /** + * The trashed condition + * + * @since __DEPLOY_VERSION__ + */ + const CONDITION_NAMES = [ + self::CONDITION_PUBLISHED => 'JPUBLISHED', + self::CONDITION_UNPUBLISHED => 'JUNPUBLISHED', + self::CONDITION_TRASHED => 'JTRASHED', + ]; + + /** + * The published condition + * + * @since __DEPLOY_VERSION__ + */ + const CONDITION_PUBLISHED = 1; + + /** + * The unpublished condition + * + * @since __DEPLOY_VERSION__ + */ + const CONDITION_UNPUBLISHED = 0; + + /** + * The trashed condition + * + * @since __DEPLOY_VERSION__ + */ + const CONDITION_TRASHED = -2; + + /** * Booting the extension. This is the function to set up the environment of the extension like * registering new class loaders, etc. From 3b1e167935cd9a9200bb8e7005cce229c8bc8360 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Mon, 26 Jul 2021 19:04:31 +0530 Subject: [PATCH 23/85] make WorkflowBehaviourTrait lang const global --- libraries/src/MVC/Model/WorkflowBehaviorTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php index 4005c52ea8df0..5418a1dc6f582 100644 --- a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php +++ b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php @@ -341,7 +341,7 @@ protected function addTransitionField(Form $form, $data) $field->addAttribute('name', 'transition'); $field->addAttribute('type', $this->workflowEnabled ? 'transition' : 'hidden'); - $field->addAttribute('label', 'COM_CONTENT_WORKFLOW'); + $field->addAttribute('label', 'JWORKFLOW_TITLE'); $field->addAttribute('extension', $extension); $form->setField($field); From 7261bba6d43bee44de19fdb9338fdb5467feae10 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Mon, 26 Jul 2021 19:04:47 +0530 Subject: [PATCH 24/85] display workflow transition field --- administrator/components/com_modules/tmpl/module/edit.php | 1 + 1 file changed, 1 insertion(+) diff --git a/administrator/components/com_modules/tmpl/module/edit.php b/administrator/components/com_modules/tmpl/module/edit.php index 982bbf002d4fc..38d8c58da144a 100644 --- a/administrator/components/com_modules/tmpl/module/edit.php +++ b/administrator/components/com_modules/tmpl/module/edit.php @@ -134,6 +134,7 @@ fields = array( + 'transition', 'showtitle', 'position', 'published', From 1fc34fb60cd3965d5cd2e12b8f000cf0a9d6d268 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Tue, 27 Jul 2021 18:52:10 +0530 Subject: [PATCH 25/85] fix bug in saving new modules --- .../com_modules/src/Model/ModuleModel.php | 47 +++++++++++++++++-- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/administrator/components/com_modules/src/Model/ModuleModel.php b/administrator/components/com_modules/src/Model/ModuleModel.php index e6ffc50cb507b..c4a548c8335f0 100644 --- a/administrator/components/com_modules/src/Model/ModuleModel.php +++ b/administrator/components/com_modules/src/Model/ModuleModel.php @@ -852,12 +852,12 @@ public function getTable($type = 'Module', $prefix = 'JTable', $config = array() protected function prepareTable($table) { // Set the publish date to now - if ($table->state == Workflow::CONDITION_PUBLISHED && (int) $table->publish_up == 0) + if ($table->published == Workflow::CONDITION_PUBLISHED && (int) $table->publish_up == 0) { $table->publish_up = Factory::getDate()->toSql(); } - if ($table->state == Workflow::CONDITION_PUBLISHED && intval($table->publish_down) == 0) + if ($table->published == Workflow::CONDITION_PUBLISHED && intval($table->publish_down) == 0) { $table->publish_down = null; } @@ -1187,6 +1187,9 @@ public function save($data) $this->setState('module.extension_id', $extensionId); $this->setState('module.id', $table->id); + $this->setState('module.new', $isNew);; + + $this->workflowAfterSave($data); // Clear modules cache $this->cleanCache(); @@ -1194,8 +1197,6 @@ public function save($data) // Clean module cache parent::cleanCache($table->module); - $this->workflowAfterSave($data); - return true; } @@ -1247,4 +1248,42 @@ public function publish(&$pks, $value = 1) return parent::publish($pks, $value); } + + /** + * Overrides the function in WorkflowBehaviorTrait to get the default + * stage ID while creating a new module. + * + * @param Form $form A Form object. + * @param mixed $data The data expected for the form. + * + * @return boolean|integer An integer, holding the stage ID or false + * + * @since __DEPLOY_VERSION__ + */ + protected function getStageForNewItem(Form $form, $data) + { + $db = $this->getDbo(); + + // Query to find the default workflow id of the extension type com_modules.module + $defaultWorkflowQuery = $db->getQuery(true) + ->select($db->quoteName('id')) + ->from($db->quoteName('#__workflows')) + ->where($db->quoteName('default') . ' = 1') + ->where($db->quoteName('extension') . ' = "com_modules.module"'); + + $query = $db->getQuery(true) + ->select($db->quoteName('id')) + ->from($db->quoteName('#__workflow_stages')) + ->where($db->quoteName('default') . '= 1') + ->where($db->quoteName('workflow_id') . ' IN (' . $defaultWorkflowQuery . ')'); + $db->setQuery($query); + $defaultStage = $db->loadResult(); + + if (empty($defaultStage)) + { + return false; + } + + return $defaultStage; + } } From 00bb45e8039aed83ce3555672d82efd79f6a755f Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Tue, 27 Jul 2021 18:52:51 +0530 Subject: [PATCH 26/85] rename default workflow for modules --- administrator/language/en-GB/com_workflow.ini | 1 + installation/sql/mysql/base.sql | 44 +++++++++---------- installation/sql/postgresql/base.sql | 15 ++++--- 3 files changed, 31 insertions(+), 29 deletions(-) diff --git a/administrator/language/en-GB/com_workflow.ini b/administrator/language/en-GB/com_workflow.ini index f4644f2fcdd6e..1d6dcd126a291 100644 --- a/administrator/language/en-GB/com_workflow.ini +++ b/administrator/language/en-GB/com_workflow.ini @@ -8,6 +8,7 @@ COM_WORKFLOW_AUTHOR="Author" COM_WORKFLOW_BASIC_STAGE="Basic Stage" COM_WORKFLOW_BASIC_TAB="Basic" COM_WORKFLOW_BASIC_WORKFLOW="Basic Workflow" +COM_WORKFLOW_BASIC_WORKFLOW_MODULES="Basic Workflow: Modules" COM_WORKFLOW_CHOOSE_CONTEXT_LABEL="Context" COM_WORKFLOW_CONFIGURATION="Workflow: Options" COM_WORKFLOW_COUNT_STAGES="Stages" diff --git a/installation/sql/mysql/base.sql b/installation/sql/mysql/base.sql index dc14ee172ec98..73858ff72dba5 100644 --- a/installation/sql/mysql/base.sql +++ b/installation/sql/mysql/base.sql @@ -25,7 +25,7 @@ CREATE TABLE IF NOT EXISTS `#__assets` ( -- INSERT INTO `#__assets` (`id`, `parent_id`, `lft`, `rgt`, `level`, `name`, `title`, `rules`) VALUES -(1, 0, 0, 165, 0, 'root.1', 'Root Asset', '{"core.login.site":{"6":1,"2":1},"core.login.admin":{"6":1},"core.login.api":{"8":1},"core.login.offline":{"6":1},"core.admin":{"8":1},"core.manage":{"7":1},"core.create":{"6":1,"3":1},"core.delete":{"6":1},"core.edit":{"6":1,"4":1},"core.edit.state":{"6":1,"5":1},"core.edit.own":{"6":1,"3":1}}'), +(1, 0, 0, 175, 0, 'root.1', 'Root Asset', '{"core.login.site":{"6":1,"2":1},"core.login.admin":{"6":1},"core.login.api":{"8":1},"core.login.offline":{"6":1},"core.admin":{"8":1},"core.manage":{"7":1},"core.create":{"6":1,"3":1},"core.delete":{"6":1},"core.edit":{"6":1,"4":1},"core.edit.state":{"6":1,"5":1},"core.edit.own":{"6":1,"3":1}}'), (2, 1, 1, 2, 1, 'com_admin', 'com_admin', '{}'), (3, 1, 3, 6, 1, 'com_banners', 'com_banners', '{"core.admin":{"7":1},"core.manage":{"6":1}}'), (4, 1, 7, 8, 1, 'com_cache', 'com_cache', '{"core.admin":{"7":1},"core.manage":{"7":1}}'), @@ -41,24 +41,24 @@ INSERT INTO `#__assets` (`id`, `parent_id`, `lft`, `rgt`, `level`, `name`, `titl (15, 1, 49, 50, 1, 'com_media', 'com_media', '{"core.admin":{"7":1},"core.manage":{"6":1},"core.create":{"3":1},"core.delete":{"5":1}}'), (16, 1, 51, 54, 1, 'com_menus', 'com_menus', '{"core.admin":{"7":1}}'), (17, 1, 55, 56, 1, 'com_messages', 'com_messages', '{"core.admin":{"7":1},"core.manage":{"7":1}}'), -(18, 1, 57, 130, 1, 'com_modules', 'com_modules', '{"core.admin":{"7":1}}'), -(19, 1, 131, 134, 1, 'com_newsfeeds', 'com_newsfeeds', '{"core.admin":{"7":1},"core.manage":{"6":1}}'), -(20, 1, 135, 136, 1, 'com_plugins', 'com_plugins', '{"core.admin":{"7":1}}'), -(21, 1, 137, 138, 1, 'com_redirect', 'com_redirect', '{"core.admin":{"7":1}}'), -(23, 1, 139, 140, 1, 'com_templates', 'com_templates', '{"core.admin":{"7":1}}'), -(24, 1, 145, 148, 1, 'com_users', 'com_users', '{"core.admin":{"7":1}}'), -(26, 1, 149, 150, 1, 'com_wrapper', 'com_wrapper', '{}'), +(18, 1, 57, 140, 1, 'com_modules', 'com_modules', '{"core.admin":{"7":1}}'), +(19, 1, 141, 144, 1, 'com_newsfeeds', 'com_newsfeeds', '{"core.admin":{"7":1},"core.manage":{"6":1}}'), +(20, 1, 145, 146, 1, 'com_plugins', 'com_plugins', '{"core.admin":{"7":1}}'), +(21, 1, 147, 148, 1, 'com_redirect', 'com_redirect', '{"core.admin":{"7":1}}'), +(23, 1, 149, 150, 1, 'com_templates', 'com_templates', '{"core.admin":{"7":1}}'), +(24, 1, 155, 158, 1, 'com_users', 'com_users', '{"core.admin":{"7":1}}'), +(26, 1, 159, 160, 1, 'com_wrapper', 'com_wrapper', '{}'), (27, 8, 18, 19, 2, 'com_content.category.2', 'Uncategorised', '{}'), (28, 3, 4, 5, 2, 'com_banners.category.3', 'Uncategorised', '{}'), (29, 7, 14, 15, 2, 'com_contact.category.4', 'Uncategorised', '{}'), -(30, 19, 132, 133, 2, 'com_newsfeeds.category.5', 'Uncategorised', '{}'), -(32, 24, 146, 147, 2, 'com_users.category.7', 'Uncategorised', '{}'), -(33, 1, 151, 152, 1, 'com_finder', 'com_finder', '{"core.admin":{"7":1},"core.manage":{"6":1}}'), -(34, 1, 153, 154, 1, 'com_joomlaupdate', 'com_joomlaupdate', '{}'), -(35, 1, 155, 156, 1, 'com_tags', 'com_tags', '{}'), -(36, 1, 157, 158, 1, 'com_contenthistory', 'com_contenthistory', '{}'), -(37, 1, 159, 160, 1, 'com_ajax', 'com_ajax', '{}'), -(38, 1, 161, 162, 1, 'com_postinstall', 'com_postinstall', '{}'), +(30, 19, 142, 143, 2, 'com_newsfeeds.category.5', 'Uncategorised', '{}'), +(32, 24, 156, 157, 2, 'com_users.category.7', 'Uncategorised', '{}'), +(33, 1, 161, 162, 1, 'com_finder', 'com_finder', '{"core.admin":{"7":1},"core.manage":{"6":1}}'), +(34, 1, 163, 164, 1, 'com_joomlaupdate', 'com_joomlaupdate', '{}'), +(35, 1, 165, 166, 1, 'com_tags', 'com_tags', '{}'), +(36, 1, 167, 168, 1, 'com_contenthistory', 'com_contenthistory', '{}'), +(37, 1, 169, 170, 1, 'com_ajax', 'com_ajax', '{}'), +(38, 1, 171, 172, 1, 'com_postinstall', 'com_postinstall', '{}'), (39, 18, 58, 59, 2, 'com_modules.module.1', 'Main Menu', '{}'), (40, 18, 60, 61, 2, 'com_modules.module.2', 'Login', '{}'), (41, 18, 62, 63, 2, 'com_modules.module.3', 'Popular Articles', '{}'), @@ -108,11 +108,11 @@ INSERT INTO `#__assets` (`id`, `parent_id`, `lft`, `rgt`, `level`, `name`, `titl (88, 18, 126, 127, 2, 'com_modules.module.98', 'Logged-in Users', '{}'), (89, 18, 128, 129, 2, 'com_modules.module.90', 'Login Support', '{}'), (90, 1, 173, 174, 1, 'com_scheduler', 'com_scheduler', '{}'); -(91, 8, 130, 131, 2, 'com_modules.workflow.1', 'COM_WORKFLOW_BASIC_WORKFLOW', '{}'), -(92, 18, 132, 133, 3, 'com_modules.state.1', 'COM_WORKFLOW_BASIC_STAGE', '{}'), -(93, 18, 134, 135, 3, 'com_modules.transition.1', 'Publish', '{}'), -(94, 18, 136, 137, 3, 'com_modules.transition.2', 'Unpublish', '{}'), -(95, 18, 138, 139, 3, 'com_modules.transition.3', 'Trash', '{}'); +(89, 8, 130, 131, 2, 'com_modules.workflow.1', 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '{}'), +(90, 18, 132, 133, 3, 'com_modules.state.1', 'COM_WORKFLOW_BASIC_STAGE', '{}'), +(91, 18, 134, 135, 3, 'com_modules.transition.1', 'Publish', '{}'), +(92, 18, 136, 137, 3, 'com_modules.transition.2', 'Unpublish', '{}'), +(93, 18, 138, 139, 3, 'com_modules.transition.3', 'Trash', '{}'); -- -------------------------------------------------------- @@ -1095,7 +1095,7 @@ CREATE TABLE IF NOT EXISTS `#__workflows` ( INSERT INTO `#__workflows` (`id`, `asset_id`, `published`, `title`, `description`, `extension`, `default`, `ordering`, `created`, `created_by`, `modified`, `modified_by`) VALUES (1, 56, 1, 'COM_WORKFLOW_BASIC_WORKFLOW', '', 'com_content.article', 1, 1, CURRENT_TIMESTAMP(), 42, CURRENT_TIMESTAMP(), 42), -(2, 89, 1, 'COM_WORKFLOW_BASIC_WORKFLOW', '', 'com_modules.module', 1, 1, CURRENT_TIMESTAMP(), 42, CURRENT_TIMESTAMP(), 42); +(2, 89, 1, 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '', 'com_modules.module', 1, 1, CURRENT_TIMESTAMP(), 42, CURRENT_TIMESTAMP(), 42); -- -------------------------------------------------------- diff --git a/installation/sql/postgresql/base.sql b/installation/sql/postgresql/base.sql index 5feaaca36a368..bc979ce7a8cb1 100644 --- a/installation/sql/postgresql/base.sql +++ b/installation/sql/postgresql/base.sql @@ -31,7 +31,7 @@ COMMENT ON COLUMN "#__assets"."rules" IS 'JSON encoded access control.'; -- INSERT INTO "#__assets" ("id", "parent_id", "lft", "rgt", "level", "name", "title", "rules") VALUES -(1, 0, 0, 165, 0, 'root.1', 'Root Asset', '{"core.login.site":{"6":1,"2":1},"core.login.admin":{"6":1},"core.login.api":{"8":1},"core.login.offline":{"6":1},"core.admin":{"8":1},"core.manage":{"7":1},"core.create":{"6":1,"3":1},"core.delete":{"6":1},"core.edit":{"6":1,"4":1},"core.edit.state":{"6":1,"5":1},"core.edit.own":{"6":1,"3":1}}'), +(1, 0, 0, 175, 0, 'root.1', 'Root Asset', '{"core.login.site":{"6":1,"2":1},"core.login.admin":{"6":1},"core.login.api":{"8":1},"core.login.offline":{"6":1},"core.admin":{"8":1},"core.manage":{"7":1},"core.create":{"6":1,"3":1},"core.delete":{"6":1},"core.edit":{"6":1,"4":1},"core.edit.state":{"6":1,"5":1},"core.edit.own":{"6":1,"3":1}}'), (2, 1, 1, 2, 1, 'com_admin', 'com_admin', '{}'), (3, 1, 3, 6, 1, 'com_banners', 'com_banners', '{"core.admin":{"7":1},"core.manage":{"6":1}}'), (4, 1, 7, 8, 1, 'com_cache', 'com_cache', '{"core.admin":{"7":1},"core.manage":{"7":1}}'), @@ -114,11 +114,12 @@ INSERT INTO "#__assets" ("id", "parent_id", "lft", "rgt", "level", "name", "titl (88, 18, 126, 127, 2, 'com_modules.module.98', 'Logged-in Users', '{}'), (89, 18, 128, 129, 2, 'com_modules.module.90', 'Login Support', '{}'), (90, 1, 173, 174, 1, 'com_scheduler', 'com_scheduler', '{}'); -(91, 8, 130, 131, 2, 'com_modules.workflow.1', 'COM_WORKFLOW_BASIC_WORKFLOW', '{}'), -(92, 18, 132, 133, 3, 'com_modules.state.1', 'COM_WORKFLOW_BASIC_STAGE', '{}'), -(93, 18, 134, 135, 3, 'com_modules.transition.1', 'Publish', '{}'), -(94, 18, 136, 137, 3, 'com_modules.transition.2', 'Unpublish', '{}'), -(95, 18, 138, 139, 3, 'com_modules.transition.3', 'Trash', '{}'); +(89, 8, 130, 131, 2, 'com_modules.workflow.1', 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '{}'), +(90, 18, 132, 133, 3, 'com_modules.state.1', 'COM_WORKFLOW_BASIC_STAGE', '{}'), +(91, 18, 134, 135, 3, 'com_modules.transition.1', 'Publish', '{}'), +(92, 18, 136, 137, 3, 'com_modules.transition.2', 'Unpublish', '{}'), +(93, 18, 138, 139, 3, 'com_modules.transition.3', 'Trash', '{}'); + SELECT setval('#__assets_id_seq', 91, false); @@ -1117,7 +1118,7 @@ CREATE INDEX "#__workflows_idx_checked_out" ON "#__workflows" ("checked_out"); INSERT INTO "#__workflows" ("id", "asset_id", "published", "title", "description", "extension", "default", "ordering", "created", "created_by", "modified", "modified_by") VALUES (1, 56, 1, 'COM_WORKFLOW_BASIC_WORKFLOW', '', 'com_content.article', 1, 1, CURRENT_TIMESTAMP, 42, CURRENT_TIMESTAMP, 42), -(2, 89, 1, 'COM_WORKFLOW_BASIC_WORKFLOW', '', 'com_modules.module', 1, 1, CURRENT_TIMESTAMP, 42, CURRENT_TIMESTAMP, 42); +(2, 89, 1, 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '', 'com_modules.module', 1, 1, CURRENT_TIMESTAMP, 42, CURRENT_TIMESTAMP, 42); SELECT setval('#__workflows_id_seq', 2, false); From 61578c9f19353fb1fd5d2a5cb2a3b5da4d4ee625 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Tue, 27 Jul 2021 18:53:22 +0530 Subject: [PATCH 27/85] rephrase workflows to workflow --- .../com_modules/forms/moduleadmin.xml | 19 +++++++++++++++++++ administrator/language/en-GB/com_modules.ini | 1 - 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/administrator/components/com_modules/forms/moduleadmin.xml b/administrator/components/com_modules/forms/moduleadmin.xml index 4f2b7efa84e93..565e1d6f99499 100644 --- a/administrator/components/com_modules/forms/moduleadmin.xml +++ b/administrator/components/com_modules/forms/moduleadmin.xml @@ -142,4 +142,23 @@ validate="rules" /> + +
+ +
diff --git a/administrator/language/en-GB/com_modules.ini b/administrator/language/en-GB/com_modules.ini index 0160cc32bb9a4..3257dfecf22a7 100644 --- a/administrator/language/en-GB/com_modules.ini +++ b/administrator/language/en-GB/com_modules.ini @@ -194,7 +194,6 @@ COM_MODULES_TYPE_OR_SELECT_POSITION="Type or Select a Position" COM_MODULES_WORKFLOW="Workflow" COM_MODULES_WORKFLOW_NOT_FOUND="No default workflow available, please define one or contact an administrator." COM_MODULES_WORKFLOW_TRANSITION_NOT_ALLOWED="You're not allowed to execute this transition" -COM_MODULES_WORKFLOWS="Workflows" COM_MODULES_XML_DESCRIPTION="Component for module management in the Administrator Backend." JLIB_RULES_SETTING_NOTES_COM_MODULES="Changes apply to this component only.
Inherited - a Global Configuration setting or higher level setting is applied.
Denied always wins - whatever is set at the Global or higher level and applies to all child elements.
Allowed will enable the action for this component unless overruled by a Global Configuration setting." ; Alternate language strings for the rules form field From b3d7bf1605d5bd168365aece5c758d1bfe7c64f3 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Tue, 27 Jul 2021 18:54:03 +0530 Subject: [PATCH 28/85] filter extension in workflow field --- .../components/com_modules/forms/module.xml | 38 +++++++++---------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/administrator/components/com_modules/forms/module.xml b/administrator/components/com_modules/forms/module.xml index 5072371db8254..f88019bca0be1 100644 --- a/administrator/components/com_modules/forms/module.xml +++ b/administrator/components/com_modules/forms/module.xml @@ -149,24 +149,22 @@ /> - -
- -
-
+
+ +
From 2ad7590f6b896edad271fb8c247bd3b7855c44da Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Wed, 28 Jul 2021 23:11:30 +0530 Subject: [PATCH 29/85] return inital stage depending on workflow_id param --- .../com_modules/src/Model/ModuleModel.php | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/administrator/components/com_modules/src/Model/ModuleModel.php b/administrator/components/com_modules/src/Model/ModuleModel.php index c4a548c8335f0..6c5bc9e8e9e58 100644 --- a/administrator/components/com_modules/src/Model/ModuleModel.php +++ b/administrator/components/com_modules/src/Model/ModuleModel.php @@ -1187,7 +1187,7 @@ public function save($data) $this->setState('module.extension_id', $extensionId); $this->setState('module.id', $table->id); - $this->setState('module.new', $isNew);; + $this->setState('module.new', $isNew); $this->workflowAfterSave($data); @@ -1264,18 +1264,29 @@ protected function getStageForNewItem(Form $form, $data) { $db = $this->getDbo(); - // Query to find the default workflow id of the extension type com_modules.module - $defaultWorkflowQuery = $db->getQuery(true) - ->select($db->quoteName('id')) - ->from($db->quoteName('#__workflows')) - ->where($db->quoteName('default') . ' = 1') - ->where($db->quoteName('extension') . ' = "com_modules.module"'); - $query = $db->getQuery(true) ->select($db->quoteName('id')) ->from($db->quoteName('#__workflow_stages')) - ->where($db->quoteName('default') . '= 1') - ->where($db->quoteName('workflow_id') . ' IN (' . $defaultWorkflowQuery . ')'); + ->where($db->quoteName('default') . '= 1'); + + if (isset($data['workflow_id'])) + { + // If workflow_id is set by the query then we find the stage corresponding to that workflow_id + $query->where($db->quoteName('workflow_id') . ' = :workflowid') + ->bind(':workflowid', $data['workflow_id'], ParameterType::INTEGER); + } + else + { + // Query to find the default workflow id of the extension type com_modules.module + $defaultWorkflowQuery = $db->getQuery(true) + ->select($db->quoteName('id')) + ->from($db->quoteName('#__workflows')) + ->where($db->quoteName('default') . ' = 1') + ->where($db->quoteName('extension') . ' = "com_modules.module"'); + + $query->where($db->quoteName('workflow_id') . ' IN (' . $defaultWorkflowQuery . ')'); + } + $db->setQuery($query); $defaultStage = $db->loadResult(); From 1c3ad7682e7cd2e18a2c2006c5c741c9bf1f601f Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Wed, 28 Jul 2021 23:12:09 +0530 Subject: [PATCH 30/85] display workflow field for new modules and transition for editing existing ones --- administrator/components/com_modules/tmpl/module/edit.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/administrator/components/com_modules/tmpl/module/edit.php b/administrator/components/com_modules/tmpl/module/edit.php index 38d8c58da144a..2b1948c3643bc 100644 --- a/administrator/components/com_modules/tmpl/module/edit.php +++ b/administrator/components/com_modules/tmpl/module/edit.php @@ -50,6 +50,9 @@ $layout = $isModal ? 'modal' : 'edit'; $tmpl = $isModal || $input->get('tmpl', '', 'cmd') === 'component' ? '&tmpl=component' : ''; +// If the module is already created then display the transition field else display the workflow selection field +$workflowField = empty($input->get('id')) ? 'workflow_id' : 'transition'; + ?>
@@ -134,7 +137,7 @@ fields = array( - 'transition', + $workflowField, 'showtitle', 'position', 'published', @@ -179,7 +182,7 @@ fieldsets = array(); - $this->ignore_fieldsets = array('basic', 'description'); + $this->ignore_fieldsets = array('basic', 'description', 'workflow'); echo LayoutHelper::render('joomla.edit.params', $this); ?> From cf23886368971dea22a3f762195998cc7345bf47 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Wed, 28 Jul 2021 23:12:43 +0530 Subject: [PATCH 31/85] Remove transition field for new modules --- libraries/src/MVC/Model/WorkflowBehaviorTrait.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php index 5418a1dc6f582..da2af397f6dc6 100644 --- a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php +++ b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php @@ -364,12 +364,7 @@ protected function addTransitionField(Form $form, $data) } else { - $stage_id = $this->getStageForNewItem($form, $data); - - if (!empty($stage_id)) - { - $form->setFieldAttribute('transition', 'workflow_stage', (int) $stage_id); - } + $form->removeField('transition'); } } From 82135ca30166f86c9f931e1648690607fd0c9db9 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Thu, 29 Jul 2021 14:33:49 +0530 Subject: [PATCH 32/85] make transition_ids camelcase --- administrator/components/com_modules/tmpl/modules/default.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/administrator/components/com_modules/tmpl/modules/default.php b/administrator/components/com_modules/tmpl/modules/default.php index cff0a19b2dcca..1524583895364 100644 --- a/administrator/components/com_modules/tmpl/modules/default.php +++ b/administrator/components/com_modules/tmpl/modules/default.php @@ -139,8 +139,8 @@ { $transitions = ContentHelper::filterTransitions($this->transitions, (int) $item->stage_id, (int) $item->workflow_id); - $transition_ids = ArrayHelper::getColumn($transitions, 'value'); - $transition_ids = ArrayHelper::toInteger($transition_ids); + $transitionIds = ArrayHelper::getColumn($transitions, 'value'); + $transitionIds = ArrayHelper::toInteger($transitionIds); } ?> From 8465dd3634fd666be8a39a1816e008570581fbc4 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Thu, 29 Jul 2021 14:51:13 +0530 Subject: [PATCH 33/85] camel casing --- .../com_modules/src/Model/ModulesModel.php | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/administrator/components/com_modules/src/Model/ModulesModel.php b/administrator/components/com_modules/src/Model/ModulesModel.php index a1930a775a532..cf0142e377bc9 100644 --- a/administrator/components/com_modules/src/Model/ModulesModel.php +++ b/administrator/components/com_modules/src/Model/ModulesModel.php @@ -549,19 +549,19 @@ public function getTransitions() return false; } - $stage_ids = ArrayHelper::getColumn($items, 'stage_id'); - $stage_ids = ArrayHelper::toInteger($stage_ids); - $stage_ids = array_values(array_unique(array_filter($stage_ids))); + $stageIds = ArrayHelper::getColumn($items, 'stage_id'); + $stageIds = ArrayHelper::toInteger($stageIds); + $stageIds = array_values(array_unique(array_filter($stageIds))); - $workflow_ids = ArrayHelper::getColumn($items, 'workflow_id'); - $workflow_ids = ArrayHelper::toInteger($workflow_ids); - $workflow_ids = array_values(array_unique(array_filter($workflow_ids))); + $workflowIds = ArrayHelper::getColumn($items, 'workflow_id'); + $workflowIds = ArrayHelper::toInteger($workflowIds); + $workflowIds = array_values(array_unique(array_filter($workflowIds))); $this->cache[$store] = array(); try { - if (count($stage_ids) || count($workflow_ids)) + if (count($stageIds) || count($workflowIds)) { Factory::getLanguage()->load('com_workflow', JPATH_ADMINISTRATOR); @@ -593,14 +593,14 @@ public function getTransitions() $where = []; - if (count($stage_ids)) + if (count($stageIds)) { - $where[] = $db->quoteName('t.from_stage_id') . ' IN (' . implode(',', $query->bindArray($stage_ids)) . ')'; + $where[] = $db->quoteName('t.from_stage_id') . ' IN (' . implode(',', $query->bindArray($stageIds)) . ')'; } - if (count($workflow_ids)) + if (count($workflowIds)) { - $where[] = '(' . $db->quoteName('t.from_stage_id') . ' = -1 AND ' . $db->quoteName('t.workflow_id') . ' IN (' . implode(',', $query->bindArray($workflow_ids)) . '))'; + $where[] = '(' . $db->quoteName('t.from_stage_id') . ' = -1 AND ' . $db->quoteName('t.workflow_id') . ' IN (' . implode(',', $query->bindArray($workflowIds)) . '))'; } $query->where('((' . implode(') OR (', $where) . '))'); From f4be1787530907d185c6bfff061b42f9c0e36fcd Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Thu, 29 Jul 2021 20:52:26 +0530 Subject: [PATCH 34/85] revert changes to library function --- libraries/src/MVC/Model/WorkflowBehaviorTrait.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php index da2af397f6dc6..5418a1dc6f582 100644 --- a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php +++ b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php @@ -364,7 +364,12 @@ protected function addTransitionField(Form $form, $data) } else { - $form->removeField('transition'); + $stage_id = $this->getStageForNewItem($form, $data); + + if (!empty($stage_id)) + { + $form->setFieldAttribute('transition', 'workflow_stage', (int) $stage_id); + } } } From eff4c8f34e6e1c684021d238edb96813b38eca6c Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Thu, 29 Jul 2021 20:52:56 +0530 Subject: [PATCH 35/85] improve the logic for conditionally adding transition field --- .../com_modules/src/Model/ModuleModel.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/administrator/components/com_modules/src/Model/ModuleModel.php b/administrator/components/com_modules/src/Model/ModuleModel.php index 6c5bc9e8e9e58..97c34b3660083 100644 --- a/administrator/components/com_modules/src/Model/ModuleModel.php +++ b/administrator/components/com_modules/src/Model/ModuleModel.php @@ -961,7 +961,22 @@ protected function preprocessForm(Form $form, $data, $group = 'content') } } } - $this->workflowPreprocessForm($form, $data); + + if (ComponentHelper::getParams('com_modules')->get('workflow_enabled')) + { + // The workflowPreprocessForm function enables the workflow plugins and adds the transition field + // to the form. We do not need to add the transition field to the form in the case of new + // items so we seperately call the importWorkflowPlugins function. + if (!empty(Factory::getApplication()->input->get('id'))) + { + $this->workflowPreprocessForm($form, $data); + } + else + { + // Import the workflow plugin group to allow form manipulation. + $this->importWorkflowPlugins(); + } + } // Trigger the default form events. parent::preprocessForm($form, $data, $group); From 4cecc7bae88548233273a156072f2b72bf60c91f Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Thu, 29 Jul 2021 21:27:22 +0530 Subject: [PATCH 36/85] phpcs --- .../components/com_modules/src/Model/ModuleModel.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/administrator/components/com_modules/src/Model/ModuleModel.php b/administrator/components/com_modules/src/Model/ModuleModel.php index 97c34b3660083..f90392412ca43 100644 --- a/administrator/components/com_modules/src/Model/ModuleModel.php +++ b/administrator/components/com_modules/src/Model/ModuleModel.php @@ -964,9 +964,11 @@ protected function preprocessForm(Form $form, $data, $group = 'content') if (ComponentHelper::getParams('com_modules')->get('workflow_enabled')) { - // The workflowPreprocessForm function enables the workflow plugins and adds the transition field - // to the form. We do not need to add the transition field to the form in the case of new - // items so we seperately call the importWorkflowPlugins function. + /** + * The workflowPreprocessForm function enables the workflow plugins and adds the + * transition field to the form. We do not need to add the transition field to the + * form in the case of items so we seperately call the importWorkflowPlugins function. + */ if (!empty(Factory::getApplication()->input->get('id'))) { $this->workflowPreprocessForm($form, $data); From 00a6708ebbb935137854782ad22396c19be387fa Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Thu, 29 Jul 2021 23:11:52 +0530 Subject: [PATCH 37/85] Load Language file for workflows --- administrator/components/com_modules/src/Model/ModuleModel.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/administrator/components/com_modules/src/Model/ModuleModel.php b/administrator/components/com_modules/src/Model/ModuleModel.php index f90392412ca43..ad01e08f3c54a 100644 --- a/administrator/components/com_modules/src/Model/ModuleModel.php +++ b/administrator/components/com_modules/src/Model/ModuleModel.php @@ -964,6 +964,8 @@ protected function preprocessForm(Form $form, $data, $group = 'content') if (ComponentHelper::getParams('com_modules')->get('workflow_enabled')) { + Factory::getLanguage()->load('com_workflow', JPATH_ADMINISTRATOR); + /** * The workflowPreprocessForm function enables the workflow plugins and adds the * transition field to the form. We do not need to add the transition field to the From 3d7c0a3cd647e5f1e4e5952ede5a0827def36b77 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Fri, 30 Jul 2021 15:24:52 +0530 Subject: [PATCH 38/85] correct the name of default module workflow --- installation/sql/mysql/base.sql | 2 +- installation/sql/postgresql/base.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/installation/sql/mysql/base.sql b/installation/sql/mysql/base.sql index 73858ff72dba5..d0662f3952bc6 100644 --- a/installation/sql/mysql/base.sql +++ b/installation/sql/mysql/base.sql @@ -1145,7 +1145,7 @@ CREATE TABLE IF NOT EXISTS `#__workflow_stages` ( INSERT INTO `#__workflow_stages` (`id`, `asset_id`, `ordering`, `workflow_id`, `published`, `title`, `description`, `default`) VALUES (1, 0, 1, 1, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1), -(2, 18, 1, 2, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1); +(2, 18, 1, 2, 1, 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '', 1); -- -------------------------------------------------------- diff --git a/installation/sql/postgresql/base.sql b/installation/sql/postgresql/base.sql index bc979ce7a8cb1..60d37c59bc25a 100644 --- a/installation/sql/postgresql/base.sql +++ b/installation/sql/postgresql/base.sql @@ -1169,7 +1169,7 @@ CREATE INDEX "#__workflow_stages_idx_checked_out" ON "#__workflow_stages" ("chec INSERT INTO "#__workflow_stages" ("id", "asset_id", "ordering", "workflow_id", "published", "title", "description", "default") VALUES (1, 57, 1, 1, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1), -(2, 90, 1, 2, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1); +(2, 90, 1, 2, 1, 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '', 1); SELECT setval('#__workflow_stages_id_seq', 2, false); From 4a69c3c4488acf751ecb7662d1e027ac72d71be2 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Fri, 30 Jul 2021 23:13:06 +0530 Subject: [PATCH 39/85] workflow update sql script --- .../sql/updates/mysql/4.1.0-2021-07-30.sql | 41 +++++++++++++++++++ .../updates/postgresql/4.1.0-2021-07-30.sql | 41 +++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 administrator/components/com_admin/sql/updates/mysql/4.1.0-2021-07-30.sql create mode 100644 administrator/components/com_admin/sql/updates/postgresql/4.1.0-2021-07-30.sql diff --git a/administrator/components/com_admin/sql/updates/mysql/4.1.0-2021-07-30.sql b/administrator/components/com_admin/sql/updates/mysql/4.1.0-2021-07-30.sql new file mode 100644 index 0000000000000..cbc91f69ba46f --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/4.1.0-2021-07-30.sql @@ -0,0 +1,41 @@ +-- +-- Insert a new workflow for com_modules +-- +INSERT INTO `#__workflows` (`id`, `asset_id`, `published`, `title`, `description`, `extension`, `default`, `ordering`, `created`, `created_by`, `modified`, `modified_by`, `checked_out_time`, `checked_out`) VALUES +(NULL, 0, 1, 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '', 'com_modules.module', 1, 1, CURRENT_TIMESTAMP(), 0, CURRENT_TIMESTAMP(), 0, NULL, 0); + +-- +-- Inserting the default stage for the new worklfow +-- +INSERT INTO `#__workflow_stages` (`id`, `asset_id`, `ordering`, `workflow_id`, `published`, `title`, `description`, `default`, `checked_out_time`, `checked_out`) +SELECT NULL, 0, 1, `id`, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1, NULL, 0 FROM `#__workflows` WHERE `title` = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES'; + +-- +-- Inserting the default stage for the new worklfow +-- +INSERT INTO `#__workflow_stages` (`id`, `asset_id`, `ordering`, `workflow_id`, `published`, `title`, `description`, `default`, `checked_out_time`, `checked_out`) +SELECT NULL, 0, 1, `id`, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1, NULL, 0 FROM `#__workflows` WHERE `title` = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES'; + +-- +-- Inserting the transitions for the new worklfow +-- +INSERT INTO `#__workflow_transitions` (`id`, `asset_id`, `published`, `ordering`, `workflow_id`, `title`, `description`, `from_stage_id`, `to_stage_id`, `options`) +SELECT NULL, 0, 1, NULL, `w`.`id`, 'Unpublish', '', -1, `s`.`id`, '{"publishing":"0"}' FROM `#__workflows` as `w` INNER JOIN `#__workflow_stages` as `s` ON `w`.`title` = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES' AND `s`.`title` = 'COM_WORKFLOW_BASIC_STAGE' AND `s`.`extension` = 'com_modules.module'; + +INSERT INTO `#__workflow_transitions` (`id`, `asset_id`, `published`, `ordering`, `workflow_id`, `title`, `description`, `from_stage_id`, `to_stage_id`, `options`) +SELECT NULL, 0, 1, NULL, `w`.`id`, 'Publish', '', -1, `s`.`id`, '{"publishing":"1"}' FROM `#__workflows` as `w` INNER JOIN `#__workflow_stages` as `s` ON `w`.`title` = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES' AND `s`.`title` = 'COM_WORKFLOW_BASIC_STAGE' AND `s`.`extension` = 'com_modules.module'; + +INSERT INTO `#__workflow_transitions` (`id`, `asset_id`, `published`, `ordering`, `workflow_id`, `title`, `description`, `from_stage_id`, `to_stage_id`, `options`) +SELECT NULL, 0, 1, NULL, `w`.`id`, 'Trash', '', -1, `s`.`id`, '{"publishing":"-2"}' FROM `#__workflows` as `w` INNER JOIN `#__workflow_stages` as `s` ON `w`.`title` = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES' AND `s`.`title` = 'COM_WORKFLOW_BASIC_STAGE' AND `s`.`workflow_id` = `w`.`id`; + +-- +-- Creating Associations for existing modules +-- +INSERT INTO `#__workflow_associations` (`item_id`, `stage_id`, `extension`) +SELECT `m`.`id`, `s`.`id`, 'com_modules.module' +FROM `#__modules` as `m` , +(`#__workflow_stages` as `s` + INNER JOIN `#__workflows` as `w` + ON `w`.`title` = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES' + AND `s`.`title` = 'COM_WORKFLOW_BASIC_STAGE' + AND `s`.`workflow_id` = `w`.`id`); \ No newline at end of file diff --git a/administrator/components/com_admin/sql/updates/postgresql/4.1.0-2021-07-30.sql b/administrator/components/com_admin/sql/updates/postgresql/4.1.0-2021-07-30.sql new file mode 100644 index 0000000000000..cbc91f69ba46f --- /dev/null +++ b/administrator/components/com_admin/sql/updates/postgresql/4.1.0-2021-07-30.sql @@ -0,0 +1,41 @@ +-- +-- Insert a new workflow for com_modules +-- +INSERT INTO `#__workflows` (`id`, `asset_id`, `published`, `title`, `description`, `extension`, `default`, `ordering`, `created`, `created_by`, `modified`, `modified_by`, `checked_out_time`, `checked_out`) VALUES +(NULL, 0, 1, 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '', 'com_modules.module', 1, 1, CURRENT_TIMESTAMP(), 0, CURRENT_TIMESTAMP(), 0, NULL, 0); + +-- +-- Inserting the default stage for the new worklfow +-- +INSERT INTO `#__workflow_stages` (`id`, `asset_id`, `ordering`, `workflow_id`, `published`, `title`, `description`, `default`, `checked_out_time`, `checked_out`) +SELECT NULL, 0, 1, `id`, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1, NULL, 0 FROM `#__workflows` WHERE `title` = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES'; + +-- +-- Inserting the default stage for the new worklfow +-- +INSERT INTO `#__workflow_stages` (`id`, `asset_id`, `ordering`, `workflow_id`, `published`, `title`, `description`, `default`, `checked_out_time`, `checked_out`) +SELECT NULL, 0, 1, `id`, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1, NULL, 0 FROM `#__workflows` WHERE `title` = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES'; + +-- +-- Inserting the transitions for the new worklfow +-- +INSERT INTO `#__workflow_transitions` (`id`, `asset_id`, `published`, `ordering`, `workflow_id`, `title`, `description`, `from_stage_id`, `to_stage_id`, `options`) +SELECT NULL, 0, 1, NULL, `w`.`id`, 'Unpublish', '', -1, `s`.`id`, '{"publishing":"0"}' FROM `#__workflows` as `w` INNER JOIN `#__workflow_stages` as `s` ON `w`.`title` = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES' AND `s`.`title` = 'COM_WORKFLOW_BASIC_STAGE' AND `s`.`extension` = 'com_modules.module'; + +INSERT INTO `#__workflow_transitions` (`id`, `asset_id`, `published`, `ordering`, `workflow_id`, `title`, `description`, `from_stage_id`, `to_stage_id`, `options`) +SELECT NULL, 0, 1, NULL, `w`.`id`, 'Publish', '', -1, `s`.`id`, '{"publishing":"1"}' FROM `#__workflows` as `w` INNER JOIN `#__workflow_stages` as `s` ON `w`.`title` = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES' AND `s`.`title` = 'COM_WORKFLOW_BASIC_STAGE' AND `s`.`extension` = 'com_modules.module'; + +INSERT INTO `#__workflow_transitions` (`id`, `asset_id`, `published`, `ordering`, `workflow_id`, `title`, `description`, `from_stage_id`, `to_stage_id`, `options`) +SELECT NULL, 0, 1, NULL, `w`.`id`, 'Trash', '', -1, `s`.`id`, '{"publishing":"-2"}' FROM `#__workflows` as `w` INNER JOIN `#__workflow_stages` as `s` ON `w`.`title` = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES' AND `s`.`title` = 'COM_WORKFLOW_BASIC_STAGE' AND `s`.`workflow_id` = `w`.`id`; + +-- +-- Creating Associations for existing modules +-- +INSERT INTO `#__workflow_associations` (`item_id`, `stage_id`, `extension`) +SELECT `m`.`id`, `s`.`id`, 'com_modules.module' +FROM `#__modules` as `m` , +(`#__workflow_stages` as `s` + INNER JOIN `#__workflows` as `w` + ON `w`.`title` = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES' + AND `s`.`title` = 'COM_WORKFLOW_BASIC_STAGE' + AND `s`.`workflow_id` = `w`.`id`); \ No newline at end of file From d47849a469dbd7cbcb8c3679eaf85f0b155bd89a Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Sat, 31 Jul 2021 00:02:27 +0530 Subject: [PATCH 40/85] fix parent id for modules workflow asset --- installation/sql/mysql/base.sql | 2 +- installation/sql/postgresql/base.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/installation/sql/mysql/base.sql b/installation/sql/mysql/base.sql index d0662f3952bc6..784864c59ec77 100644 --- a/installation/sql/mysql/base.sql +++ b/installation/sql/mysql/base.sql @@ -108,7 +108,7 @@ INSERT INTO `#__assets` (`id`, `parent_id`, `lft`, `rgt`, `level`, `name`, `titl (88, 18, 126, 127, 2, 'com_modules.module.98', 'Logged-in Users', '{}'), (89, 18, 128, 129, 2, 'com_modules.module.90', 'Login Support', '{}'), (90, 1, 173, 174, 1, 'com_scheduler', 'com_scheduler', '{}'); -(89, 8, 130, 131, 2, 'com_modules.workflow.1', 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '{}'), +(89, 18, 130, 131, 2, 'com_modules.workflow.1', 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '{}'), (90, 18, 132, 133, 3, 'com_modules.state.1', 'COM_WORKFLOW_BASIC_STAGE', '{}'), (91, 18, 134, 135, 3, 'com_modules.transition.1', 'Publish', '{}'), (92, 18, 136, 137, 3, 'com_modules.transition.2', 'Unpublish', '{}'), diff --git a/installation/sql/postgresql/base.sql b/installation/sql/postgresql/base.sql index 60d37c59bc25a..19df171fe5417 100644 --- a/installation/sql/postgresql/base.sql +++ b/installation/sql/postgresql/base.sql @@ -114,7 +114,7 @@ INSERT INTO "#__assets" ("id", "parent_id", "lft", "rgt", "level", "name", "titl (88, 18, 126, 127, 2, 'com_modules.module.98', 'Logged-in Users', '{}'), (89, 18, 128, 129, 2, 'com_modules.module.90', 'Login Support', '{}'), (90, 1, 173, 174, 1, 'com_scheduler', 'com_scheduler', '{}'); -(89, 8, 130, 131, 2, 'com_modules.workflow.1', 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '{}'), +(89, 18, 130, 131, 2, 'com_modules.workflow.1', 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '{}'), (90, 18, 132, 133, 3, 'com_modules.state.1', 'COM_WORKFLOW_BASIC_STAGE', '{}'), (91, 18, 134, 135, 3, 'com_modules.transition.1', 'Publish', '{}'), (92, 18, 136, 137, 3, 'com_modules.transition.2', 'Unpublish', '{}'), From b9f1350e661076f0ad4e10b6f4c59710f37c8573 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Sat, 31 Jul 2021 00:06:10 +0530 Subject: [PATCH 41/85] remove backticks for postgresql --- installation/sql/postgresql/base.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/installation/sql/postgresql/base.sql b/installation/sql/postgresql/base.sql index 19df171fe5417..d4fb8081560c9 100644 --- a/installation/sql/postgresql/base.sql +++ b/installation/sql/postgresql/base.sql @@ -1213,5 +1213,5 @@ INSERT INTO "#__workflow_transitions" ("id", "asset_id", "published", "ordering" SELECT setval('#__workflow_transitions_id_seq', 8, false); -INSERT INTO `#__workflow_associations` (`item_id`, `stage_id`, `extension`) -SELECT `id`, 2, 'com_modules.module' FROM `#__modules`; \ No newline at end of file +INSERT INTO "#__workflow_associations" ("item_id", "stage_id", "extension") +SELECT "id", 2, 'com_modules.module' FROM "#__modules"; \ No newline at end of file From 9f8b6d77eed3dc7c556c5938f46d692f55dded8d Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Sat, 31 Jul 2021 00:08:37 +0530 Subject: [PATCH 42/85] replace backticks by quotes in postgresql update --- .../updates/postgresql/4.1.0-2021-07-30.sql | 32 ++++++++----------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/administrator/components/com_admin/sql/updates/postgresql/4.1.0-2021-07-30.sql b/administrator/components/com_admin/sql/updates/postgresql/4.1.0-2021-07-30.sql index cbc91f69ba46f..e7f755e2cc033 100644 --- a/administrator/components/com_admin/sql/updates/postgresql/4.1.0-2021-07-30.sql +++ b/administrator/components/com_admin/sql/updates/postgresql/4.1.0-2021-07-30.sql @@ -1,41 +1,35 @@ -- -- Insert a new workflow for com_modules -- -INSERT INTO `#__workflows` (`id`, `asset_id`, `published`, `title`, `description`, `extension`, `default`, `ordering`, `created`, `created_by`, `modified`, `modified_by`, `checked_out_time`, `checked_out`) VALUES +INSERT INTO "#__workflows" ("id", "asset_id", "published", "title", "description", "extension", "default", "ordering", "created", "created_by", "modified", "modified_by", "checked_out_time", "checked_out") VALUES (NULL, 0, 1, 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '', 'com_modules.module', 1, 1, CURRENT_TIMESTAMP(), 0, CURRENT_TIMESTAMP(), 0, NULL, 0); -- -- Inserting the default stage for the new worklfow -- -INSERT INTO `#__workflow_stages` (`id`, `asset_id`, `ordering`, `workflow_id`, `published`, `title`, `description`, `default`, `checked_out_time`, `checked_out`) -SELECT NULL, 0, 1, `id`, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1, NULL, 0 FROM `#__workflows` WHERE `title` = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES'; +INSERT INTO "#__workflow_stages" ("id", "asset_id", "ordering", "workflow_id", "published", "title", "description", "default", "checked_out_time", "checked_out") +SELECT NULL, 0, 1, "id", 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1, NULL, 0 FROM "#__workflows" WHERE "title" = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES'; -- -- Inserting the default stage for the new worklfow -- -INSERT INTO `#__workflow_stages` (`id`, `asset_id`, `ordering`, `workflow_id`, `published`, `title`, `description`, `default`, `checked_out_time`, `checked_out`) -SELECT NULL, 0, 1, `id`, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1, NULL, 0 FROM `#__workflows` WHERE `title` = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES'; +INSERT INTO "#__workflow_stages" ("id", "asset_id", "ordering", "workflow_id", "published", "title", "description", "default", "checked_out_time", "checked_out") +SELECT NULL, 0, 1, "id", 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1, NULL, 0 FROM "#__workflows" WHERE "title" = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES'; -- -- Inserting the transitions for the new worklfow -- -INSERT INTO `#__workflow_transitions` (`id`, `asset_id`, `published`, `ordering`, `workflow_id`, `title`, `description`, `from_stage_id`, `to_stage_id`, `options`) -SELECT NULL, 0, 1, NULL, `w`.`id`, 'Unpublish', '', -1, `s`.`id`, '{"publishing":"0"}' FROM `#__workflows` as `w` INNER JOIN `#__workflow_stages` as `s` ON `w`.`title` = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES' AND `s`.`title` = 'COM_WORKFLOW_BASIC_STAGE' AND `s`.`extension` = 'com_modules.module'; +INSERT INTO "#__workflow_transitions" ("id", "asset_id", "published", "ordering", "workflow_id", "title", "description", "from_stage_id", "to_stage_id", "options") +SELECT NULL, 0, 1, NULL, "w"."id", 'Unpublish', '', -1, "s"."id", '{"publishing":"0"}' FROM "#__workflows" as "w" INNER JOIN "#__workflow_stages" as "s" ON "w"."title" = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES' AND "s"."title" = 'COM_WORKFLOW_BASIC_STAGE' AND "s"."extension" = 'com_modules.module'; -INSERT INTO `#__workflow_transitions` (`id`, `asset_id`, `published`, `ordering`, `workflow_id`, `title`, `description`, `from_stage_id`, `to_stage_id`, `options`) -SELECT NULL, 0, 1, NULL, `w`.`id`, 'Publish', '', -1, `s`.`id`, '{"publishing":"1"}' FROM `#__workflows` as `w` INNER JOIN `#__workflow_stages` as `s` ON `w`.`title` = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES' AND `s`.`title` = 'COM_WORKFLOW_BASIC_STAGE' AND `s`.`extension` = 'com_modules.module'; +INSERT INTO "#__workflow_transitions" ("id", "asset_id", "published", "ordering", "workflow_id", "title", "description", "from_stage_id", "to_stage_id", "options") +SELECT NULL, 0, 1, NULL, "w"."id", 'Publish', '', -1, "s"."id", '{"publishing":"1"}' FROM "#__workflows" as "w" INNER JOIN "#__workflow_stages" as "s" ON "w"."title" = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES' AND "s"."title" = 'COM_WORKFLOW_BASIC_STAGE' AND "s"."extension" = 'com_modules.module'; -INSERT INTO `#__workflow_transitions` (`id`, `asset_id`, `published`, `ordering`, `workflow_id`, `title`, `description`, `from_stage_id`, `to_stage_id`, `options`) -SELECT NULL, 0, 1, NULL, `w`.`id`, 'Trash', '', -1, `s`.`id`, '{"publishing":"-2"}' FROM `#__workflows` as `w` INNER JOIN `#__workflow_stages` as `s` ON `w`.`title` = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES' AND `s`.`title` = 'COM_WORKFLOW_BASIC_STAGE' AND `s`.`workflow_id` = `w`.`id`; +INSERT INTO "#__workflow_transitions" ("id", "asset_id", "published", "ordering", "workflow_id", "title", "description", "from_stage_id", "to_stage_id", "options") +SELECT NULL, 0, 1, NULL, "w"."id", 'Trash', '', -1, "s"."id", '{"publishing":"-2"}' FROM "#__workflows" as "w" INNER JOIN "#__workflow_stages" as "s" ON "w"."title" = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES' AND "s"."title" = 'COM_WORKFLOW_BASIC_STAGE' AND "s"."workflow_id" = "w"."id"; -- -- Creating Associations for existing modules -- -INSERT INTO `#__workflow_associations` (`item_id`, `stage_id`, `extension`) -SELECT `m`.`id`, `s`.`id`, 'com_modules.module' -FROM `#__modules` as `m` , -(`#__workflow_stages` as `s` - INNER JOIN `#__workflows` as `w` - ON `w`.`title` = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES' - AND `s`.`title` = 'COM_WORKFLOW_BASIC_STAGE' - AND `s`.`workflow_id` = `w`.`id`); \ No newline at end of file +INSERT INTO "#__workflow_associations" ("item_id", "stage_id", "extension") +SELECT "m"."id", "s"."id", 'com_modules.module' FROM "#__modules" as "m" , ("#__workflow_stages" as "s" INNER JOIN "#__workflows" as "w" ON "w"."title" = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES' AND "s"."title" = 'COM_WORKFLOW_BASIC_STAGE' AND "s"."workflow_id" = "w"."id"); \ No newline at end of file From 87e5b266592e6532b84123897007b54f2ac2af04 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Sat, 31 Jul 2021 00:10:07 +0530 Subject: [PATCH 43/85] remove extra space and format the query --- .../com_admin/sql/updates/mysql/4.1.0-2021-07-30.sql | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/administrator/components/com_admin/sql/updates/mysql/4.1.0-2021-07-30.sql b/administrator/components/com_admin/sql/updates/mysql/4.1.0-2021-07-30.sql index cbc91f69ba46f..8ad97fbea0ef7 100644 --- a/administrator/components/com_admin/sql/updates/mysql/4.1.0-2021-07-30.sql +++ b/administrator/components/com_admin/sql/updates/mysql/4.1.0-2021-07-30.sql @@ -32,10 +32,4 @@ SELECT NULL, 0, 1, NULL, `w`.`id`, 'Trash', '', -1, `s`.`id`, '{"publishing":"-2 -- Creating Associations for existing modules -- INSERT INTO `#__workflow_associations` (`item_id`, `stage_id`, `extension`) -SELECT `m`.`id`, `s`.`id`, 'com_modules.module' -FROM `#__modules` as `m` , -(`#__workflow_stages` as `s` - INNER JOIN `#__workflows` as `w` - ON `w`.`title` = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES' - AND `s`.`title` = 'COM_WORKFLOW_BASIC_STAGE' - AND `s`.`workflow_id` = `w`.`id`); \ No newline at end of file +SELECT `m`.`id`, `s`.`id`, 'com_modules.module' FROM `#__modules` as `m` , (`#__workflow_stages` as `s` INNER JOIN `#__workflows` as `w` ON `w`.`title` = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES' AND `s`.`title` = 'COM_WORKFLOW_BASIC_STAGE' AND `s`.`workflow_id` = `w`.`id`); \ No newline at end of file From 65b86deea971b06860c55e2cf28816dea581961d Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Sat, 31 Jul 2021 00:52:36 +0530 Subject: [PATCH 44/85] improve readability --- .../com_admin/sql/updates/mysql/4.1.0-2021-07-30.sql | 10 +++++++++- .../sql/updates/postgresql/4.1.0-2021-07-30.sql | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/administrator/components/com_admin/sql/updates/mysql/4.1.0-2021-07-30.sql b/administrator/components/com_admin/sql/updates/mysql/4.1.0-2021-07-30.sql index 8ad97fbea0ef7..b17aa82e01ef1 100644 --- a/administrator/components/com_admin/sql/updates/mysql/4.1.0-2021-07-30.sql +++ b/administrator/components/com_admin/sql/updates/mysql/4.1.0-2021-07-30.sql @@ -32,4 +32,12 @@ SELECT NULL, 0, 1, NULL, `w`.`id`, 'Trash', '', -1, `s`.`id`, '{"publishing":"-2 -- Creating Associations for existing modules -- INSERT INTO `#__workflow_associations` (`item_id`, `stage_id`, `extension`) -SELECT `m`.`id`, `s`.`id`, 'com_modules.module' FROM `#__modules` as `m` , (`#__workflow_stages` as `s` INNER JOIN `#__workflows` as `w` ON `w`.`title` = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES' AND `s`.`title` = 'COM_WORKFLOW_BASIC_STAGE' AND `s`.`workflow_id` = `w`.`id`); \ No newline at end of file +SELECT `m`.`id`, `s`.`id`, 'com_modules.module' +FROM `#__modules` as `m` , +( + `#__workflow_stages` as `s` + INNER JOIN `#__workflows` as `w` + ON `w`.`title` = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES' + AND `s`.`title` = 'COM_WORKFLOW_BASIC_STAGE' + AND `s`.`workflow_id` = `w`.`id` +); \ No newline at end of file diff --git a/administrator/components/com_admin/sql/updates/postgresql/4.1.0-2021-07-30.sql b/administrator/components/com_admin/sql/updates/postgresql/4.1.0-2021-07-30.sql index e7f755e2cc033..014ac99c77b95 100644 --- a/administrator/components/com_admin/sql/updates/postgresql/4.1.0-2021-07-30.sql +++ b/administrator/components/com_admin/sql/updates/postgresql/4.1.0-2021-07-30.sql @@ -32,4 +32,12 @@ SELECT NULL, 0, 1, NULL, "w"."id", 'Trash', '', -1, "s"."id", '{"publishing":"-2 -- Creating Associations for existing modules -- INSERT INTO "#__workflow_associations" ("item_id", "stage_id", "extension") -SELECT "m"."id", "s"."id", 'com_modules.module' FROM "#__modules" as "m" , ("#__workflow_stages" as "s" INNER JOIN "#__workflows" as "w" ON "w"."title" = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES' AND "s"."title" = 'COM_WORKFLOW_BASIC_STAGE' AND "s"."workflow_id" = "w"."id"); \ No newline at end of file +SELECT "m"."id", "s"."id", 'com_modules.module' +FROM "#__modules" as "m", +( + "#__workflow_stages" as "s" + INNER JOIN "#__workflows" as "w" + ON "w"."title" = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES' + AND "s"."title" = 'COM_WORKFLOW_BASIC_STAGE' + AND "s"."workflow_id" = "w"."id" +); \ No newline at end of file From 682448a815d3b6253318f49b27cc9a108ce31497 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Sun, 1 Aug 2021 18:55:39 +0530 Subject: [PATCH 45/85] fix lft and rgt values of the assets --- installation/sql/mysql/base.sql | 8 ++++---- installation/sql/postgresql/base.sql | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/installation/sql/mysql/base.sql b/installation/sql/mysql/base.sql index 784864c59ec77..ca39adcbc0fce 100644 --- a/installation/sql/mysql/base.sql +++ b/installation/sql/mysql/base.sql @@ -109,10 +109,10 @@ INSERT INTO `#__assets` (`id`, `parent_id`, `lft`, `rgt`, `level`, `name`, `titl (89, 18, 128, 129, 2, 'com_modules.module.90', 'Login Support', '{}'), (90, 1, 173, 174, 1, 'com_scheduler', 'com_scheduler', '{}'); (89, 18, 130, 131, 2, 'com_modules.workflow.1', 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '{}'), -(90, 18, 132, 133, 3, 'com_modules.state.1', 'COM_WORKFLOW_BASIC_STAGE', '{}'), -(91, 18, 134, 135, 3, 'com_modules.transition.1', 'Publish', '{}'), -(92, 18, 136, 137, 3, 'com_modules.transition.2', 'Unpublish', '{}'), -(93, 18, 138, 139, 3, 'com_modules.transition.3', 'Trash', '{}'); +(90, 89, 132, 133, 3, 'com_modules.state.1', 'COM_WORKFLOW_BASIC_STAGE', '{}'), +(91, 89, 134, 135, 3, 'com_modules.transition.1', 'Publish', '{}'), +(92, 89, 136, 137, 3, 'com_modules.transition.2', 'Unpublish', '{}'), +(93, 89, 138, 139, 3, 'com_modules.transition.3', 'Trash', '{}'); -- -------------------------------------------------------- diff --git a/installation/sql/postgresql/base.sql b/installation/sql/postgresql/base.sql index d4fb8081560c9..a494920de0fc0 100644 --- a/installation/sql/postgresql/base.sql +++ b/installation/sql/postgresql/base.sql @@ -115,10 +115,10 @@ INSERT INTO "#__assets" ("id", "parent_id", "lft", "rgt", "level", "name", "titl (89, 18, 128, 129, 2, 'com_modules.module.90', 'Login Support', '{}'), (90, 1, 173, 174, 1, 'com_scheduler', 'com_scheduler', '{}'); (89, 18, 130, 131, 2, 'com_modules.workflow.1', 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '{}'), -(90, 18, 132, 133, 3, 'com_modules.state.1', 'COM_WORKFLOW_BASIC_STAGE', '{}'), -(91, 18, 134, 135, 3, 'com_modules.transition.1', 'Publish', '{}'), -(92, 18, 136, 137, 3, 'com_modules.transition.2', 'Unpublish', '{}'), -(93, 18, 138, 139, 3, 'com_modules.transition.3', 'Trash', '{}'); +(90, 89, 132, 133, 3, 'com_modules.state.1', 'COM_WORKFLOW_BASIC_STAGE', '{}'), +(91, 89, 134, 135, 3, 'com_modules.transition.1', 'Publish', '{}'), +(92, 89, 136, 137, 3, 'com_modules.transition.2', 'Unpublish', '{}'), +(93, 89, 138, 139, 3, 'com_modules.transition.3', 'Trash', '{}'); SELECT setval('#__assets_id_seq', 91, false); From f9cd0cbdfe5e8585481b718541bf20f17c0c2c88 Mon Sep 17 00:00:00 2001 From: Yatharth Vyas Date: Sun, 1 Aug 2021 19:37:44 +0530 Subject: [PATCH 46/85] Update installation/sql/postgresql/base.sql Co-authored-by: Richard Fath --- installation/sql/postgresql/base.sql | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/installation/sql/postgresql/base.sql b/installation/sql/postgresql/base.sql index a494920de0fc0..ba66b4c35e5ec 100644 --- a/installation/sql/postgresql/base.sql +++ b/installation/sql/postgresql/base.sql @@ -120,7 +120,6 @@ INSERT INTO "#__assets" ("id", "parent_id", "lft", "rgt", "level", "name", "titl (92, 89, 136, 137, 3, 'com_modules.transition.2', 'Unpublish', '{}'), (93, 89, 138, 139, 3, 'com_modules.transition.3', 'Trash', '{}'); - SELECT setval('#__assets_id_seq', 91, false); -- @@ -1214,4 +1213,4 @@ INSERT INTO "#__workflow_transitions" ("id", "asset_id", "published", "ordering" SELECT setval('#__workflow_transitions_id_seq', 8, false); INSERT INTO "#__workflow_associations" ("item_id", "stage_id", "extension") -SELECT "id", 2, 'com_modules.module' FROM "#__modules"; \ No newline at end of file +SELECT "id", 2, 'com_modules.module' FROM "#__modules"; From 0a108681605bf31708cb5bf6c8197bb344667ef5 Mon Sep 17 00:00:00 2001 From: Yatharth Vyas Date: Sun, 1 Aug 2021 19:38:41 +0530 Subject: [PATCH 47/85] Update installation/sql/mysql/base.sql Co-authored-by: Richard Fath --- installation/sql/mysql/base.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/installation/sql/mysql/base.sql b/installation/sql/mysql/base.sql index ca39adcbc0fce..a80fa47e82dac 100644 --- a/installation/sql/mysql/base.sql +++ b/installation/sql/mysql/base.sql @@ -1145,7 +1145,7 @@ CREATE TABLE IF NOT EXISTS `#__workflow_stages` ( INSERT INTO `#__workflow_stages` (`id`, `asset_id`, `ordering`, `workflow_id`, `published`, `title`, `description`, `default`) VALUES (1, 0, 1, 1, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1), -(2, 18, 1, 2, 1, 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '', 1); +(2, 90, 1, 2, 1, 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '', 1); -- -------------------------------------------------------- From 3368025de634d7db6e0415b9f345ec10ae43b354 Mon Sep 17 00:00:00 2001 From: Yatharth Vyas Date: Sun, 1 Aug 2021 19:38:59 +0530 Subject: [PATCH 48/85] Update installation/sql/postgresql/base.sql Co-authored-by: Richard Fath --- installation/sql/postgresql/base.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/installation/sql/postgresql/base.sql b/installation/sql/postgresql/base.sql index ba66b4c35e5ec..fec590e0f1c9f 100644 --- a/installation/sql/postgresql/base.sql +++ b/installation/sql/postgresql/base.sql @@ -1119,7 +1119,7 @@ INSERT INTO "#__workflows" ("id", "asset_id", "published", "title", "description (1, 56, 1, 'COM_WORKFLOW_BASIC_WORKFLOW', '', 'com_content.article', 1, 1, CURRENT_TIMESTAMP, 42, CURRENT_TIMESTAMP, 42), (2, 89, 1, 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '', 'com_modules.module', 1, 1, CURRENT_TIMESTAMP, 42, CURRENT_TIMESTAMP, 42); -SELECT setval('#__workflows_id_seq', 2, false); +SELECT setval('#__workflows_id_seq', 3, false); -- -- Table structure for table `#__workflow_associations` From 786ec927a5f30b0eb034b40b4376c21a57479d20 Mon Sep 17 00:00:00 2001 From: Yatharth Vyas Date: Sun, 1 Aug 2021 19:39:23 +0530 Subject: [PATCH 49/85] Update installation/sql/postgresql/base.sql Co-authored-by: Richard Fath --- installation/sql/postgresql/base.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/installation/sql/postgresql/base.sql b/installation/sql/postgresql/base.sql index fec590e0f1c9f..c827a29f80b60 100644 --- a/installation/sql/postgresql/base.sql +++ b/installation/sql/postgresql/base.sql @@ -1210,7 +1210,7 @@ INSERT INTO "#__workflow_transitions" ("id", "asset_id", "published", "ordering" (9, 91, 1, 2, 2, 'Publish', '', -1, 2, '{"publishing":"1"}'), (10, 93, 1, 3, 2, 'Trash', '', -1, 2, '{"publishing":"-2"}'); -SELECT setval('#__workflow_transitions_id_seq', 8, false); +SELECT setval('#__workflow_transitions_id_seq', 11, false); INSERT INTO "#__workflow_associations" ("item_id", "stage_id", "extension") SELECT "id", 2, 'com_modules.module' FROM "#__modules"; From fd143adf2d84c7a17ec00ed0a20f0dc41eb16227 Mon Sep 17 00:00:00 2001 From: Yatharth Vyas Date: Sun, 1 Aug 2021 19:39:39 +0530 Subject: [PATCH 50/85] Update installation/sql/postgresql/base.sql Co-authored-by: Richard Fath --- installation/sql/postgresql/base.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/installation/sql/postgresql/base.sql b/installation/sql/postgresql/base.sql index c827a29f80b60..cd0786e037606 100644 --- a/installation/sql/postgresql/base.sql +++ b/installation/sql/postgresql/base.sql @@ -1170,7 +1170,7 @@ INSERT INTO "#__workflow_stages" ("id", "asset_id", "ordering", "workflow_id", " (1, 57, 1, 1, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1), (2, 90, 1, 2, 1, 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '', 1); -SELECT setval('#__workflow_stages_id_seq', 2, false); +SELECT setval('#__workflow_stages_id_seq', 3, false); -- -- Table structure for table `#__workflow_transitions` From 28d888a5fce68ea4b078f52ac2145dcede855897 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Sun, 1 Aug 2021 19:42:02 +0530 Subject: [PATCH 51/85] place where clause after the end of all joins --- .../components/com_content/src/Model/ArticlesModel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/administrator/components/com_content/src/Model/ArticlesModel.php b/administrator/components/com_content/src/Model/ArticlesModel.php index fa2ecf16cc5b9..0bf97f837c3f5 100644 --- a/administrator/components/com_content/src/Model/ArticlesModel.php +++ b/administrator/components/com_content/src/Model/ArticlesModel.php @@ -302,9 +302,9 @@ protected function getListQuery() ->join('LEFT', $db->quoteName('#__categories', 'parent'), $db->quoteName('parent.id') . ' = ' . $db->quoteName('c.parent_id')) ->join('LEFT', $db->quoteName('#__users', 'ua'), $db->quoteName('ua.id') . ' = ' . $db->quoteName('a.created_by')) ->join('INNER', $db->quoteName('#__workflow_associations', 'wa'), $db->quoteName('wa.item_id') . ' = ' . $db->quoteName('a.id')) - ->where($db->quoteName('wa.extension') . ' = "com_content.article"') ->join('INNER', $db->quoteName('#__workflow_stages', 'ws'), $db->quoteName('ws.id') . ' = ' . $db->quoteName('wa.stage_id')) - ->join('INNER', $db->quoteName('#__workflows', 'w'), $db->quoteName('w.id') . ' = ' . $db->quoteName('ws.workflow_id')); + ->join('INNER', $db->quoteName('#__workflows', 'w'), $db->quoteName('w.id') . ' = ' . $db->quoteName('ws.workflow_id')) + ->where($db->quoteName('wa.extension') . ' = "com_content.article"'); if (PluginHelper::isEnabled('content', 'vote')) { From 82d8f319c18c0285a6426d1eb6cfa9e43d9f187e Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Sun, 1 Aug 2021 19:47:35 +0530 Subject: [PATCH 52/85] update the workflow stage name --- installation/sql/mysql/base.sql | 2 +- installation/sql/postgresql/base.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/installation/sql/mysql/base.sql b/installation/sql/mysql/base.sql index a80fa47e82dac..812d6e81ac2e3 100644 --- a/installation/sql/mysql/base.sql +++ b/installation/sql/mysql/base.sql @@ -1145,7 +1145,7 @@ CREATE TABLE IF NOT EXISTS `#__workflow_stages` ( INSERT INTO `#__workflow_stages` (`id`, `asset_id`, `ordering`, `workflow_id`, `published`, `title`, `description`, `default`) VALUES (1, 0, 1, 1, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1), -(2, 90, 1, 2, 1, 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '', 1); +(2, 90, 1, 2, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1); -- -------------------------------------------------------- diff --git a/installation/sql/postgresql/base.sql b/installation/sql/postgresql/base.sql index cd0786e037606..beae80a9debe9 100644 --- a/installation/sql/postgresql/base.sql +++ b/installation/sql/postgresql/base.sql @@ -1168,7 +1168,7 @@ CREATE INDEX "#__workflow_stages_idx_checked_out" ON "#__workflow_stages" ("chec INSERT INTO "#__workflow_stages" ("id", "asset_id", "ordering", "workflow_id", "published", "title", "description", "default") VALUES (1, 57, 1, 1, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1), -(2, 90, 1, 2, 1, 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '', 1); +(2, 90, 1, 2, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1); SELECT setval('#__workflow_stages_id_seq', 3, false); From c57d3484e494e016c14ba32ab4b87b714c5a8fd7 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Sun, 1 Aug 2021 19:48:30 +0530 Subject: [PATCH 53/85] remove duplicate query in updates --- .../com_admin/sql/updates/mysql/4.1.0-2021-07-30.sql | 6 ------ .../com_admin/sql/updates/postgresql/4.1.0-2021-07-30.sql | 6 ------ 2 files changed, 12 deletions(-) diff --git a/administrator/components/com_admin/sql/updates/mysql/4.1.0-2021-07-30.sql b/administrator/components/com_admin/sql/updates/mysql/4.1.0-2021-07-30.sql index b17aa82e01ef1..f47f88c52251f 100644 --- a/administrator/components/com_admin/sql/updates/mysql/4.1.0-2021-07-30.sql +++ b/administrator/components/com_admin/sql/updates/mysql/4.1.0-2021-07-30.sql @@ -10,12 +10,6 @@ INSERT INTO `#__workflows` (`id`, `asset_id`, `published`, `title`, `description INSERT INTO `#__workflow_stages` (`id`, `asset_id`, `ordering`, `workflow_id`, `published`, `title`, `description`, `default`, `checked_out_time`, `checked_out`) SELECT NULL, 0, 1, `id`, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1, NULL, 0 FROM `#__workflows` WHERE `title` = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES'; --- --- Inserting the default stage for the new worklfow --- -INSERT INTO `#__workflow_stages` (`id`, `asset_id`, `ordering`, `workflow_id`, `published`, `title`, `description`, `default`, `checked_out_time`, `checked_out`) -SELECT NULL, 0, 1, `id`, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1, NULL, 0 FROM `#__workflows` WHERE `title` = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES'; - -- -- Inserting the transitions for the new worklfow -- diff --git a/administrator/components/com_admin/sql/updates/postgresql/4.1.0-2021-07-30.sql b/administrator/components/com_admin/sql/updates/postgresql/4.1.0-2021-07-30.sql index 014ac99c77b95..c3eb9e04ae7a2 100644 --- a/administrator/components/com_admin/sql/updates/postgresql/4.1.0-2021-07-30.sql +++ b/administrator/components/com_admin/sql/updates/postgresql/4.1.0-2021-07-30.sql @@ -10,12 +10,6 @@ INSERT INTO "#__workflows" ("id", "asset_id", "published", "title", "description INSERT INTO "#__workflow_stages" ("id", "asset_id", "ordering", "workflow_id", "published", "title", "description", "default", "checked_out_time", "checked_out") SELECT NULL, 0, 1, "id", 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1, NULL, 0 FROM "#__workflows" WHERE "title" = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES'; --- --- Inserting the default stage for the new worklfow --- -INSERT INTO "#__workflow_stages" ("id", "asset_id", "ordering", "workflow_id", "published", "title", "description", "default", "checked_out_time", "checked_out") -SELECT NULL, 0, 1, "id", 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1, NULL, 0 FROM "#__workflows" WHERE "title" = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES'; - -- -- Inserting the transitions for the new worklfow -- From 01630fe25ebccc1dff60e0cacf9f9f4cbe781b6f Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Mon, 2 Aug 2021 21:59:46 +0530 Subject: [PATCH 54/85] show default option in workflow field --- .../src/Extension/ModulesComponent.php | 1 - .../com_modules/src/Model/ModuleModel.php | 40 +++++++++++++++++++ administrator/language/en-GB/com_modules.ini | 1 + 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/administrator/components/com_modules/src/Extension/ModulesComponent.php b/administrator/components/com_modules/src/Extension/ModulesComponent.php index 4753869730ae1..a2005ba944cc0 100644 --- a/administrator/components/com_modules/src/Extension/ModulesComponent.php +++ b/administrator/components/com_modules/src/Extension/ModulesComponent.php @@ -134,5 +134,4 @@ public function filterTransitions(array $transitions, int $pk): array { return ModuleHelper::filterTransitions($transitions, $pk); } - } diff --git a/administrator/components/com_modules/src/Model/ModuleModel.php b/administrator/components/com_modules/src/Model/ModuleModel.php index ad01e08f3c54a..e03674401645e 100644 --- a/administrator/components/com_modules/src/Model/ModuleModel.php +++ b/administrator/components/com_modules/src/Model/ModuleModel.php @@ -979,6 +979,7 @@ protected function preprocessForm(Form $form, $data, $group = 'content') { // Import the workflow plugin group to allow form manipulation. $this->importWorkflowPlugins(); + $this->prepareWorkflowField($form, $data); } } @@ -1316,4 +1317,43 @@ protected function getStageForNewItem(Form $form, $data) return $defaultStage; } + + /** + * Adds defaylt stage to workflow field in the form. + * + * @param Form $form The form to change + * @param array|object $data The form data + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public static function prepareWorkflowField(Form $form, $data) + { + $db = Factory::getDbo(); + + $data = (array) $data; + + $form->setFieldAttribute('workflow_id', 'default', 'inherit'); + + $query = $db->getQuery(true); + + $query->select($db->quoteName('title')) + ->from($db->quoteName('#__workflows')) + ->where( + [ + $db->quoteName('default') . ' = 1', + $db->quoteName('published') . ' = 1', + $db->quoteName('extension') . ' = "com_modules.module"', + ] + ); + + $defaulttitle = $db->setQuery($query)->loadResult(); + + $field = $form->getField('workflow_id'); + + $field->addOption(Text::sprintf('COM_WORKFLOW_USE_DEFAULT_WORKFLOWS', Text::_($defaulttitle)), ['value' => 'use_default']); + + $field->addOption('- ' . Text::_('COM_MODULES_WORKFLOW') . ' -', ['disabled' => 'true']); + } } diff --git a/administrator/language/en-GB/com_modules.ini b/administrator/language/en-GB/com_modules.ini index 3257dfecf22a7..8b49a07004e8d 100644 --- a/administrator/language/en-GB/com_modules.ini +++ b/administrator/language/en-GB/com_modules.ini @@ -192,6 +192,7 @@ COM_MODULES_TABLE_CAPTION="Table of Modules" COM_MODULES_TYPE_CHOOSE="Select a Module Type" COM_MODULES_TYPE_OR_SELECT_POSITION="Type or Select a Position" COM_MODULES_WORKFLOW="Workflow" +COM_MODULES_WORKFLOW="Workflows" COM_MODULES_WORKFLOW_NOT_FOUND="No default workflow available, please define one or contact an administrator." COM_MODULES_WORKFLOW_TRANSITION_NOT_ALLOWED="You're not allowed to execute this transition" COM_MODULES_XML_DESCRIPTION="Component for module management in the Administrator Backend." From eac74620c175f01aad98d0dcca5fca6dfa06df3d Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Mon, 2 Aug 2021 22:01:41 +0530 Subject: [PATCH 55/85] remove unused function --- .../com_modules/src/Helper/ModulesHelper.php | 103 ------------------ 1 file changed, 103 deletions(-) diff --git a/administrator/components/com_modules/src/Helper/ModulesHelper.php b/administrator/components/com_modules/src/Helper/ModulesHelper.php index ab6a6fc60aaa9..24d0ff948c621 100644 --- a/administrator/components/com_modules/src/Helper/ModulesHelper.php +++ b/administrator/components/com_modules/src/Helper/ModulesHelper.php @@ -347,107 +347,4 @@ function ($var) use ($pk, $workflowId) ) ); } - - /** - * Prepares a form - * - * @param Form $form The form to change - * @param array|object $data The form data - * - * @return void - * - * @since __DEPLOY_VERSION__ - */ - public static function onPrepareForm(Form $form, $data) - { - $db = Factory::getDbo(); - - $data = (array) $data; - - // Make workflows translatable - Factory::getLanguage()->load('com_workflow', JPATH_ADMINISTRATOR); - - $form->setFieldAttribute('workflow_id', 'default', 'inherit'); - - $query = $db->getQuery(true); - - $query->select($db->quoteName('title')) - ->from($db->quoteName('#__workflows')) - ->where( - [ - $db->quoteName('default') . ' = 1', - $db->quoteName('published') . ' = 1', - ] - ); - - $defaulttitle = $db->setQuery($query)->loadResult(); - - $option = Text::_('COM_WORKFLOW_INHERIT_WORKFLOW_NEW'); - - if (!empty($data['id'])) - { - $category = new Category($db); - - $categories = $category->getPath((int) $data['id']); - - // Remove the current category, because we search for inheritance from parent. - array_pop($categories); - - $option = Text::sprintf('COM_WORKFLOW_INHERIT_WORKFLOW', Text::_($defaulttitle)); - - if (!empty($categories)) - { - $categories = array_reverse($categories); - - $query = $db->getQuery(true); - - $query->select($db->quoteName('title')) - ->from($db->quoteName('#__workflows')) - ->where( - [ - $db->quoteName('id') . ' = :workflowId', - $db->quoteName('published') . ' = 1', - ] - ) - ->bind(':workflowId', $workflow_id, ParameterType::INTEGER); - - $db->setQuery($query); - - foreach ($categories as $cat) - { - $cat->params = new Registry($cat->params); - - $workflow_id = $cat->params->get('workflow_id'); - - if ($workflow_id == 'inherit') - { - continue; - } - elseif ($workflow_id == 'use_default') - { - break; - } - elseif ($workflow_id = (int) $workflow_id) - { - $title = $db->loadResult(); - - if (!is_null($title)) - { - $option = Text::sprintf('COM_WORKFLOW_INHERIT_WORKFLOW', Text::_($title)); - - break; - } - } - } - } - } - - $field = $form->getField('workflow_id', 'params'); - - $field->addOption($option, ['value' => 'inherit']); - - $field->addOption(Text::sprintf('COM_WORKFLOW_USE_DEFAULT_WORKFLOW', Text::_($defaulttitle)), ['value' => 'use_default']); - - $field->addOption('- ' . Text::_('COM_MODULE_WORKFLOWS') . ' -', ['disabled' => 'true']); - } } From 674cd336f6d41f3a0236cfb3358dda94a175d1be Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Mon, 2 Aug 2021 23:51:50 +0530 Subject: [PATCH 56/85] add the use default option in workflow dropdown --- .../components/com_modules/src/Model/ModuleModel.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/administrator/components/com_modules/src/Model/ModuleModel.php b/administrator/components/com_modules/src/Model/ModuleModel.php index e03674401645e..4d6e9139cf016 100644 --- a/administrator/components/com_modules/src/Model/ModuleModel.php +++ b/administrator/components/com_modules/src/Model/ModuleModel.php @@ -1338,7 +1338,10 @@ public static function prepareWorkflowField(Form $form, $data) $query = $db->getQuery(true); - $query->select($db->quoteName('title')) + $query->select([ + $db->quoteName('title'), + $db->quoteName('id') + ]) ->from($db->quoteName('#__workflows')) ->where( [ @@ -1348,11 +1351,10 @@ public static function prepareWorkflowField(Form $form, $data) ] ); - $defaulttitle = $db->setQuery($query)->loadResult(); - + $defaultWorkflow = $db->setQuery($query)->loadObject(); $field = $form->getField('workflow_id'); - $field->addOption(Text::sprintf('COM_WORKFLOW_USE_DEFAULT_WORKFLOWS', Text::_($defaulttitle)), ['value' => 'use_default']); + $field->addOption(Text::sprintf('COM_WORKFLOW_USE_DEFAULT_WORKFLOW', Text::_($defaultWorkflow->title)), ['value' => $defaultWorkflow->id]); $field->addOption('- ' . Text::_('COM_MODULES_WORKFLOW') . ' -', ['disabled' => 'true']); } From 0c561cfa879b211c486626b34648426370b2a613 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Tue, 3 Aug 2021 00:17:53 +0530 Subject: [PATCH 57/85] change workflow to workflows --- administrator/components/com_modules/src/Model/ModuleModel.php | 2 +- administrator/language/en-GB/com_modules.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/administrator/components/com_modules/src/Model/ModuleModel.php b/administrator/components/com_modules/src/Model/ModuleModel.php index 4d6e9139cf016..b702737fbb96d 100644 --- a/administrator/components/com_modules/src/Model/ModuleModel.php +++ b/administrator/components/com_modules/src/Model/ModuleModel.php @@ -1356,6 +1356,6 @@ public static function prepareWorkflowField(Form $form, $data) $field->addOption(Text::sprintf('COM_WORKFLOW_USE_DEFAULT_WORKFLOW', Text::_($defaultWorkflow->title)), ['value' => $defaultWorkflow->id]); - $field->addOption('- ' . Text::_('COM_MODULES_WORKFLOW') . ' -', ['disabled' => 'true']); + $field->addOption('- ' . Text::_('COM_MODULES_WORKFLOWS') . ' -', ['disabled' => 'true']); } } diff --git a/administrator/language/en-GB/com_modules.ini b/administrator/language/en-GB/com_modules.ini index 8b49a07004e8d..10390bee39b1a 100644 --- a/administrator/language/en-GB/com_modules.ini +++ b/administrator/language/en-GB/com_modules.ini @@ -192,7 +192,7 @@ COM_MODULES_TABLE_CAPTION="Table of Modules" COM_MODULES_TYPE_CHOOSE="Select a Module Type" COM_MODULES_TYPE_OR_SELECT_POSITION="Type or Select a Position" COM_MODULES_WORKFLOW="Workflow" -COM_MODULES_WORKFLOW="Workflows" +COM_MODULES_WORKFLOWS="Workflows" COM_MODULES_WORKFLOW_NOT_FOUND="No default workflow available, please define one or contact an administrator." COM_MODULES_WORKFLOW_TRANSITION_NOT_ALLOWED="You're not allowed to execute this transition" COM_MODULES_XML_DESCRIPTION="Component for module management in the Administrator Backend." From 00bebf5863ecebfe5c4846c9c5f198ea3babf420 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Tue, 3 Aug 2021 13:18:59 +0530 Subject: [PATCH 58/85] phpcs --- .../components/com_modules/src/Model/ModuleModel.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/administrator/components/com_modules/src/Model/ModuleModel.php b/administrator/components/com_modules/src/Model/ModuleModel.php index b702737fbb96d..9475128344783 100644 --- a/administrator/components/com_modules/src/Model/ModuleModel.php +++ b/administrator/components/com_modules/src/Model/ModuleModel.php @@ -1338,10 +1338,7 @@ public static function prepareWorkflowField(Form $form, $data) $query = $db->getQuery(true); - $query->select([ - $db->quoteName('title'), - $db->quoteName('id') - ]) + $query->select([$db->quoteName('title'), $db->quoteName('id')]) ->from($db->quoteName('#__workflows')) ->where( [ From cccb2149545ade27f2b6132da7e1ec895b65f5e3 Mon Sep 17 00:00:00 2001 From: Yatharth Vyas Date: Sun, 8 Aug 2021 22:13:22 +0530 Subject: [PATCH 59/85] Update administrator/components/com_content/src/Model/ArticlesModel.php Co-authored-by: Richard Fath --- .../components/com_content/src/Model/ArticlesModel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/administrator/components/com_content/src/Model/ArticlesModel.php b/administrator/components/com_content/src/Model/ArticlesModel.php index 0bf97f837c3f5..a8f66799e3250 100644 --- a/administrator/components/com_content/src/Model/ArticlesModel.php +++ b/administrator/components/com_content/src/Model/ArticlesModel.php @@ -304,7 +304,7 @@ protected function getListQuery() ->join('INNER', $db->quoteName('#__workflow_associations', 'wa'), $db->quoteName('wa.item_id') . ' = ' . $db->quoteName('a.id')) ->join('INNER', $db->quoteName('#__workflow_stages', 'ws'), $db->quoteName('ws.id') . ' = ' . $db->quoteName('wa.stage_id')) ->join('INNER', $db->quoteName('#__workflows', 'w'), $db->quoteName('w.id') . ' = ' . $db->quoteName('ws.workflow_id')) - ->where($db->quoteName('wa.extension') . ' = "com_content.article"'); + ->where($db->quoteName('wa.extension') . ' = ' . $db->quote('com_content.article'); if (PluginHelper::isEnabled('content', 'vote')) { From 5d2454619275cbbd7e43764f822715fd3761b0b8 Mon Sep 17 00:00:00 2001 From: Yatharth Vyas Date: Sun, 8 Aug 2021 22:17:24 +0530 Subject: [PATCH 60/85] Update administrator/components/com_modules/src/Model/ModuleModel.php Co-authored-by: Richard Fath --- administrator/components/com_modules/src/Model/ModuleModel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/administrator/components/com_modules/src/Model/ModuleModel.php b/administrator/components/com_modules/src/Model/ModuleModel.php index 9475128344783..eedc9cccb6a24 100644 --- a/administrator/components/com_modules/src/Model/ModuleModel.php +++ b/administrator/components/com_modules/src/Model/ModuleModel.php @@ -1302,7 +1302,7 @@ protected function getStageForNewItem(Form $form, $data) ->select($db->quoteName('id')) ->from($db->quoteName('#__workflows')) ->where($db->quoteName('default') . ' = 1') - ->where($db->quoteName('extension') . ' = "com_modules.module"'); + ->where($db->quoteName('extension') . ' = ' . $db->quote('com_modules.module'); $query->where($db->quoteName('workflow_id') . ' IN (' . $defaultWorkflowQuery . ')'); } From 0a3f1c820f33b083903548c38da29ece650b7637 Mon Sep 17 00:00:00 2001 From: Yatharth Vyas Date: Sun, 8 Aug 2021 22:31:14 +0530 Subject: [PATCH 61/85] Escape string quotes in query Co-authored-by: Richard Fath --- administrator/components/com_modules/src/Model/ModuleModel.php | 2 +- administrator/components/com_modules/src/Model/ModulesModel.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/administrator/components/com_modules/src/Model/ModuleModel.php b/administrator/components/com_modules/src/Model/ModuleModel.php index eedc9cccb6a24..abf8b8d43235d 100644 --- a/administrator/components/com_modules/src/Model/ModuleModel.php +++ b/administrator/components/com_modules/src/Model/ModuleModel.php @@ -1344,7 +1344,7 @@ public static function prepareWorkflowField(Form $form, $data) [ $db->quoteName('default') . ' = 1', $db->quoteName('published') . ' = 1', - $db->quoteName('extension') . ' = "com_modules.module"', + $db->quoteName('extension') . ' = ' . $db->quote('com_modules.module'), ] ); diff --git a/administrator/components/com_modules/src/Model/ModulesModel.php b/administrator/components/com_modules/src/Model/ModulesModel.php index cf0142e377bc9..a6788d5e14af4 100644 --- a/administrator/components/com_modules/src/Model/ModulesModel.php +++ b/administrator/components/com_modules/src/Model/ModulesModel.php @@ -347,7 +347,7 @@ protected function getListQuery() // Join over the workflows association $query->select($db->quoteName('wa.stage_id', 'stage_id')) ->join('INNER', $db->quoteName('#__workflow_associations', 'wa'), $db->quoteName('wa.item_id') . ' = ' . $db->quoteName('a.id')) - ->where($db->quoteName('wa.extension') . ' = "com_modules.module"'); + ->where($db->quoteName('wa.extension') . ' = ' . $db->quote('com_modules.module'); // Join over the workflows stage $query->select( From e4c35236da1f00e1f212c764a31a42cdf3037458 Mon Sep 17 00:00:00 2001 From: Yatharth Vyas Date: Sun, 8 Aug 2021 22:33:43 +0530 Subject: [PATCH 62/85] Update administrator/components/com_modules/src/Model/ModulesModel.php Co-authored-by: Richard Fath --- administrator/components/com_modules/src/Model/ModulesModel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/administrator/components/com_modules/src/Model/ModulesModel.php b/administrator/components/com_modules/src/Model/ModulesModel.php index a6788d5e14af4..f329bdfd2f74f 100644 --- a/administrator/components/com_modules/src/Model/ModulesModel.php +++ b/administrator/components/com_modules/src/Model/ModulesModel.php @@ -347,7 +347,7 @@ protected function getListQuery() // Join over the workflows association $query->select($db->quoteName('wa.stage_id', 'stage_id')) ->join('INNER', $db->quoteName('#__workflow_associations', 'wa'), $db->quoteName('wa.item_id') . ' = ' . $db->quoteName('a.id')) - ->where($db->quoteName('wa.extension') . ' = ' . $db->quote('com_modules.module'); + ->where($db->quoteName('wa.extension') . ' = ' . $db->quote('com_modules.module')); // Join over the workflows stage $query->select( From 22583e898b9b88a140cd6ae3b4de7b8d2d94844b Mon Sep 17 00:00:00 2001 From: Yatharth Vyas Date: Sun, 8 Aug 2021 22:39:27 +0530 Subject: [PATCH 63/85] Update administrator/components/com_modules/src/Model/ModuleModel.php Co-authored-by: Richard Fath --- administrator/components/com_modules/src/Model/ModuleModel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/administrator/components/com_modules/src/Model/ModuleModel.php b/administrator/components/com_modules/src/Model/ModuleModel.php index abf8b8d43235d..92baba1b5f521 100644 --- a/administrator/components/com_modules/src/Model/ModuleModel.php +++ b/administrator/components/com_modules/src/Model/ModuleModel.php @@ -1302,7 +1302,7 @@ protected function getStageForNewItem(Form $form, $data) ->select($db->quoteName('id')) ->from($db->quoteName('#__workflows')) ->where($db->quoteName('default') . ' = 1') - ->where($db->quoteName('extension') . ' = ' . $db->quote('com_modules.module'); + ->where($db->quoteName('extension') . ' = ' . $db->quote('com_modules.module')); $query->where($db->quoteName('workflow_id') . ' IN (' . $defaultWorkflowQuery . ')'); } From d31d625d530bf109e36165c19cb8e3cd5e3ff4e0 Mon Sep 17 00:00:00 2001 From: Yatharth Vyas Date: Sun, 8 Aug 2021 23:01:38 +0530 Subject: [PATCH 64/85] Update administrator/components/com_content/src/Model/ArticlesModel.php Co-authored-by: Richard Fath --- .../components/com_content/src/Model/ArticlesModel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/administrator/components/com_content/src/Model/ArticlesModel.php b/administrator/components/com_content/src/Model/ArticlesModel.php index a8f66799e3250..bb185fc620db6 100644 --- a/administrator/components/com_content/src/Model/ArticlesModel.php +++ b/administrator/components/com_content/src/Model/ArticlesModel.php @@ -304,7 +304,7 @@ protected function getListQuery() ->join('INNER', $db->quoteName('#__workflow_associations', 'wa'), $db->quoteName('wa.item_id') . ' = ' . $db->quoteName('a.id')) ->join('INNER', $db->quoteName('#__workflow_stages', 'ws'), $db->quoteName('ws.id') . ' = ' . $db->quoteName('wa.stage_id')) ->join('INNER', $db->quoteName('#__workflows', 'w'), $db->quoteName('w.id') . ' = ' . $db->quoteName('ws.workflow_id')) - ->where($db->quoteName('wa.extension') . ' = ' . $db->quote('com_content.article'); + ->where($db->quoteName('wa.extension') . ' = ' . $db->quote('com_content.article')); if (PluginHelper::isEnabled('content', 'vote')) { From 5d07965ba13eedbe38a82ba9c31dcd41fb90fed1 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Wed, 11 Aug 2021 18:44:04 +0530 Subject: [PATCH 65/85] use modules component helper for workflow field --- .../components/com_modules/tmpl/modules/default_batch_body.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/administrator/components/com_modules/tmpl/modules/default_batch_body.php b/administrator/components/com_modules/tmpl/modules/default_batch_body.php index ee7764d870ae2..d70543f87e9ca 100644 --- a/administrator/components/com_modules/tmpl/modules/default_batch_body.php +++ b/administrator/components/com_modules/tmpl/modules/default_batch_body.php @@ -19,7 +19,7 @@ $clientId = $this->state->get('client_id'); -$params = ComponentHelper::getParams('com_content'); +$params = ComponentHelper::getParams('com_modules'); $user = Factory::getUser(); From 8a4a83c8541b308c3d3576ba34d6a3ad02283683 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Wed, 11 Aug 2021 21:24:12 +0530 Subject: [PATCH 66/85] create workflow association on duplicating modules --- .../com_modules/src/Model/ModuleModel.php | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/administrator/components/com_modules/src/Model/ModuleModel.php b/administrator/components/com_modules/src/Model/ModuleModel.php index 92baba1b5f521..e694428211e95 100644 --- a/administrator/components/com_modules/src/Model/ModuleModel.php +++ b/administrator/components/com_modules/src/Model/ModuleModel.php @@ -476,6 +476,16 @@ public function duplicate(&$pks) { $tuples[] = (int) $table->id . ',' . (int) $menuid; } + + $query = $db->getQuery(true) + ->select($db->quoteName('stage_id')) + ->from($db->quoteName('#__workflow_associations')) + ->where($db->quoteName('extension') . ' = ' . $db->quote('com_modules.module')) + ->where($db->quoteName('item_id') . ' = :moduleid') + ->bind(':moduleid', $pk, ParameterType::INTEGER); + + $db->setQuery($query); + $stageIdTuples[] = (int) $table->id . ',' . (int) $db->loadResult() . ',' . $db->quote('com_modules.module'); } else { @@ -505,6 +515,27 @@ public function duplicate(&$pks) } } + if (!empty($stageIdTuples)) + { + $query = $db->getQuery(true) + ->insert($db->quoteName('#__workflow_associations')) + ->columns($db->quoteName(array('item_id', 'stage_id', 'extension'))) + ->values($stageIdTuples); + + $db->setQuery($query); + + try + { + $db->execute(); + } + catch (\RuntimeException $e) + { + Factory::getApplication()->enqueueMessage($e->getMessage(), 'error'); + + return false; + } + } + // Clear modules cache $this->cleanCache(); From 9ecd0f009bfccc1574a1580930b13067ae1c2c20 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Thu, 12 Aug 2021 18:51:24 +0530 Subject: [PATCH 67/85] declare the new abstract method --- .../src/Extension/ModulesComponent.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/administrator/components/com_modules/src/Extension/ModulesComponent.php b/administrator/components/com_modules/src/Extension/ModulesComponent.php index a2005ba944cc0..02170ce907542 100644 --- a/administrator/components/com_modules/src/Extension/ModulesComponent.php +++ b/administrator/components/com_modules/src/Extension/ModulesComponent.php @@ -134,4 +134,20 @@ public function filterTransitions(array $transitions, int $pk): array { return ModuleHelper::filterTransitions($transitions, $pk); } + + /** + * Returns the workflow context based on the given category section + * + * @param string $section The section + * + * @return string|null + * + * @since __DEPLOY_VERSION__ + */ + public function getCategoryWorkflowContext(?string $section = null): string + { + $context = $this->getWorkflowContexts(); + + return array_key_first($context); + } } From 4310cde294cdfe010ea4fe2071bfc2edd18991ea Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Thu, 12 Aug 2021 20:58:22 +0530 Subject: [PATCH 68/85] remove required as we have a default --- administrator/components/com_modules/forms/module.xml | 1 - administrator/components/com_modules/forms/moduleadmin.xml | 1 - 2 files changed, 2 deletions(-) diff --git a/administrator/components/com_modules/forms/module.xml b/administrator/components/com_modules/forms/module.xml index f88019bca0be1..5f175339d8528 100644 --- a/administrator/components/com_modules/forms/module.xml +++ b/administrator/components/com_modules/forms/module.xml @@ -162,7 +162,6 @@ sql_order="ordering" key_field="id" value_field="title" - required="true" default="use_default" translate="true" /> diff --git a/administrator/components/com_modules/forms/moduleadmin.xml b/administrator/components/com_modules/forms/moduleadmin.xml index 565e1d6f99499..97b0a6f234409 100644 --- a/administrator/components/com_modules/forms/moduleadmin.xml +++ b/administrator/components/com_modules/forms/moduleadmin.xml @@ -156,7 +156,6 @@ sql_order="ordering" key_field="id" value_field="title" - required="true" default="use_default" translate="true" /> From a2779e1ce3adcc1f37770e04e3aae48bf9c4dd12 Mon Sep 17 00:00:00 2001 From: Yatharth Vyas Date: Thu, 12 Aug 2021 21:25:53 +0530 Subject: [PATCH 69/85] Update administrator/components/com_modules/src/Model/ModuleModel.php Co-authored-by: Brian Teeman --- administrator/components/com_modules/src/Model/ModuleModel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/administrator/components/com_modules/src/Model/ModuleModel.php b/administrator/components/com_modules/src/Model/ModuleModel.php index e694428211e95..a63e2a807ffb5 100644 --- a/administrator/components/com_modules/src/Model/ModuleModel.php +++ b/administrator/components/com_modules/src/Model/ModuleModel.php @@ -1350,7 +1350,7 @@ protected function getStageForNewItem(Form $form, $data) } /** - * Adds defaylt stage to workflow field in the form. + * Adds default stage to workflow field in the form. * * @param Form $form The form to change * @param array|object $data The form data From d55241101ebaaeca222730a977f9bf8c3e2beaa5 Mon Sep 17 00:00:00 2001 From: Yatharth Vyas Date: Thu, 12 Aug 2021 21:26:30 +0530 Subject: [PATCH 70/85] Update administrator/components/com_modules/src/Model/ModulesModel.php Co-authored-by: Brian Teeman --- administrator/components/com_modules/src/Model/ModulesModel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/administrator/components/com_modules/src/Model/ModulesModel.php b/administrator/components/com_modules/src/Model/ModulesModel.php index f329bdfd2f74f..fbd218f7fdd34 100644 --- a/administrator/components/com_modules/src/Model/ModulesModel.php +++ b/administrator/components/com_modules/src/Model/ModulesModel.php @@ -522,7 +522,7 @@ protected function getListQuery() } /** - * Method to get all transitions at once for all articles + * Method to get all transitions at once for all modules * * @return array|boolean * From 0c45a0b5b3e4463f1e461c1e5cf63b6e89f0587c Mon Sep 17 00:00:00 2001 From: Yatharth Vyas Date: Thu, 12 Aug 2021 21:28:53 +0530 Subject: [PATCH 71/85] Update administrator/language/en-GB/com_modules.ini Co-authored-by: Brian Teeman --- administrator/language/en-GB/com_modules.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/administrator/language/en-GB/com_modules.ini b/administrator/language/en-GB/com_modules.ini index 10390bee39b1a..ef56c56b0cb27 100644 --- a/administrator/language/en-GB/com_modules.ini +++ b/administrator/language/en-GB/com_modules.ini @@ -194,7 +194,7 @@ COM_MODULES_TYPE_OR_SELECT_POSITION="Type or Select a Position" COM_MODULES_WORKFLOW="Workflow" COM_MODULES_WORKFLOWS="Workflows" COM_MODULES_WORKFLOW_NOT_FOUND="No default workflow available, please define one or contact an administrator." -COM_MODULES_WORKFLOW_TRANSITION_NOT_ALLOWED="You're not allowed to execute this transition" +COM_MODULES_WORKFLOW_TRANSITION_NOT_ALLOWED="You're not allowed to execute this transition." COM_MODULES_XML_DESCRIPTION="Component for module management in the Administrator Backend." JLIB_RULES_SETTING_NOTES_COM_MODULES="Changes apply to this component only.
Inherited - a Global Configuration setting or higher level setting is applied.
Denied always wins - whatever is set at the Global or higher level and applies to all child elements.
Allowed will enable the action for this component unless overruled by a Global Configuration setting." ; Alternate language strings for the rules form field From 1287c8f846b2fc07ecb8a2b872ff125a94a04ea1 Mon Sep 17 00:00:00 2001 From: Yatharth Vyas Date: Fri, 20 Aug 2021 13:36:32 +0530 Subject: [PATCH 72/85] Correct typo in workflow Co-authored-by: Phil E. Taylor --- .../com_admin/sql/updates/mysql/4.1.0-2021-07-30.sql | 4 ++-- .../com_admin/sql/updates/postgresql/4.1.0-2021-07-30.sql | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/administrator/components/com_admin/sql/updates/mysql/4.1.0-2021-07-30.sql b/administrator/components/com_admin/sql/updates/mysql/4.1.0-2021-07-30.sql index f47f88c52251f..76a9605841c17 100644 --- a/administrator/components/com_admin/sql/updates/mysql/4.1.0-2021-07-30.sql +++ b/administrator/components/com_admin/sql/updates/mysql/4.1.0-2021-07-30.sql @@ -5,13 +5,13 @@ INSERT INTO `#__workflows` (`id`, `asset_id`, `published`, `title`, `description (NULL, 0, 1, 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '', 'com_modules.module', 1, 1, CURRENT_TIMESTAMP(), 0, CURRENT_TIMESTAMP(), 0, NULL, 0); -- --- Inserting the default stage for the new worklfow +-- Inserting the default stage for the new workflow -- INSERT INTO `#__workflow_stages` (`id`, `asset_id`, `ordering`, `workflow_id`, `published`, `title`, `description`, `default`, `checked_out_time`, `checked_out`) SELECT NULL, 0, 1, `id`, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1, NULL, 0 FROM `#__workflows` WHERE `title` = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES'; -- --- Inserting the transitions for the new worklfow +-- Inserting the transitions for the new workflow -- INSERT INTO `#__workflow_transitions` (`id`, `asset_id`, `published`, `ordering`, `workflow_id`, `title`, `description`, `from_stage_id`, `to_stage_id`, `options`) SELECT NULL, 0, 1, NULL, `w`.`id`, 'Unpublish', '', -1, `s`.`id`, '{"publishing":"0"}' FROM `#__workflows` as `w` INNER JOIN `#__workflow_stages` as `s` ON `w`.`title` = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES' AND `s`.`title` = 'COM_WORKFLOW_BASIC_STAGE' AND `s`.`extension` = 'com_modules.module'; diff --git a/administrator/components/com_admin/sql/updates/postgresql/4.1.0-2021-07-30.sql b/administrator/components/com_admin/sql/updates/postgresql/4.1.0-2021-07-30.sql index c3eb9e04ae7a2..aa8ef84e84aeb 100644 --- a/administrator/components/com_admin/sql/updates/postgresql/4.1.0-2021-07-30.sql +++ b/administrator/components/com_admin/sql/updates/postgresql/4.1.0-2021-07-30.sql @@ -5,13 +5,13 @@ INSERT INTO "#__workflows" ("id", "asset_id", "published", "title", "description (NULL, 0, 1, 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '', 'com_modules.module', 1, 1, CURRENT_TIMESTAMP(), 0, CURRENT_TIMESTAMP(), 0, NULL, 0); -- --- Inserting the default stage for the new worklfow +-- Inserting the default stage for the new workflow -- INSERT INTO "#__workflow_stages" ("id", "asset_id", "ordering", "workflow_id", "published", "title", "description", "default", "checked_out_time", "checked_out") SELECT NULL, 0, 1, "id", 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1, NULL, 0 FROM "#__workflows" WHERE "title" = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES'; -- --- Inserting the transitions for the new worklfow +-- Inserting the transitions for the new workflow -- INSERT INTO "#__workflow_transitions" ("id", "asset_id", "published", "ordering", "workflow_id", "title", "description", "from_stage_id", "to_stage_id", "options") SELECT NULL, 0, 1, NULL, "w"."id", 'Unpublish', '', -1, "s"."id", '{"publishing":"0"}' FROM "#__workflows" as "w" INNER JOIN "#__workflow_stages" as "s" ON "w"."title" = 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES' AND "s"."title" = 'COM_WORKFLOW_BASIC_STAGE' AND "s"."extension" = 'com_modules.module'; From d80da65d5c7d06ea5c13826d0473b19e304c6d53 Mon Sep 17 00:00:00 2001 From: Yatharth Vyas Date: Fri, 20 Aug 2021 13:38:05 +0530 Subject: [PATCH 73/85] Apply suggestions from code review Co-authored-by: Phil E. Taylor --- .../com_modules/src/Extension/ModulesComponent.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/administrator/components/com_modules/src/Extension/ModulesComponent.php b/administrator/components/com_modules/src/Extension/ModulesComponent.php index 02170ce907542..1ad1953fbde2d 100644 --- a/administrator/components/com_modules/src/Extension/ModulesComponent.php +++ b/administrator/components/com_modules/src/Extension/ModulesComponent.php @@ -32,7 +32,10 @@ class ModulesComponent extends MVCComponent implements BootableExtensionInterfac use HTMLRegistryAwareTrait; use WorkflowServiceTrait; - /** @var array Supported functionality */ + /** + * @since __DEPLOY_VERSION_ + * @var array + */ protected $supportedFunctionality = [ 'core.state' => true, ]; @@ -99,9 +102,9 @@ public function getWorkflowContexts(): array { Factory::getLanguage()->load('com_modules', JPATH_ADMINISTRATOR); - $contexts = array( + $contexts = [ 'com_modules.module' => Text::_('COM_MODULES') - ); + ]; return $contexts; } @@ -146,8 +149,6 @@ public function filterTransitions(array $transitions, int $pk): array */ public function getCategoryWorkflowContext(?string $section = null): string { - $context = $this->getWorkflowContexts(); - - return array_key_first($context); + return array_key_first($this->getWorkflowContexts()); } } From 8d074598fa47ec6792fb23ec16a20dfde3eac31d Mon Sep 17 00:00:00 2001 From: Yatharth Vyas Date: Fri, 20 Aug 2021 13:39:19 +0530 Subject: [PATCH 74/85] comment formatting Co-authored-by: Phil E. Taylor --- administrator/components/com_modules/src/Model/ModuleModel.php | 2 +- administrator/components/com_modules/tmpl/module/edit.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/administrator/components/com_modules/src/Model/ModuleModel.php b/administrator/components/com_modules/src/Model/ModuleModel.php index a63e2a807ffb5..6af06207ec81c 100644 --- a/administrator/components/com_modules/src/Model/ModuleModel.php +++ b/administrator/components/com_modules/src/Model/ModuleModel.php @@ -1001,7 +1001,7 @@ protected function preprocessForm(Form $form, $data, $group = 'content') * The workflowPreprocessForm function enables the workflow plugins and adds the * transition field to the form. We do not need to add the transition field to the * form in the case of items so we seperately call the importWorkflowPlugins function. - */ + */ if (!empty(Factory::getApplication()->input->get('id'))) { $this->workflowPreprocessForm($form, $data); diff --git a/administrator/components/com_modules/tmpl/module/edit.php b/administrator/components/com_modules/tmpl/module/edit.php index 2b1948c3643bc..04601a130eaed 100644 --- a/administrator/components/com_modules/tmpl/module/edit.php +++ b/administrator/components/com_modules/tmpl/module/edit.php @@ -50,7 +50,7 @@ $layout = $isModal ? 'modal' : 'edit'; $tmpl = $isModal || $input->get('tmpl', '', 'cmd') === 'component' ? '&tmpl=component' : ''; -// If the module is already created then display the transition field else display the workflow selection field +// If the module is already created then display the transition field else display the workflow selection field. $workflowField = empty($input->get('id')) ? 'workflow_id' : 'transition'; ?> From 86c04ff1938408fe1cc830587b9ab245e8eda5ff Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Thu, 23 Sep 2021 19:18:11 +0530 Subject: [PATCH 75/85] phpcs --- .../components/com_modules/src/Extension/ModulesComponent.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/administrator/components/com_modules/src/Extension/ModulesComponent.php b/administrator/components/com_modules/src/Extension/ModulesComponent.php index 1ad1953fbde2d..f7c31691431c7 100644 --- a/administrator/components/com_modules/src/Extension/ModulesComponent.php +++ b/administrator/components/com_modules/src/Extension/ModulesComponent.php @@ -32,9 +32,9 @@ class ModulesComponent extends MVCComponent implements BootableExtensionInterfac use HTMLRegistryAwareTrait; use WorkflowServiceTrait; - /** + /** + * @var array * @since __DEPLOY_VERSION_ - * @var array */ protected $supportedFunctionality = [ 'core.state' => true, From af6dc87eb3363ecb67dc4b547e64ceccce39798e Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Sat, 2 Apr 2022 18:31:34 +0530 Subject: [PATCH 76/85] revert drone signature change --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index e6385d0e238a2..954b3df2b709c 100644 --- a/.drone.yml +++ b/.drone.yml @@ -420,6 +420,6 @@ steps: --- kind: signature -hmac: 53e23beca546bde246f812a726320210f33d231106cb154a65cc900ecbf7502e +hmac: d9707d261edba35bc6b70f09a1babee119cb0a88cebda40171248e5c0a8b135e ... From 7c2f68e682189c41197433e960a17e436cd85a04 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Sat, 2 Apr 2022 18:38:49 +0530 Subject: [PATCH 77/85] fix asset ids --- installation/sql/mysql/base.sql | 14 +++++++------- installation/sql/postgresql/base.sql | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/installation/sql/mysql/base.sql b/installation/sql/mysql/base.sql index 812d6e81ac2e3..2974edd5a60f1 100644 --- a/installation/sql/mysql/base.sql +++ b/installation/sql/mysql/base.sql @@ -108,11 +108,11 @@ INSERT INTO `#__assets` (`id`, `parent_id`, `lft`, `rgt`, `level`, `name`, `titl (88, 18, 126, 127, 2, 'com_modules.module.98', 'Logged-in Users', '{}'), (89, 18, 128, 129, 2, 'com_modules.module.90', 'Login Support', '{}'), (90, 1, 173, 174, 1, 'com_scheduler', 'com_scheduler', '{}'); -(89, 18, 130, 131, 2, 'com_modules.workflow.1', 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '{}'), -(90, 89, 132, 133, 3, 'com_modules.state.1', 'COM_WORKFLOW_BASIC_STAGE', '{}'), -(91, 89, 134, 135, 3, 'com_modules.transition.1', 'Publish', '{}'), -(92, 89, 136, 137, 3, 'com_modules.transition.2', 'Unpublish', '{}'), -(93, 89, 138, 139, 3, 'com_modules.transition.3', 'Trash', '{}'); +(91, 18, 130, 131, 2, 'com_modules.workflow.1', 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '{}'), +(92, 89, 132, 133, 3, 'com_modules.state.1', 'COM_WORKFLOW_BASIC_STAGE', '{}'), +(93, 89, 134, 135, 3, 'com_modules.transition.1', 'Publish', '{}'), +(94, 89, 136, 137, 3, 'com_modules.transition.2', 'Unpublish', '{}'), +(95, 89, 138, 139, 3, 'com_modules.transition.3', 'Trash', '{}'); -- -------------------------------------------------------- @@ -1095,7 +1095,7 @@ CREATE TABLE IF NOT EXISTS `#__workflows` ( INSERT INTO `#__workflows` (`id`, `asset_id`, `published`, `title`, `description`, `extension`, `default`, `ordering`, `created`, `created_by`, `modified`, `modified_by`) VALUES (1, 56, 1, 'COM_WORKFLOW_BASIC_WORKFLOW', '', 'com_content.article', 1, 1, CURRENT_TIMESTAMP(), 42, CURRENT_TIMESTAMP(), 42), -(2, 89, 1, 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '', 'com_modules.module', 1, 1, CURRENT_TIMESTAMP(), 42, CURRENT_TIMESTAMP(), 42); +(2, 91, 1, 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '', 'com_modules.module', 1, 1, CURRENT_TIMESTAMP(), 42, CURRENT_TIMESTAMP(), 42); -- -------------------------------------------------------- @@ -1145,7 +1145,7 @@ CREATE TABLE IF NOT EXISTS `#__workflow_stages` ( INSERT INTO `#__workflow_stages` (`id`, `asset_id`, `ordering`, `workflow_id`, `published`, `title`, `description`, `default`) VALUES (1, 0, 1, 1, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1), -(2, 90, 1, 2, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1); +(2, 92, 1, 2, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1); -- -------------------------------------------------------- diff --git a/installation/sql/postgresql/base.sql b/installation/sql/postgresql/base.sql index beae80a9debe9..e3bb684c3fa6b 100644 --- a/installation/sql/postgresql/base.sql +++ b/installation/sql/postgresql/base.sql @@ -114,11 +114,11 @@ INSERT INTO "#__assets" ("id", "parent_id", "lft", "rgt", "level", "name", "titl (88, 18, 126, 127, 2, 'com_modules.module.98', 'Logged-in Users', '{}'), (89, 18, 128, 129, 2, 'com_modules.module.90', 'Login Support', '{}'), (90, 1, 173, 174, 1, 'com_scheduler', 'com_scheduler', '{}'); -(89, 18, 130, 131, 2, 'com_modules.workflow.1', 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '{}'), -(90, 89, 132, 133, 3, 'com_modules.state.1', 'COM_WORKFLOW_BASIC_STAGE', '{}'), -(91, 89, 134, 135, 3, 'com_modules.transition.1', 'Publish', '{}'), -(92, 89, 136, 137, 3, 'com_modules.transition.2', 'Unpublish', '{}'), -(93, 89, 138, 139, 3, 'com_modules.transition.3', 'Trash', '{}'); +(91, 18, 130, 131, 2, 'com_modules.workflow.1', 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '{}'), +(92, 89, 132, 133, 3, 'com_modules.state.1', 'COM_WORKFLOW_BASIC_STAGE', '{}'), +(93, 89, 134, 135, 3, 'com_modules.transition.1', 'Publish', '{}'), +(94, 89, 136, 137, 3, 'com_modules.transition.2', 'Unpublish', '{}'), +(95, 89, 138, 139, 3, 'com_modules.transition.3', 'Trash', '{}'); SELECT setval('#__assets_id_seq', 91, false); @@ -1117,7 +1117,7 @@ CREATE INDEX "#__workflows_idx_checked_out" ON "#__workflows" ("checked_out"); INSERT INTO "#__workflows" ("id", "asset_id", "published", "title", "description", "extension", "default", "ordering", "created", "created_by", "modified", "modified_by") VALUES (1, 56, 1, 'COM_WORKFLOW_BASIC_WORKFLOW', '', 'com_content.article', 1, 1, CURRENT_TIMESTAMP, 42, CURRENT_TIMESTAMP, 42), -(2, 89, 1, 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '', 'com_modules.module', 1, 1, CURRENT_TIMESTAMP, 42, CURRENT_TIMESTAMP, 42); +(2, 91, 1, 'COM_WORKFLOW_BASIC_WORKFLOW_MODULES', '', 'com_modules.module', 1, 1, CURRENT_TIMESTAMP, 42, CURRENT_TIMESTAMP, 42); SELECT setval('#__workflows_id_seq', 3, false); @@ -1168,7 +1168,7 @@ CREATE INDEX "#__workflow_stages_idx_checked_out" ON "#__workflow_stages" ("chec INSERT INTO "#__workflow_stages" ("id", "asset_id", "ordering", "workflow_id", "published", "title", "description", "default") VALUES (1, 57, 1, 1, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1), -(2, 90, 1, 2, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1); +(2, 92, 1, 2, 1, 'COM_WORKFLOW_BASIC_STAGE', '', 1); SELECT setval('#__workflow_stages_id_seq', 3, false); From 762ad21f909ae7b9996a9287d77b6af74bf651d9 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Sat, 2 Apr 2022 18:41:38 +0530 Subject: [PATCH 78/85] fix asset id foreign keys --- installation/sql/mysql/base.sql | 6 +++--- installation/sql/postgresql/base.sql | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/installation/sql/mysql/base.sql b/installation/sql/mysql/base.sql index 2974edd5a60f1..1c8136aeb2867 100644 --- a/installation/sql/mysql/base.sql +++ b/installation/sql/mysql/base.sql @@ -1187,9 +1187,9 @@ INSERT INTO `#__workflow_transitions` (`id`, `asset_id`, `published`, `ordering` (5, 62, 1, 5, 1, 'Feature', '', -1, 1, '{"featuring":"1"}'), (6, 63, 1, 6, 1, 'Unfeature', '', -1, 1, '{"featuring":"0"}'), (7, 64, 1, 7, 1, 'Publish & Feature', '', -1, 1, '{"publishing":"1","featuring":"1"}'), -(8, 92, 1, 1, 2, 'Unpublish', '', -1, 2, '{"publishing":"0"}'), -(9, 91, 1, 2, 2, 'Publish', '', -1, 2, '{"publishing":"1"}'), -(10, 93, 1, 3, 2, 'Trash', '', -1, 2, '{"publishing":"-2"}'); +(8, 94, 1, 1, 2, 'Unpublish', '', -1, 2, '{"publishing":"0"}'), +(9, 93, 1, 2, 2, 'Publish', '', -1, 2, '{"publishing":"1"}'), +(10, 95, 1, 3, 2, 'Trash', '', -1, 2, '{"publishing":"-2"}'); INSERT INTO `#__workflow_associations` (`item_id`, `stage_id`, `extension`) SELECT `id`, 2, 'com_modules.module' FROM `#__modules`; diff --git a/installation/sql/postgresql/base.sql b/installation/sql/postgresql/base.sql index e3bb684c3fa6b..71945f5fedae6 100644 --- a/installation/sql/postgresql/base.sql +++ b/installation/sql/postgresql/base.sql @@ -1206,9 +1206,9 @@ INSERT INTO "#__workflow_transitions" ("id", "asset_id", "published", "ordering" (5, 62, 1, 5, 1, 'Feature', '', -1, 1, '{"featuring":"1"}'), (6, 63, 1, 6, 1, 'Unfeature', '', -1, 1, '{"featuring":"0"}'), (7, 64, 1, 7, 1, 'Publish & Feature', '', -1, 1, '{"publishing":"1","featuring":"1"}'), -(8, 92, 1, 1, 2, 'Unpublish', '', -1, 2, '{"publishing":"0"}'), -(9, 91, 1, 2, 2, 'Publish', '', -1, 2, '{"publishing":"1"}'), -(10, 93, 1, 3, 2, 'Trash', '', -1, 2, '{"publishing":"-2"}'); +(8, 94, 1, 1, 2, 'Unpublish', '', -1, 2, '{"publishing":"0"}'), +(9, 93, 1, 2, 2, 'Publish', '', -1, 2, '{"publishing":"1"}'), +(10, 95, 1, 3, 2, 'Trash', '', -1, 2, '{"publishing":"-2"}'); SELECT setval('#__workflow_transitions_id_seq', 11, false); From 3777ecd07089159b142ed67041e4322cd1c311fd Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Sat, 2 Apr 2022 18:56:00 +0530 Subject: [PATCH 79/85] correct the assets_id_seq value --- installation/sql/postgresql/base.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/installation/sql/postgresql/base.sql b/installation/sql/postgresql/base.sql index 71945f5fedae6..8157595c3500a 100644 --- a/installation/sql/postgresql/base.sql +++ b/installation/sql/postgresql/base.sql @@ -120,7 +120,7 @@ INSERT INTO "#__assets" ("id", "parent_id", "lft", "rgt", "level", "name", "titl (94, 89, 136, 137, 3, 'com_modules.transition.2', 'Unpublish', '{}'), (95, 89, 138, 139, 3, 'com_modules.transition.3', 'Trash', '{}'); -SELECT setval('#__assets_id_seq', 91, false); +SELECT setval('#__assets_id_seq', 96, false); -- -- Table structure for table `#__extensions` From 5d09d6ac8c7a48bf7541a6fce62a8d41aea9e7cd Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Sat, 2 Apr 2022 19:01:41 +0530 Subject: [PATCH 80/85] s/ModuleHelper/ModulesHelper --- .../components/com_modules/src/Extension/ModulesComponent.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/administrator/components/com_modules/src/Extension/ModulesComponent.php b/administrator/components/com_modules/src/Extension/ModulesComponent.php index f7c31691431c7..c3706006b08e8 100644 --- a/administrator/components/com_modules/src/Extension/ModulesComponent.php +++ b/administrator/components/com_modules/src/Extension/ModulesComponent.php @@ -135,7 +135,7 @@ public function getWorkflowTableBySection(?string $section = null): string */ public function filterTransitions(array $transitions, int $pk): array { - return ModuleHelper::filterTransitions($transitions, $pk); + return ModulesHelper::filterTransitions($transitions, $pk); } /** From 8cad5b362bb344eede3842b664659bd62a82fc42 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Sat, 2 Apr 2022 19:01:59 +0530 Subject: [PATCH 81/85] s/seperately/separately --- administrator/components/com_modules/src/Model/ModuleModel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/administrator/components/com_modules/src/Model/ModuleModel.php b/administrator/components/com_modules/src/Model/ModuleModel.php index 6af06207ec81c..db858d697be37 100644 --- a/administrator/components/com_modules/src/Model/ModuleModel.php +++ b/administrator/components/com_modules/src/Model/ModuleModel.php @@ -1000,7 +1000,7 @@ protected function preprocessForm(Form $form, $data, $group = 'content') /** * The workflowPreprocessForm function enables the workflow plugins and adds the * transition field to the form. We do not need to add the transition field to the - * form in the case of items so we seperately call the importWorkflowPlugins function. + * form in the case of items so we separately call the importWorkflowPlugins function. */ if (!empty(Factory::getApplication()->input->get('id'))) { From 8cd0c7dbc2e18879ac4361878ada49b94db0c838 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Sat, 2 Apr 2022 19:24:44 +0530 Subject: [PATCH 82/85] remove indentation before delimiter --- .../com_modules/tmpl/modules/default.php | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/administrator/components/com_modules/tmpl/modules/default.php b/administrator/components/com_modules/tmpl/modules/default.php index 1524583895364..9aa7e4259c307 100644 --- a/administrator/components/com_modules/tmpl/modules/default.php +++ b/administrator/components/com_modules/tmpl/modules/default.php @@ -45,20 +45,20 @@ if ($workflow_enabled) : - // @todo move the script to a file - $js = <<document->getWebAssetManager(); From f0408fb519ee9c1bbe2bafa1f0cadb295dc8bef2 Mon Sep 17 00:00:00 2001 From: YatharthVyas Date: Sat, 2 Apr 2022 19:27:56 +0530 Subject: [PATCH 83/85] add missing import for ModulesHelper --- .../components/com_modules/src/Extension/ModulesComponent.php | 1 + 1 file changed, 1 insertion(+) diff --git a/administrator/components/com_modules/src/Extension/ModulesComponent.php b/administrator/components/com_modules/src/Extension/ModulesComponent.php index c3706006b08e8..86764c5beb171 100644 --- a/administrator/components/com_modules/src/Extension/ModulesComponent.php +++ b/administrator/components/com_modules/src/Extension/ModulesComponent.php @@ -18,6 +18,7 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\Workflow\WorkflowServiceInterface; use Joomla\CMS\Workflow\WorkflowServiceTrait; +use Joomla\Component\Modules\Administrator\Helper\ModulesHelper; use Joomla\Component\Modules\Administrator\Service\HTML\Modules; use Psr\Container\ContainerInterface; From 41d42524057cdbc79a83753e7abefde20dbb3191 Mon Sep 17 00:00:00 2001 From: Joomla! Bot Date: Mon, 27 Jun 2022 23:38:15 +0200 Subject: [PATCH 84/85] Phase 1 convert BRANCH to PSR-12 --- .../com_content/src/Model/ArticlesModel.php | 1315 ++++----- .../com_content/tmpl/featured/default.php | 675 +++-- .../src/Extension/ModulesComponent.php | 250 +- .../com_modules/src/Helper/ModulesHelper.php | 629 ++-- .../com_modules/src/Model/ModuleModel.php | 2567 ++++++++--------- .../com_modules/src/Model/ModulesModel.php | 1181 ++++---- .../com_modules/src/View/Modules/HtmlView.php | 461 ++- .../com_modules/tmpl/module/edit.php | 299 +- .../com_modules/tmpl/modules/default.php | 458 ++- .../tmpl/modules/default_batch_body.php | 103 +- .../src/MVC/Model/WorkflowBehaviorTrait.php | 786 +++-- 11 files changed, 4200 insertions(+), 4524 deletions(-) diff --git a/administrator/components/com_content/src/Model/ArticlesModel.php b/administrator/components/com_content/src/Model/ArticlesModel.php index b9bbdc8d5de31..d467512173bea 100644 --- a/administrator/components/com_content/src/Model/ArticlesModel.php +++ b/administrator/components/com_content/src/Model/ArticlesModel.php @@ -1,4 +1,5 @@ get('workflow_enabled')) - { - $form->removeField('stage', 'filter'); - } - else - { - $ordering = $form->getField('fullordering', 'list'); - - $ordering->addOption('JSTAGE_ASC', ['value' => 'ws.title ASC']); - $ordering->addOption('JSTAGE_DESC', ['value' => 'ws.title DESC']); - } - - return $form; - } - - /** - * Method to auto-populate the model state. - * - * 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 1.6 - */ - protected function populateState($ordering = 'a.id', $direction = 'desc') - { - $app = Factory::getApplication(); - - $forcedLanguage = $app->input->get('forcedLanguage', '', 'cmd'); - - // Adjust the context to support modal layouts. - if ($layout = $app->input->get('layout')) - { - $this->context .= '.' . $layout; - } - - // Adjust the context to support forced languages. - if ($forcedLanguage) - { - $this->context .= '.' . $forcedLanguage; - } - - $search = $this->getUserStateFromRequest($this->context . '.filter.search', 'filter_search'); - $this->setState('filter.search', $search); - - $featured = $this->getUserStateFromRequest($this->context . '.filter.featured', 'filter_featured', ''); - $this->setState('filter.featured', $featured); - - $published = $this->getUserStateFromRequest($this->context . '.filter.published', 'filter_published', ''); - $this->setState('filter.published', $published); - - $level = $this->getUserStateFromRequest($this->context . '.filter.level', 'filter_level'); - $this->setState('filter.level', $level); - - $language = $this->getUserStateFromRequest($this->context . '.filter.language', 'filter_language', ''); - $this->setState('filter.language', $language); - - $formSubmitted = $app->input->post->get('form_submitted'); - - // Gets the value of a user state variable and sets it in the session - $this->getUserStateFromRequest($this->context . '.filter.access', 'filter_access'); - $this->getUserStateFromRequest($this->context . '.filter.author_id', 'filter_author_id'); - $this->getUserStateFromRequest($this->context . '.filter.category_id', 'filter_category_id'); - $this->getUserStateFromRequest($this->context . '.filter.tag', 'filter_tag', ''); - - if ($formSubmitted) - { - $access = $app->input->post->get('access'); - $this->setState('filter.access', $access); - - $authorId = $app->input->post->get('author_id'); - $this->setState('filter.author_id', $authorId); - - $categoryId = $app->input->post->get('category_id'); - $this->setState('filter.category_id', $categoryId); - - $tag = $app->input->post->get('tag'); - $this->setState('filter.tag', $tag); - } - - // List state information. - parent::populateState($ordering, $direction); - - // Force a language - if (!empty($forcedLanguage)) - { - $this->setState('filter.language', $forcedLanguage); - $this->setState('filter.forcedLanguage', $forcedLanguage); - } - } - - /** - * Method to get a store id based on model configuration state. - * - * This is necessary because the model is used by the component and - * different modules that might need different sets of data or different - * ordering requirements. - * - * @param string $id A prefix for the store id. - * - * @return string A store id. - * - * @since 1.6 - */ - protected function getStoreId($id = '') - { - // Compile the store id. - $id .= ':' . $this->getState('filter.search'); - $id .= ':' . serialize($this->getState('filter.access')); - $id .= ':' . $this->getState('filter.published'); - $id .= ':' . serialize($this->getState('filter.category_id')); - $id .= ':' . serialize($this->getState('filter.author_id')); - $id .= ':' . $this->getState('filter.language'); - $id .= ':' . serialize($this->getState('filter.tag')); - - return parent::getStoreId($id); - } - - /** - * Build an SQL query to load the list data. - * - * @return \Joomla\Database\DatabaseQuery - * - * @since 1.6 - */ - protected function getListQuery() - { - // Create a new query object. - $db = $this->getDatabase(); - $query = $db->getQuery(true); - $user = Factory::getUser(); - - $params = ComponentHelper::getParams('com_content'); - - // Select the required fields from the table. - $query->select( - $this->getState( - 'list.select', - [ - $db->quoteName('a.id'), - $db->quoteName('a.asset_id'), - $db->quoteName('a.title'), - $db->quoteName('a.alias'), - $db->quoteName('a.checked_out'), - $db->quoteName('a.checked_out_time'), - $db->quoteName('a.catid'), - $db->quoteName('a.state'), - $db->quoteName('a.access'), - $db->quoteName('a.created'), - $db->quoteName('a.created_by'), - $db->quoteName('a.created_by_alias'), - $db->quoteName('a.modified'), - $db->quoteName('a.ordering'), - $db->quoteName('a.featured'), - $db->quoteName('a.language'), - $db->quoteName('a.hits'), - $db->quoteName('a.publish_up'), - $db->quoteName('a.publish_down'), - $db->quoteName('a.introtext'), - $db->quoteName('a.fulltext'), - $db->quoteName('a.note'), - $db->quoteName('a.images'), - $db->quoteName('a.metakey'), - $db->quoteName('a.metadesc'), - $db->quoteName('a.metadata'), - $db->quoteName('a.version'), - ] - ) - ) - ->select( - [ - $db->quoteName('fp.featured_up'), - $db->quoteName('fp.featured_down'), - $db->quoteName('l.title', 'language_title'), - $db->quoteName('l.image', 'language_image'), - $db->quoteName('uc.name', 'editor'), - $db->quoteName('ag.title', 'access_level'), - $db->quoteName('c.title', 'category_title'), - $db->quoteName('c.created_user_id', 'category_uid'), - $db->quoteName('c.level', 'category_level'), - $db->quoteName('c.published', 'category_published'), - $db->quoteName('parent.title', 'parent_category_title'), - $db->quoteName('parent.id', 'parent_category_id'), - $db->quoteName('parent.created_user_id', 'parent_category_uid'), - $db->quoteName('parent.level', 'parent_category_level'), - $db->quoteName('ua.name', 'author_name'), - $db->quoteName('wa.stage_id', 'stage_id'), - $db->quoteName('ws.title', 'stage_title'), - $db->quoteName('ws.workflow_id', 'workflow_id'), - $db->quoteName('w.title', 'workflow_title'), - ] - ) - ->from($db->quoteName('#__content', 'a')) - ->where($db->quoteName('wa.extension') . ' = ' . $db->quote('com_content.article')) - ->join('LEFT', $db->quoteName('#__languages', 'l'), $db->quoteName('l.lang_code') . ' = ' . $db->quoteName('a.language')) - ->join('LEFT', $db->quoteName('#__content_frontpage', 'fp'), $db->quoteName('fp.content_id') . ' = ' . $db->quoteName('a.id')) - ->join('LEFT', $db->quoteName('#__users', 'uc'), $db->quoteName('uc.id') . ' = ' . $db->quoteName('a.checked_out')) - ->join('LEFT', $db->quoteName('#__viewlevels', 'ag'), $db->quoteName('ag.id') . ' = ' . $db->quoteName('a.access')) - ->join('LEFT', $db->quoteName('#__categories', 'c'), $db->quoteName('c.id') . ' = ' . $db->quoteName('a.catid')) - ->join('LEFT', $db->quoteName('#__categories', 'parent'), $db->quoteName('parent.id') . ' = ' . $db->quoteName('c.parent_id')) - ->join('LEFT', $db->quoteName('#__users', 'ua'), $db->quoteName('ua.id') . ' = ' . $db->quoteName('a.created_by')) - ->join('INNER', $db->quoteName('#__workflow_associations', 'wa'), $db->quoteName('wa.item_id') . ' = ' . $db->quoteName('a.id')) - ->join('INNER', $db->quoteName('#__workflow_stages', 'ws'), $db->quoteName('ws.id') . ' = ' . $db->quoteName('wa.stage_id')) - ->join('INNER', $db->quoteName('#__workflows', 'w'), $db->quoteName('w.id') . ' = ' . $db->quoteName('ws.workflow_id')) - ->where($db->quoteName('wa.extension') . ' = ' . $db->quote('com_content.article')); - - if (PluginHelper::isEnabled('content', 'vote')) - { - $query->select( - [ - 'COALESCE(NULLIF(ROUND(' . $db->quoteName('v.rating_sum') . ' / ' . $db->quoteName('v.rating_count') . ', 0), 0), 0)' - . ' AS ' . $db->quoteName('rating'), - 'COALESCE(NULLIF(' . $db->quoteName('v.rating_count') . ', 0), 0) AS ' . $db->quoteName('rating_count'), - ] - ) - ->join('LEFT', $db->quoteName('#__content_rating', 'v'), $db->quoteName('a.id') . ' = ' . $db->quoteName('v.content_id')); - } - - // Join over the associations. - if (Associations::isEnabled()) - { - $subQuery = $db->getQuery(true) - ->select('COUNT(' . $db->quoteName('asso1.id') . ') > 1') - ->from($db->quoteName('#__associations', 'asso1')) - ->join('INNER', $db->quoteName('#__associations', 'asso2'), $db->quoteName('asso1.key') . ' = ' . $db->quoteName('asso2.key')) - ->where( - [ - $db->quoteName('asso1.id') . ' = ' . $db->quoteName('a.id'), - $db->quoteName('asso1.context') . ' = ' . $db->quote('com_content.item'), - ] - ); - - $query->select('(' . $subQuery . ') AS ' . $db->quoteName('association')); - } - - // Filter by access level. - $access = $this->getState('filter.access'); - - if (is_numeric($access)) - { - $access = (int) $access; - $query->where($db->quoteName('a.access') . ' = :access') - ->bind(':access', $access, ParameterType::INTEGER); - } - elseif (is_array($access)) - { - $access = ArrayHelper::toInteger($access); - $query->whereIn($db->quoteName('a.access'), $access); - } - - // Filter by featured. - $featured = (string) $this->getState('filter.featured'); - - if (\in_array($featured, ['0','1'])) - { - $featured = (int) $featured; - $query->where($db->quoteName('a.featured') . ' = :featured') - ->bind(':featured', $featured, ParameterType::INTEGER); - } - - // Filter by access level on categories. - if (!$user->authorise('core.admin')) - { - $groups = $user->getAuthorisedViewLevels(); - $query->whereIn($db->quoteName('a.access'), $groups); - $query->whereIn($db->quoteName('c.access'), $groups); - } - - // Filter by published state - $workflowStage = (string) $this->getState('filter.stage'); - - if ($params->get('workflow_enabled') && is_numeric($workflowStage)) - { - $workflowStage = (int) $workflowStage; - $query->where($db->quoteName('wa.stage_id') . ' = :stage') - ->bind(':stage', $workflowStage, ParameterType::INTEGER); - } - - $published = (string) $this->getState('filter.published'); - - if ($published !== '*') - { - if (is_numeric($published)) - { - $state = (int) $published; - $query->where($db->quoteName('a.state') . ' = :state') - ->bind(':state', $state, ParameterType::INTEGER); - } - elseif (!is_numeric($workflowStage)) - { - $query->whereIn( - $db->quoteName('a.state'), - [ - ContentComponent::CONDITION_PUBLISHED, - ContentComponent::CONDITION_UNPUBLISHED, - ] - ); - } - } - - // Filter by categories and by level - $categoryId = $this->getState('filter.category_id', array()); - $level = (int) $this->getState('filter.level'); - - if (!is_array($categoryId)) - { - $categoryId = $categoryId ? array($categoryId) : array(); - } - - // Case: Using both categories filter and by level filter - if (count($categoryId)) - { - $categoryId = ArrayHelper::toInteger($categoryId); - $categoryTable = Table::getInstance('Category', 'JTable'); - $subCatItemsWhere = array(); - - foreach ($categoryId as $key => $filter_catid) - { - $categoryTable->load($filter_catid); - - // Because values to $query->bind() are passed by reference, using $query->bindArray() here instead to prevent overwriting. - $valuesToBind = [$categoryTable->lft, $categoryTable->rgt]; - - if ($level) - { - $valuesToBind[] = $level + $categoryTable->level - 1; - } - - // Bind values and get parameter names. - $bounded = $query->bindArray($valuesToBind); - - $categoryWhere = $db->quoteName('c.lft') . ' >= ' . $bounded[0] . ' AND ' . $db->quoteName('c.rgt') . ' <= ' . $bounded[1]; - - if ($level) - { - $categoryWhere .= ' AND ' . $db->quoteName('c.level') . ' <= ' . $bounded[2]; - } - - $subCatItemsWhere[] = '(' . $categoryWhere . ')'; - } - - $query->where('(' . implode(' OR ', $subCatItemsWhere) . ')'); - } - - // Case: Using only the by level filter - elseif ($level = (int) $level) - { - $query->where($db->quoteName('c.level') . ' <= :level') - ->bind(':level', $level, ParameterType::INTEGER); - } - - // Filter by author - $authorId = $this->getState('filter.author_id'); - - if (is_numeric($authorId)) - { - $authorId = (int) $authorId; - $type = $this->getState('filter.author_id.include', true) ? ' = ' : ' <> '; - $query->where($db->quoteName('a.created_by') . $type . ':authorId') - ->bind(':authorId', $authorId, ParameterType::INTEGER); - } - elseif (is_array($authorId)) - { - // Check to see if by_me is in the array - if (\in_array('by_me', $authorId)) - - // Replace by_me with the current user id in the array - { - $authorId['by_me'] = $user->id; - } - - $authorId = ArrayHelper::toInteger($authorId); - $query->whereIn($db->quoteName('a.created_by'), $authorId); - } - - // Filter by search in title. - $search = $this->getState('filter.search'); - - if (!empty($search)) - { - if (stripos($search, 'id:') === 0) - { - $search = (int) substr($search, 3); - $query->where($db->quoteName('a.id') . ' = :search') - ->bind(':search', $search, ParameterType::INTEGER); - } - elseif (stripos($search, 'author:') === 0) - { - $search = '%' . substr($search, 7) . '%'; - $query->where('(' . $db->quoteName('ua.name') . ' LIKE :search1 OR ' . $db->quoteName('ua.username') . ' LIKE :search2)') - ->bind([':search1', ':search2'], $search); - } - elseif (stripos($search, 'content:') === 0) - { - $search = '%' . substr($search, 8) . '%'; - $query->where('(' . $db->quoteName('a.introtext') . ' LIKE :search1 OR ' . $db->quoteName('a.fulltext') . ' LIKE :search2)') - ->bind([':search1', ':search2'], $search); - } - else - { - $search = '%' . str_replace(' ', '%', trim($search)) . '%'; - $query->where( - '(' . $db->quoteName('a.title') . ' LIKE :search1 OR ' . $db->quoteName('a.alias') . ' LIKE :search2' - . ' OR ' . $db->quoteName('a.note') . ' LIKE :search3)' - ) - ->bind([':search1', ':search2', ':search3'], $search); - } - } - - // Filter on the language. - if ($language = $this->getState('filter.language')) - { - $query->where($db->quoteName('a.language') . ' = :language') - ->bind(':language', $language); - } - - // Filter by a single or group of tags. - $tag = $this->getState('filter.tag'); - - // Run simplified query when filtering by one tag. - if (\is_array($tag) && \count($tag) === 1) - { - $tag = $tag[0]; - } - - if ($tag && \is_array($tag)) - { - $tag = ArrayHelper::toInteger($tag); - - $subQuery = $db->getQuery(true) - ->select('DISTINCT ' . $db->quoteName('content_item_id')) - ->from($db->quoteName('#__contentitem_tag_map')) - ->where( - [ - $db->quoteName('tag_id') . ' IN (' . implode(',', $query->bindArray($tag)) . ')', - $db->quoteName('type_alias') . ' = ' . $db->quote('com_content.article'), - ] - ); - - $query->join( - 'INNER', - '(' . $subQuery . ') AS ' . $db->quoteName('tagmap'), - $db->quoteName('tagmap.content_item_id') . ' = ' . $db->quoteName('a.id') - ); - } - elseif ($tag = (int) $tag) - { - $query->join( - 'INNER', - $db->quoteName('#__contentitem_tag_map', 'tagmap'), - $db->quoteName('tagmap.content_item_id') . ' = ' . $db->quoteName('a.id') - ) - ->where( - [ - $db->quoteName('tagmap.tag_id') . ' = :tag', - $db->quoteName('tagmap.type_alias') . ' = ' . $db->quote('com_content.article'), - ] - ) - ->bind(':tag', $tag, ParameterType::INTEGER); - } - - // Add the list ordering clause. - $orderCol = $this->state->get('list.ordering', 'a.id'); - $orderDirn = $this->state->get('list.direction', 'DESC'); - - if ($orderCol === 'a.ordering' || $orderCol === 'category_title') - { - $ordering = [ - $db->quoteName('c.title') . ' ' . $db->escape($orderDirn), - $db->quoteName('a.ordering') . ' ' . $db->escape($orderDirn), - ]; - } - else - { - $ordering = $db->escape($orderCol) . ' ' . $db->escape($orderDirn); - } - - $query->order($ordering); - - return $query; - } - - /** - * Method to get all transitions at once for all articles - * - * @return array|boolean - * - * @since 4.0.0 - */ - public function getTransitions() - { - // Get a storage key. - $store = $this->getStoreId('getTransitions'); - - // Try to load the data from internal storage. - if (isset($this->cache[$store])) - { - return $this->cache[$store]; - } - - $db = $this->getDatabase(); - $user = Factory::getUser(); - - $items = $this->getItems(); - - if ($items === false) - { - return false; - } - - $stage_ids = ArrayHelper::getColumn($items, 'stage_id'); - $stage_ids = ArrayHelper::toInteger($stage_ids); - $stage_ids = array_values(array_unique(array_filter($stage_ids))); - - $workflow_ids = ArrayHelper::getColumn($items, 'workflow_id'); - $workflow_ids = ArrayHelper::toInteger($workflow_ids); - $workflow_ids = array_values(array_unique(array_filter($workflow_ids))); - - $this->cache[$store] = array(); - - try - { - if (count($stage_ids) || count($workflow_ids)) - { - Factory::getLanguage()->load('com_workflow', JPATH_ADMINISTRATOR); - - $query = $db->getQuery(true); - - $query ->select( - [ - $db->quoteName('t.id', 'value'), - $db->quoteName('t.title', 'text'), - $db->quoteName('t.from_stage_id'), - $db->quoteName('t.to_stage_id'), - $db->quoteName('s.id', 'stage_id'), - $db->quoteName('s.title', 'stage_title'), - $db->quoteName('t.workflow_id'), - ] - ) - ->from($db->quoteName('#__workflow_transitions', 't')) - ->innerJoin( - $db->quoteName('#__workflow_stages', 's'), - $db->quoteName('t.to_stage_id') . ' = ' . $db->quoteName('s.id') - ) - ->where( - [ - $db->quoteName('t.published') . ' = 1', - $db->quoteName('s.published') . ' = 1', - ] - ) - ->order($db->quoteName('t.ordering')); - - $where = []; - - if (count($stage_ids)) - { - $where[] = $db->quoteName('t.from_stage_id') . ' IN (' . implode(',', $query->bindArray($stage_ids)) . ')'; - } - - if (count($workflow_ids)) - { - $where[] = '(' . $db->quoteName('t.from_stage_id') . ' = -1 AND ' . $db->quoteName('t.workflow_id') . ' IN (' . implode(',', $query->bindArray($workflow_ids)) . '))'; - } - - $query->where('((' . implode(') OR (', $where) . '))'); - - $transitions = $db->setQuery($query)->loadAssocList(); - - foreach ($transitions as $key => $transition) - { - if (!$user->authorise('core.execute.transition', 'com_content.transition.' . (int) $transition['value'])) - { - unset($transitions[$key]); - } - - $transitions[$key]['text'] = Text::_($transition['text']); - } - - $this->cache[$store] = $transitions; - } - } - catch (\RuntimeException $e) - { - $this->setError($e->getMessage()); - - return false; - } - - return $this->cache[$store]; - } - - /** - * Method to get a list of articles. - * Overridden to add item type alias. - * - * @return mixed An array of data items on success, false on failure. - * - * @since 4.0.0 - */ - public function getItems() - { - $items = parent::getItems(); - - foreach ($items as $item) - { - $item->typeAlias = 'com_content.article'; - - if (isset($item->metadata)) - { - $registry = new Registry($item->metadata); - $item->metadata = $registry->toArray(); - } - } - - return $items; - } + /** + * Constructor. + * + * @param array $config An optional associative array of configuration settings. + * + * @since 1.6 + * @see \Joomla\CMS\MVC\Controller\BaseController + */ + public function __construct($config = array()) + { + if (empty($config['filter_fields'])) { + $config['filter_fields'] = array( + 'id', 'a.id', + 'title', 'a.title', + 'alias', 'a.alias', + 'checked_out', 'a.checked_out', + 'checked_out_time', 'a.checked_out_time', + 'catid', 'a.catid', 'category_title', + 'state', 'a.state', + 'access', 'a.access', 'access_level', + 'created', 'a.created', + 'modified', 'a.modified', + 'created_by', 'a.created_by', + 'created_by_alias', 'a.created_by_alias', + 'ordering', 'a.ordering', + 'featured', 'a.featured', + 'featured_up', 'fp.featured_up', + 'featured_down', 'fp.featured_down', + 'language', 'a.language', + 'hits', 'a.hits', + 'publish_up', 'a.publish_up', + 'publish_down', 'a.publish_down', + 'published', 'a.published', + 'author_id', + 'category_id', + 'level', + 'tag', + 'rating_count', 'rating', + 'stage', 'wa.stage_id', + 'ws.title' + ); + + if (Associations::isEnabled()) { + $config['filter_fields'][] = 'association'; + } + } + + parent::__construct($config); + } + + /** + * Get the filter form + * + * @param array $data data + * @param boolean $loadData load current data + * + * @return \Joomla\CMS\Form\Form|null The Form object or null if the form can't be found + * + * @since 3.2 + */ + public function getFilterForm($data = array(), $loadData = true) + { + $form = parent::getFilterForm($data, $loadData); + + $params = ComponentHelper::getParams('com_content'); + + if (!$params->get('workflow_enabled')) { + $form->removeField('stage', 'filter'); + } else { + $ordering = $form->getField('fullordering', 'list'); + + $ordering->addOption('JSTAGE_ASC', ['value' => 'ws.title ASC']); + $ordering->addOption('JSTAGE_DESC', ['value' => 'ws.title DESC']); + } + + return $form; + } + + /** + * Method to auto-populate the model state. + * + * 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 1.6 + */ + protected function populateState($ordering = 'a.id', $direction = 'desc') + { + $app = Factory::getApplication(); + + $forcedLanguage = $app->input->get('forcedLanguage', '', 'cmd'); + + // Adjust the context to support modal layouts. + if ($layout = $app->input->get('layout')) { + $this->context .= '.' . $layout; + } + + // Adjust the context to support forced languages. + if ($forcedLanguage) { + $this->context .= '.' . $forcedLanguage; + } + + $search = $this->getUserStateFromRequest($this->context . '.filter.search', 'filter_search'); + $this->setState('filter.search', $search); + + $featured = $this->getUserStateFromRequest($this->context . '.filter.featured', 'filter_featured', ''); + $this->setState('filter.featured', $featured); + + $published = $this->getUserStateFromRequest($this->context . '.filter.published', 'filter_published', ''); + $this->setState('filter.published', $published); + + $level = $this->getUserStateFromRequest($this->context . '.filter.level', 'filter_level'); + $this->setState('filter.level', $level); + + $language = $this->getUserStateFromRequest($this->context . '.filter.language', 'filter_language', ''); + $this->setState('filter.language', $language); + + $formSubmitted = $app->input->post->get('form_submitted'); + + // Gets the value of a user state variable and sets it in the session + $this->getUserStateFromRequest($this->context . '.filter.access', 'filter_access'); + $this->getUserStateFromRequest($this->context . '.filter.author_id', 'filter_author_id'); + $this->getUserStateFromRequest($this->context . '.filter.category_id', 'filter_category_id'); + $this->getUserStateFromRequest($this->context . '.filter.tag', 'filter_tag', ''); + + if ($formSubmitted) { + $access = $app->input->post->get('access'); + $this->setState('filter.access', $access); + + $authorId = $app->input->post->get('author_id'); + $this->setState('filter.author_id', $authorId); + + $categoryId = $app->input->post->get('category_id'); + $this->setState('filter.category_id', $categoryId); + + $tag = $app->input->post->get('tag'); + $this->setState('filter.tag', $tag); + } + + // List state information. + parent::populateState($ordering, $direction); + + // Force a language + if (!empty($forcedLanguage)) { + $this->setState('filter.language', $forcedLanguage); + $this->setState('filter.forcedLanguage', $forcedLanguage); + } + } + + /** + * Method to get a store id based on model configuration state. + * + * This is necessary because the model is used by the component and + * different modules that might need different sets of data or different + * ordering requirements. + * + * @param string $id A prefix for the store id. + * + * @return string A store id. + * + * @since 1.6 + */ + protected function getStoreId($id = '') + { + // Compile the store id. + $id .= ':' . $this->getState('filter.search'); + $id .= ':' . serialize($this->getState('filter.access')); + $id .= ':' . $this->getState('filter.published'); + $id .= ':' . serialize($this->getState('filter.category_id')); + $id .= ':' . serialize($this->getState('filter.author_id')); + $id .= ':' . $this->getState('filter.language'); + $id .= ':' . serialize($this->getState('filter.tag')); + + return parent::getStoreId($id); + } + + /** + * Build an SQL query to load the list data. + * + * @return \Joomla\Database\DatabaseQuery + * + * @since 1.6 + */ + protected function getListQuery() + { + // Create a new query object. + $db = $this->getDatabase(); + $query = $db->getQuery(true); + $user = Factory::getUser(); + + $params = ComponentHelper::getParams('com_content'); + + // Select the required fields from the table. + $query->select( + $this->getState( + 'list.select', + [ + $db->quoteName('a.id'), + $db->quoteName('a.asset_id'), + $db->quoteName('a.title'), + $db->quoteName('a.alias'), + $db->quoteName('a.checked_out'), + $db->quoteName('a.checked_out_time'), + $db->quoteName('a.catid'), + $db->quoteName('a.state'), + $db->quoteName('a.access'), + $db->quoteName('a.created'), + $db->quoteName('a.created_by'), + $db->quoteName('a.created_by_alias'), + $db->quoteName('a.modified'), + $db->quoteName('a.ordering'), + $db->quoteName('a.featured'), + $db->quoteName('a.language'), + $db->quoteName('a.hits'), + $db->quoteName('a.publish_up'), + $db->quoteName('a.publish_down'), + $db->quoteName('a.introtext'), + $db->quoteName('a.fulltext'), + $db->quoteName('a.note'), + $db->quoteName('a.images'), + $db->quoteName('a.metakey'), + $db->quoteName('a.metadesc'), + $db->quoteName('a.metadata'), + $db->quoteName('a.version'), + ] + ) + ) + ->select( + [ + $db->quoteName('fp.featured_up'), + $db->quoteName('fp.featured_down'), + $db->quoteName('l.title', 'language_title'), + $db->quoteName('l.image', 'language_image'), + $db->quoteName('uc.name', 'editor'), + $db->quoteName('ag.title', 'access_level'), + $db->quoteName('c.title', 'category_title'), + $db->quoteName('c.created_user_id', 'category_uid'), + $db->quoteName('c.level', 'category_level'), + $db->quoteName('c.published', 'category_published'), + $db->quoteName('parent.title', 'parent_category_title'), + $db->quoteName('parent.id', 'parent_category_id'), + $db->quoteName('parent.created_user_id', 'parent_category_uid'), + $db->quoteName('parent.level', 'parent_category_level'), + $db->quoteName('ua.name', 'author_name'), + $db->quoteName('wa.stage_id', 'stage_id'), + $db->quoteName('ws.title', 'stage_title'), + $db->quoteName('ws.workflow_id', 'workflow_id'), + $db->quoteName('w.title', 'workflow_title'), + ] + ) + ->from($db->quoteName('#__content', 'a')) + ->where($db->quoteName('wa.extension') . ' = ' . $db->quote('com_content.article')) + ->join('LEFT', $db->quoteName('#__languages', 'l'), $db->quoteName('l.lang_code') . ' = ' . $db->quoteName('a.language')) + ->join('LEFT', $db->quoteName('#__content_frontpage', 'fp'), $db->quoteName('fp.content_id') . ' = ' . $db->quoteName('a.id')) + ->join('LEFT', $db->quoteName('#__users', 'uc'), $db->quoteName('uc.id') . ' = ' . $db->quoteName('a.checked_out')) + ->join('LEFT', $db->quoteName('#__viewlevels', 'ag'), $db->quoteName('ag.id') . ' = ' . $db->quoteName('a.access')) + ->join('LEFT', $db->quoteName('#__categories', 'c'), $db->quoteName('c.id') . ' = ' . $db->quoteName('a.catid')) + ->join('LEFT', $db->quoteName('#__categories', 'parent'), $db->quoteName('parent.id') . ' = ' . $db->quoteName('c.parent_id')) + ->join('LEFT', $db->quoteName('#__users', 'ua'), $db->quoteName('ua.id') . ' = ' . $db->quoteName('a.created_by')) + ->join('INNER', $db->quoteName('#__workflow_associations', 'wa'), $db->quoteName('wa.item_id') . ' = ' . $db->quoteName('a.id')) + ->join('INNER', $db->quoteName('#__workflow_stages', 'ws'), $db->quoteName('ws.id') . ' = ' . $db->quoteName('wa.stage_id')) + ->join('INNER', $db->quoteName('#__workflows', 'w'), $db->quoteName('w.id') . ' = ' . $db->quoteName('ws.workflow_id')) + ->where($db->quoteName('wa.extension') . ' = ' . $db->quote('com_content.article')); + + if (PluginHelper::isEnabled('content', 'vote')) { + $query->select( + [ + 'COALESCE(NULLIF(ROUND(' . $db->quoteName('v.rating_sum') . ' / ' . $db->quoteName('v.rating_count') . ', 0), 0), 0)' + . ' AS ' . $db->quoteName('rating'), + 'COALESCE(NULLIF(' . $db->quoteName('v.rating_count') . ', 0), 0) AS ' . $db->quoteName('rating_count'), + ] + ) + ->join('LEFT', $db->quoteName('#__content_rating', 'v'), $db->quoteName('a.id') . ' = ' . $db->quoteName('v.content_id')); + } + + // Join over the associations. + if (Associations::isEnabled()) { + $subQuery = $db->getQuery(true) + ->select('COUNT(' . $db->quoteName('asso1.id') . ') > 1') + ->from($db->quoteName('#__associations', 'asso1')) + ->join('INNER', $db->quoteName('#__associations', 'asso2'), $db->quoteName('asso1.key') . ' = ' . $db->quoteName('asso2.key')) + ->where( + [ + $db->quoteName('asso1.id') . ' = ' . $db->quoteName('a.id'), + $db->quoteName('asso1.context') . ' = ' . $db->quote('com_content.item'), + ] + ); + + $query->select('(' . $subQuery . ') AS ' . $db->quoteName('association')); + } + + // Filter by access level. + $access = $this->getState('filter.access'); + + if (is_numeric($access)) { + $access = (int) $access; + $query->where($db->quoteName('a.access') . ' = :access') + ->bind(':access', $access, ParameterType::INTEGER); + } elseif (is_array($access)) { + $access = ArrayHelper::toInteger($access); + $query->whereIn($db->quoteName('a.access'), $access); + } + + // Filter by featured. + $featured = (string) $this->getState('filter.featured'); + + if (\in_array($featured, ['0','1'])) { + $featured = (int) $featured; + $query->where($db->quoteName('a.featured') . ' = :featured') + ->bind(':featured', $featured, ParameterType::INTEGER); + } + + // Filter by access level on categories. + if (!$user->authorise('core.admin')) { + $groups = $user->getAuthorisedViewLevels(); + $query->whereIn($db->quoteName('a.access'), $groups); + $query->whereIn($db->quoteName('c.access'), $groups); + } + + // Filter by published state + $workflowStage = (string) $this->getState('filter.stage'); + + if ($params->get('workflow_enabled') && is_numeric($workflowStage)) { + $workflowStage = (int) $workflowStage; + $query->where($db->quoteName('wa.stage_id') . ' = :stage') + ->bind(':stage', $workflowStage, ParameterType::INTEGER); + } + + $published = (string) $this->getState('filter.published'); + + if ($published !== '*') { + if (is_numeric($published)) { + $state = (int) $published; + $query->where($db->quoteName('a.state') . ' = :state') + ->bind(':state', $state, ParameterType::INTEGER); + } elseif (!is_numeric($workflowStage)) { + $query->whereIn( + $db->quoteName('a.state'), + [ + ContentComponent::CONDITION_PUBLISHED, + ContentComponent::CONDITION_UNPUBLISHED, + ] + ); + } + } + + // Filter by categories and by level + $categoryId = $this->getState('filter.category_id', array()); + $level = (int) $this->getState('filter.level'); + + if (!is_array($categoryId)) { + $categoryId = $categoryId ? array($categoryId) : array(); + } + + // Case: Using both categories filter and by level filter + if (count($categoryId)) { + $categoryId = ArrayHelper::toInteger($categoryId); + $categoryTable = Table::getInstance('Category', 'JTable'); + $subCatItemsWhere = array(); + + foreach ($categoryId as $key => $filter_catid) { + $categoryTable->load($filter_catid); + + // Because values to $query->bind() are passed by reference, using $query->bindArray() here instead to prevent overwriting. + $valuesToBind = [$categoryTable->lft, $categoryTable->rgt]; + + if ($level) { + $valuesToBind[] = $level + $categoryTable->level - 1; + } + + // Bind values and get parameter names. + $bounded = $query->bindArray($valuesToBind); + + $categoryWhere = $db->quoteName('c.lft') . ' >= ' . $bounded[0] . ' AND ' . $db->quoteName('c.rgt') . ' <= ' . $bounded[1]; + + if ($level) { + $categoryWhere .= ' AND ' . $db->quoteName('c.level') . ' <= ' . $bounded[2]; + } + + $subCatItemsWhere[] = '(' . $categoryWhere . ')'; + } + + $query->where('(' . implode(' OR ', $subCatItemsWhere) . ')'); + } + + // Case: Using only the by level filter + elseif ($level = (int) $level) { + $query->where($db->quoteName('c.level') . ' <= :level') + ->bind(':level', $level, ParameterType::INTEGER); + } + + // Filter by author + $authorId = $this->getState('filter.author_id'); + + if (is_numeric($authorId)) { + $authorId = (int) $authorId; + $type = $this->getState('filter.author_id.include', true) ? ' = ' : ' <> '; + $query->where($db->quoteName('a.created_by') . $type . ':authorId') + ->bind(':authorId', $authorId, ParameterType::INTEGER); + } elseif (is_array($authorId)) { + // Check to see if by_me is in the array + if (\in_array('by_me', $authorId)) { + // Replace by_me with the current user id in the array + $authorId['by_me'] = $user->id; + } + + $authorId = ArrayHelper::toInteger($authorId); + $query->whereIn($db->quoteName('a.created_by'), $authorId); + } + + // Filter by search in title. + $search = $this->getState('filter.search'); + + if (!empty($search)) { + if (stripos($search, 'id:') === 0) { + $search = (int) substr($search, 3); + $query->where($db->quoteName('a.id') . ' = :search') + ->bind(':search', $search, ParameterType::INTEGER); + } elseif (stripos($search, 'author:') === 0) { + $search = '%' . substr($search, 7) . '%'; + $query->where('(' . $db->quoteName('ua.name') . ' LIKE :search1 OR ' . $db->quoteName('ua.username') . ' LIKE :search2)') + ->bind([':search1', ':search2'], $search); + } elseif (stripos($search, 'content:') === 0) { + $search = '%' . substr($search, 8) . '%'; + $query->where('(' . $db->quoteName('a.introtext') . ' LIKE :search1 OR ' . $db->quoteName('a.fulltext') . ' LIKE :search2)') + ->bind([':search1', ':search2'], $search); + } else { + $search = '%' . str_replace(' ', '%', trim($search)) . '%'; + $query->where( + '(' . $db->quoteName('a.title') . ' LIKE :search1 OR ' . $db->quoteName('a.alias') . ' LIKE :search2' + . ' OR ' . $db->quoteName('a.note') . ' LIKE :search3)' + ) + ->bind([':search1', ':search2', ':search3'], $search); + } + } + + // Filter on the language. + if ($language = $this->getState('filter.language')) { + $query->where($db->quoteName('a.language') . ' = :language') + ->bind(':language', $language); + } + + // Filter by a single or group of tags. + $tag = $this->getState('filter.tag'); + + // Run simplified query when filtering by one tag. + if (\is_array($tag) && \count($tag) === 1) { + $tag = $tag[0]; + } + + if ($tag && \is_array($tag)) { + $tag = ArrayHelper::toInteger($tag); + + $subQuery = $db->getQuery(true) + ->select('DISTINCT ' . $db->quoteName('content_item_id')) + ->from($db->quoteName('#__contentitem_tag_map')) + ->where( + [ + $db->quoteName('tag_id') . ' IN (' . implode(',', $query->bindArray($tag)) . ')', + $db->quoteName('type_alias') . ' = ' . $db->quote('com_content.article'), + ] + ); + + $query->join( + 'INNER', + '(' . $subQuery . ') AS ' . $db->quoteName('tagmap'), + $db->quoteName('tagmap.content_item_id') . ' = ' . $db->quoteName('a.id') + ); + } elseif ($tag = (int) $tag) { + $query->join( + 'INNER', + $db->quoteName('#__contentitem_tag_map', 'tagmap'), + $db->quoteName('tagmap.content_item_id') . ' = ' . $db->quoteName('a.id') + ) + ->where( + [ + $db->quoteName('tagmap.tag_id') . ' = :tag', + $db->quoteName('tagmap.type_alias') . ' = ' . $db->quote('com_content.article'), + ] + ) + ->bind(':tag', $tag, ParameterType::INTEGER); + } + + // Add the list ordering clause. + $orderCol = $this->state->get('list.ordering', 'a.id'); + $orderDirn = $this->state->get('list.direction', 'DESC'); + + if ($orderCol === 'a.ordering' || $orderCol === 'category_title') { + $ordering = [ + $db->quoteName('c.title') . ' ' . $db->escape($orderDirn), + $db->quoteName('a.ordering') . ' ' . $db->escape($orderDirn), + ]; + } else { + $ordering = $db->escape($orderCol) . ' ' . $db->escape($orderDirn); + } + + $query->order($ordering); + + return $query; + } + + /** + * Method to get all transitions at once for all articles + * + * @return array|boolean + * + * @since 4.0.0 + */ + public function getTransitions() + { + // Get a storage key. + $store = $this->getStoreId('getTransitions'); + + // Try to load the data from internal storage. + if (isset($this->cache[$store])) { + return $this->cache[$store]; + } + + $db = $this->getDatabase(); + $user = Factory::getUser(); + + $items = $this->getItems(); + + if ($items === false) { + return false; + } + + $stage_ids = ArrayHelper::getColumn($items, 'stage_id'); + $stage_ids = ArrayHelper::toInteger($stage_ids); + $stage_ids = array_values(array_unique(array_filter($stage_ids))); + + $workflow_ids = ArrayHelper::getColumn($items, 'workflow_id'); + $workflow_ids = ArrayHelper::toInteger($workflow_ids); + $workflow_ids = array_values(array_unique(array_filter($workflow_ids))); + + $this->cache[$store] = array(); + + try { + if (count($stage_ids) || count($workflow_ids)) { + Factory::getLanguage()->load('com_workflow', JPATH_ADMINISTRATOR); + + $query = $db->getQuery(true); + + $query ->select( + [ + $db->quoteName('t.id', 'value'), + $db->quoteName('t.title', 'text'), + $db->quoteName('t.from_stage_id'), + $db->quoteName('t.to_stage_id'), + $db->quoteName('s.id', 'stage_id'), + $db->quoteName('s.title', 'stage_title'), + $db->quoteName('t.workflow_id'), + ] + ) + ->from($db->quoteName('#__workflow_transitions', 't')) + ->innerJoin( + $db->quoteName('#__workflow_stages', 's'), + $db->quoteName('t.to_stage_id') . ' = ' . $db->quoteName('s.id') + ) + ->where( + [ + $db->quoteName('t.published') . ' = 1', + $db->quoteName('s.published') . ' = 1', + ] + ) + ->order($db->quoteName('t.ordering')); + + $where = []; + + if (count($stage_ids)) { + $where[] = $db->quoteName('t.from_stage_id') . ' IN (' . implode(',', $query->bindArray($stage_ids)) . ')'; + } + + if (count($workflow_ids)) { + $where[] = '(' . $db->quoteName('t.from_stage_id') . ' = -1 AND ' . $db->quoteName('t.workflow_id') . ' IN (' . implode(',', $query->bindArray($workflow_ids)) . '))'; + } + + $query->where('((' . implode(') OR (', $where) . '))'); + + $transitions = $db->setQuery($query)->loadAssocList(); + + foreach ($transitions as $key => $transition) { + if (!$user->authorise('core.execute.transition', 'com_content.transition.' . (int) $transition['value'])) { + unset($transitions[$key]); + } + + $transitions[$key]['text'] = Text::_($transition['text']); + } + + $this->cache[$store] = $transitions; + } + } catch (\RuntimeException $e) { + $this->setError($e->getMessage()); + + return false; + } + + return $this->cache[$store]; + } + + /** + * Method to get a list of articles. + * Overridden to add item type alias. + * + * @return mixed An array of data items on success, false on failure. + * + * @since 4.0.0 + */ + public function getItems() + { + $items = parent::getItems(); + + foreach ($items as $item) { + $item->typeAlias = 'com_content.article'; + + if (isset($item->metadata)) { + $registry = new Registry($item->metadata); + $item->metadata = $registry->toArray(); + } + } + + return $items; + } } diff --git a/administrator/components/com_content/tmpl/featured/default.php b/administrator/components/com_content/tmpl/featured/default.php index 4d36fa9d9772a..47241f18f9636 100644 --- a/administrator/components/com_content/tmpl/featured/default.php +++ b/administrator/components/com_content/tmpl/featured/default.php @@ -1,4 +1,5 @@ document->getWebAssetManager(); $wa->useScript('table.columns') - ->useScript('multiselect'); + ->useScript('multiselect'); $app = Factory::getApplication(); $user = Factory::getUser(); @@ -36,28 +37,20 @@ $listDirn = $this->escape($this->state->get('list.direction')); $saveOrder = $listOrder == 'fp.ordering'; -if (strpos($listOrder, 'publish_up') !== false) -{ - $orderingColumn = 'publish_up'; -} -elseif (strpos($listOrder, 'publish_down') !== false) -{ - $orderingColumn = 'publish_down'; -} -elseif (strpos($listOrder, 'modified') !== false) -{ - $orderingColumn = 'modified'; -} -else -{ - $orderingColumn = 'created'; +if (strpos($listOrder, 'publish_up') !== false) { + $orderingColumn = 'publish_up'; +} elseif (strpos($listOrder, 'publish_down') !== false) { + $orderingColumn = 'publish_down'; +} elseif (strpos($listOrder, 'modified') !== false) { + $orderingColumn = 'modified'; +} else { + $orderingColumn = 'created'; } -if ($saveOrder && !empty($this->items)) -{ - $saveOrderingUrl = 'index.php?option=com_content&task=featured.saveOrderAjax&tmpl=component&' . Session::getFormToken() . '=1'; - HTMLHelper::_('draggablelist.draggable'); +if ($saveOrder && !empty($this->items)) { + $saveOrderingUrl = 'index.php?option=com_content&task=featured.saveOrderAjax&tmpl=component&' . Session::getFormToken() . '=1'; + HTMLHelper::_('draggablelist.draggable'); } $workflow_enabled = ComponentHelper::getParams('com_content')->get('workflow_enabled'); @@ -65,9 +58,8 @@ $workflow_featured = false; if ($workflow_enabled) : - // @todo move the script to a file -$js = <<getRegistry()->addExtensionRegistryFile('com_workflow'); -$wa->useScript('com_workflow.admin-items-workflow-buttons') - ->addInlineScript($js, [], ['type' => 'module']); - -$workflow_state = Factory::getApplication()->bootComponent('com_content')->isFunctionalityUsed('core.state', 'com_content.article'); -$workflow_featured = Factory::getApplication()->bootComponent('com_content')->isFunctionalityUsed('core.featured', 'com_content.article'); + $wa->getRegistry()->addExtensionRegistryFile('com_workflow'); + $wa->useScript('com_workflow.admin-items-workflow-buttons') + ->addInlineScript($js, [], ['type' => 'module']); + $workflow_state = Factory::getApplication()->bootComponent('com_content')->isFunctionalityUsed('core.state', 'com_content.article'); + $workflow_featured = Factory::getApplication()->bootComponent('com_content')->isFunctionalityUsed('core.featured', 'com_content.article'); endif; $assoc = Associations::isEnabled(); @@ -95,332 +86,328 @@ ?> -
-
-
- $this)); - ?> - items)) : ?> -
- - -
- - - - - - - - - - - - - - - - - - - - - - - hits) : ?> - - - vote) : ?> - - - - - - - class="js-draggable" data-url="" data-direction=""> - items); ?> - items as $i => $item) : - $item->max_ordering = 0; - $ordering = ($listOrder == 'fp.ordering'); - $assetId = 'com_content.article.' . $item->id; - $canCreate = $user->authorise('core.create', 'com_content.category.' . $item->catid); - $canEdit = $user->authorise('core.edit', 'com_content.article.' . $item->id); - $canCheckin = $user->authorise('core.manage', 'com_checkin') || $item->checked_out == $userId || is_null($item->checked_out); - $canChange = $user->authorise('core.edit.state', 'com_content.article.' . $item->id) && $canCheckin; - $canEditCat = $user->authorise('core.edit', 'com_content.category.' . $item->catid); - $canEditOwnCat = $user->authorise('core.edit.own', 'com_content.category.' . $item->catid) && $item->category_uid == $userId; - $canEditParCat = $user->authorise('core.edit', 'com_content.category.' . $item->parent_category_id); - $canEditOwnParCat = $user->authorise('core.edit.own', 'com_content.category.' . $item->parent_category_id) && $item->parent_category_uid == $userId; +
+
+
+ $this)); + ?> + items)) : ?> +
+ + +
+ +
- , - , - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ + + + + + + + + + + + + + + + + + + + + hits) : ?> + + + vote) : ?> + + + + + + + class="js-draggable" data-url="" data-direction=""> + items); ?> + items as $i => $item) : + $item->max_ordering = 0; + $ordering = ($listOrder == 'fp.ordering'); + $assetId = 'com_content.article.' . $item->id; + $canCreate = $user->authorise('core.create', 'com_content.category.' . $item->catid); + $canEdit = $user->authorise('core.edit', 'com_content.article.' . $item->id); + $canCheckin = $user->authorise('core.manage', 'com_checkin') || $item->checked_out == $userId || is_null($item->checked_out); + $canChange = $user->authorise('core.edit.state', 'com_content.article.' . $item->id) && $canCheckin; + $canEditCat = $user->authorise('core.edit', 'com_content.category.' . $item->catid); + $canEditOwnCat = $user->authorise('core.edit.own', 'com_content.category.' . $item->catid) && $item->category_uid == $userId; + $canEditParCat = $user->authorise('core.edit', 'com_content.category.' . $item->parent_category_id); + $canEditOwnParCat = $user->authorise('core.edit.own', 'com_content.category.' . $item->parent_category_id) && $item->parent_category_uid == $userId; - $transitions = ContentHelper::filterTransitions($this->transitions, (int) $item->stage_id, (int) $item->workflow_id); + $transitions = ContentHelper::filterTransitions($this->transitions, (int) $item->stage_id, (int) $item->workflow_id); - $transition_ids = ArrayHelper::getColumn($transitions, 'value'); - $transition_ids = ArrayHelper::toInteger($transition_ids); + $transition_ids = ArrayHelper::getColumn($transitions, 'value'); + $transition_ids = ArrayHelper::toInteger($transition_ids); - ?> - - - + + - - + + - - + + - + - - - - - - - - - - - hits) : ?> - - - vote) : ?> - - - - - - - -
+ , + , + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
- id, false, 'cid', 'cb', $item->title); ?> - - +
+ id, false, 'cid', 'cb', $item->title); ?> + + - - - - - - - - $transitions, - 'title' => Text::_($item->stage_title), - 'tip_content' => Text::sprintf('JWORKFLOW', Text::_($item->workflow_title)), - 'id' => 'workflow-' . $item->id, - 'task' => 'articles.runTransition' - ]; + if (!$canChange) { + $iconClass = ' inactive'; + } elseif (!$saveOrder) { + $iconClass = ' inactive" title="' . Text::_('JORDERINGDISABLED'); + } + ?> + + + + + + + + $transitions, + 'title' => Text::_($item->stage_title), + 'tip_content' => Text::sprintf('JWORKFLOW', Text::_($item->workflow_title)), + 'id' => 'workflow-' . $item->id, + 'task' => 'articles.runTransition' + ]; - echo (new TransitionButton($options)) - ->render(0, $i); - ?> -
- stage_title); ?> -
-
- 'articles.', - 'disabled' => $workflow_featured || !$canChange, - 'id' => 'featured-' . $item->id - ]; + echo (new TransitionButton($options)) + ->render(0, $i); + ?> +
+ stage_title); ?> +
+
+ 'articles.', + 'disabled' => $workflow_featured || !$canChange, + 'id' => 'featured-' . $item->id + ]; - echo (new FeaturedButton) - ->render((int) $item->featured, $i, $options, $item->featured_up, $item->featured_down); - ?> - - 'articles.', - 'disabled' => $workflow_state || !$canChange, - 'id' => 'state-' . $item->id, - 'category_published' => $item->category_published - ]; + echo (new FeaturedButton()) + ->render((int) $item->featured, $i, $options, $item->featured_up, $item->featured_down); + ?> + + 'articles.', + 'disabled' => $workflow_state || !$canChange, + 'id' => 'state-' . $item->id, + 'category_published' => $item->category_published + ]; - echo (new PublishedButton)->render((int) $item->state, $i, $options, $item->publish_up, $item->publish_down); - ?> - -
- checked_out) : ?> - editor, $item->checked_out_time, 'articles.', $canCheckin); ?> - - - - escape($item->title); ?> - - escape($item->title); ?> - -
- note)) : ?> - escape($item->alias)); ?> - - escape($item->alias), $this->escape($item->note)); ?> - -
-
- parent_category_id . '&extension=com_content'); - $CurrentCatUrl = Route::_('index.php?option=com_categories&task=category.edit&id=' . $item->catid . '&extension=com_content'); - $EditCatTxt = Text::_('COM_CONTENT_EDIT_CATEGORY'); - echo Text::_('JCATEGORY') . ': '; - if ($item->category_level != '1') : - if ($item->parent_category_level != '1') : - echo ' » '; - endif; - endif; - if (Factory::getLanguage()->isRtl()) - { - if ($canEditCat || $canEditOwnCat) : - echo ''; - endif; - echo $this->escape($item->category_title); - if ($canEditCat || $canEditOwnCat) : - echo ''; - endif; - if ($item->category_level != '1') : - echo ' « '; - if ($canEditParCat || $canEditOwnParCat) : - echo ''; - endif; - echo $this->escape($item->parent_category_title); - if ($canEditParCat || $canEditOwnParCat) : - echo ''; - endif; - endif; - } - else - { - if ($item->category_level != '1') : - if ($canEditParCat || $canEditOwnParCat) : - echo ''; - endif; - echo $this->escape($item->parent_category_title); - if ($canEditParCat || $canEditOwnParCat) : - echo ''; - endif; - echo ' » '; - endif; - if ($canEditCat || $canEditOwnCat) : - echo ''; - endif; - echo $this->escape($item->category_title); - if ($canEditCat || $canEditOwnCat) : - echo ''; - endif; - } - if ($item->category_published < '1') : - echo $item->category_published == '0' ? ' (' . Text::_('JUNPUBLISHED') . ')' : ' (' . Text::_('JTRASHED') . ')'; - endif; - ?> -
-
-
- escape($item->access_level); ?> - - created_by != 0) : ?> - - escape($item->author_name); ?> - - - - - created_by_alias) : ?> -
escape($item->created_by_alias)); ?>
- -
- association) : ?> - id); ?> - - - - - {$orderingColumn}; - echo $date > 0 ? HTMLHelper::_('date', $date, Text::_('DATE_FORMAT_LC4')) : '-'; - ?> - - - hits; ?> - - - - rating_count; ?> - - - - rating; ?> - - - id; ?> -
+ echo (new PublishedButton())->render((int) $item->state, $i, $options, $item->publish_up, $item->publish_down); + ?> + + +
+ checked_out) : ?> + editor, $item->checked_out_time, 'articles.', $canCheckin); ?> + + + + escape($item->title); ?> + + escape($item->title); ?> + +
+ note)) : ?> + escape($item->alias)); ?> + + escape($item->alias), $this->escape($item->note)); ?> + +
+
+ parent_category_id . '&extension=com_content'); + $CurrentCatUrl = Route::_('index.php?option=com_categories&task=category.edit&id=' . $item->catid . '&extension=com_content'); + $EditCatTxt = Text::_('COM_CONTENT_EDIT_CATEGORY'); + echo Text::_('JCATEGORY') . ': '; + if ($item->category_level != '1') : + if ($item->parent_category_level != '1') : + echo ' » '; + endif; + endif; + if (Factory::getLanguage()->isRtl()) { + if ($canEditCat || $canEditOwnCat) : + echo ''; + endif; + echo $this->escape($item->category_title); + if ($canEditCat || $canEditOwnCat) : + echo ''; + endif; + if ($item->category_level != '1') : + echo ' « '; + if ($canEditParCat || $canEditOwnParCat) : + echo ''; + endif; + echo $this->escape($item->parent_category_title); + if ($canEditParCat || $canEditOwnParCat) : + echo ''; + endif; + endif; + } else { + if ($item->category_level != '1') : + if ($canEditParCat || $canEditOwnParCat) : + echo ''; + endif; + echo $this->escape($item->parent_category_title); + if ($canEditParCat || $canEditOwnParCat) : + echo ''; + endif; + echo ' » '; + endif; + if ($canEditCat || $canEditOwnCat) : + echo ''; + endif; + echo $this->escape($item->category_title); + if ($canEditCat || $canEditOwnCat) : + echo ''; + endif; + } + if ($item->category_published < '1') : + echo $item->category_published == '0' ? ' (' . Text::_('JUNPUBLISHED') . ')' : ' (' . Text::_('JTRASHED') . ')'; + endif; + ?> +
+
+ + + escape($item->access_level); ?> + + + created_by != 0) : ?> + + escape($item->author_name); ?> + + + + + created_by_alias) : ?> +
escape($item->created_by_alias)); ?>
+ + + + + association) : ?> + id); ?> + + + + + + + + + + {$orderingColumn}; + echo $date > 0 ? HTMLHelper::_('date', $date, Text::_('DATE_FORMAT_LC4')) : '-'; + ?> + + hits) : ?> + + + hits; ?> + + + + vote) : ?> + + + rating_count; ?> + + + + + rating; ?> + + + + + id; ?> + + + + + - - pagination->getListFooter(); ?> + + pagination->getListFooter(); ?> - Text::_('JTOOLBAR_CHANGE_STATUS'), - 'footer' => $this->loadTemplate('stage_footer'), - ), - $this->loadTemplate('stage_body') - ); ?> + Text::_('JTOOLBAR_CHANGE_STATUS'), + 'footer' => $this->loadTemplate('stage_footer'), + ), + $this->loadTemplate('stage_body') + ); ?> - + - - - + + + - - - - -
-
-
+ + + + +
+
+
diff --git a/administrator/components/com_modules/src/Extension/ModulesComponent.php b/administrator/components/com_modules/src/Extension/ModulesComponent.php index 86764c5beb171..4bdccd860df3a 100644 --- a/administrator/components/com_modules/src/Extension/ModulesComponent.php +++ b/administrator/components/com_modules/src/Extension/ModulesComponent.php @@ -1,4 +1,5 @@ true, - ]; - - /** - * The trashed condition - * - * @since __DEPLOY_VERSION__ - */ - const CONDITION_NAMES = [ - self::CONDITION_PUBLISHED => 'JPUBLISHED', - self::CONDITION_UNPUBLISHED => 'JUNPUBLISHED', - self::CONDITION_TRASHED => 'JTRASHED', - ]; - - /** - * The published condition - * - * @since __DEPLOY_VERSION__ - */ - const CONDITION_PUBLISHED = 1; - - /** - * The unpublished condition - * - * @since __DEPLOY_VERSION__ - */ - const CONDITION_UNPUBLISHED = 0; - - /** - * The trashed condition - * - * @since __DEPLOY_VERSION__ - */ - const CONDITION_TRASHED = -2; - - - /** - * Booting the extension. This is the function to set up the environment of the extension like - * registering new class loaders, etc. - * - * If required, some initial set up can be done from services of the container, eg. - * registering HTML services. - * - * @param ContainerInterface $container The container - * - * @return void - * - * @since 4.0.0 - */ - public function boot(ContainerInterface $container) - { - $this->getRegistry()->register('modules', new Modules); - } - - /** - * Returns valid contexts - * - * @return array - * - * @since __DEPLOY_VERSION__ - */ - public function getWorkflowContexts(): array - { - Factory::getLanguage()->load('com_modules', JPATH_ADMINISTRATOR); - - $contexts = [ - 'com_modules.module' => Text::_('COM_MODULES') - ]; - - return $contexts; - } - - /** - * Returns a table name for the state association - * - * @param string $section An optional section to separate different areas in the component - * - * @return string - * - * @since __DEPLOY_VERSION__ - */ - public function getWorkflowTableBySection(?string $section = null): string - { - return '#__modules'; - } - - /** - * Method to filter transitions by given id of state. - * - * @param array $transitions The Transitions to filter - * @param int $pk Id of the state - * - * @return array - * - * @since __DEPLOY_VERSION__ - */ - public function filterTransitions(array $transitions, int $pk): array - { - return ModulesHelper::filterTransitions($transitions, $pk); - } - - /** - * Returns the workflow context based on the given category section - * - * @param string $section The section - * - * @return string|null - * - * @since __DEPLOY_VERSION__ - */ - public function getCategoryWorkflowContext(?string $section = null): string - { - return array_key_first($this->getWorkflowContexts()); - } + use HTMLRegistryAwareTrait; + use WorkflowServiceTrait; + + /** + * @var array + * @since __DEPLOY_VERSION_ + */ + protected $supportedFunctionality = [ + 'core.state' => true, + ]; + + /** + * The trashed condition + * + * @since __DEPLOY_VERSION__ + */ + const CONDITION_NAMES = [ + self::CONDITION_PUBLISHED => 'JPUBLISHED', + self::CONDITION_UNPUBLISHED => 'JUNPUBLISHED', + self::CONDITION_TRASHED => 'JTRASHED', + ]; + + /** + * The published condition + * + * @since __DEPLOY_VERSION__ + */ + const CONDITION_PUBLISHED = 1; + + /** + * The unpublished condition + * + * @since __DEPLOY_VERSION__ + */ + const CONDITION_UNPUBLISHED = 0; + + /** + * The trashed condition + * + * @since __DEPLOY_VERSION__ + */ + const CONDITION_TRASHED = -2; + + + /** + * Booting the extension. This is the function to set up the environment of the extension like + * registering new class loaders, etc. + * + * If required, some initial set up can be done from services of the container, eg. + * registering HTML services. + * + * @param ContainerInterface $container The container + * + * @return void + * + * @since 4.0.0 + */ + public function boot(ContainerInterface $container) + { + $this->getRegistry()->register('modules', new Modules()); + } + + /** + * Returns valid contexts + * + * @return array + * + * @since __DEPLOY_VERSION__ + */ + public function getWorkflowContexts(): array + { + Factory::getLanguage()->load('com_modules', JPATH_ADMINISTRATOR); + + $contexts = [ + 'com_modules.module' => Text::_('COM_MODULES') + ]; + + return $contexts; + } + + /** + * Returns a table name for the state association + * + * @param string $section An optional section to separate different areas in the component + * + * @return string + * + * @since __DEPLOY_VERSION__ + */ + public function getWorkflowTableBySection(?string $section = null): string + { + return '#__modules'; + } + + /** + * Method to filter transitions by given id of state. + * + * @param array $transitions The Transitions to filter + * @param int $pk Id of the state + * + * @return array + * + * @since __DEPLOY_VERSION__ + */ + public function filterTransitions(array $transitions, int $pk): array + { + return ModulesHelper::filterTransitions($transitions, $pk); + } + + /** + * Returns the workflow context based on the given category section + * + * @param string $section The section + * + * @return string|null + * + * @since __DEPLOY_VERSION__ + */ + public function getCategoryWorkflowContext(?string $section = null): string + { + return array_key_first($this->getWorkflowContexts()); + } } diff --git a/administrator/components/com_modules/src/Helper/ModulesHelper.php b/administrator/components/com_modules/src/Helper/ModulesHelper.php index 24d0ff948c621..4c4f1f1cea8bb 100644 --- a/administrator/components/com_modules/src/Helper/ModulesHelper.php +++ b/administrator/components/com_modules/src/Helper/ModulesHelper.php @@ -1,4 +1,5 @@ getQuery(true) - ->select('DISTINCT ' . $db->quoteName('position')) - ->from($db->quoteName('#__modules')) - ->where($db->quoteName('client_id') . ' = :clientid') - ->order($db->quoteName('position')) - ->bind(':clientid', $clientId, ParameterType::INTEGER); - - $db->setQuery($query); - - try - { - $positions = $db->loadColumn(); - $positions = is_array($positions) ? $positions : array(); - } - catch (\RuntimeException $e) - { - Factory::getApplication()->enqueueMessage($e->getMessage(), 'error'); - - return; - } - - // Build the list - $options = array(); - - foreach ($positions as $position) - { - if (!$position && !$editPositions) - { - $options[] = HTMLHelper::_('select.option', 'none', Text::_('COM_MODULES_NONE')); - } - elseif (!$position) - { - $options[] = HTMLHelper::_('select.option', '', Text::_('COM_MODULES_NONE')); - } - else - { - $options[] = HTMLHelper::_('select.option', $position, $position); - } - } - - return $options; - } - - /** - * Return a list of templates - * - * @param integer $clientId Client ID - * @param string $state State - * @param string $template Template name - * - * @return array List of templates - */ - public static function getTemplates($clientId = 0, $state = '', $template = '') - { - $db = Factory::getDbo(); - $clientId = (int) $clientId; - - // Get the database object and a new query object. - $query = $db->getQuery(true); - - // Build the query. - $query->select($db->quoteName(['element', 'name', 'enabled'])) - ->from($db->quoteName('#__extensions')) - ->where($db->quoteName('client_id') . ' = :clientid') - ->where($db->quoteName('type') . ' = ' . $db->quote('template')); - - if ($state != '') - { - $query->where($db->quoteName('enabled') . ' = :state') - ->bind(':state', $state); - } - - if ($template != '') - { - $query->where($db->quoteName('element') . ' = :element') - ->bind(':element', $template); - } - - $query->bind(':clientid', $clientId, ParameterType::INTEGER); - - // Set the query and load the templates. - $db->setQuery($query); - $templates = $db->loadObjectList('element'); - - return $templates; - } - - /** - * Get a list of the unique modules installed in the client application. - * - * @param int $clientId The client id. - * - * @return array Array of unique modules - */ - public static function getModules($clientId) - { - $db = Factory::getDbo(); - $query = $db->getQuery(true) - ->select('element AS value, name AS text') - ->from('#__extensions as e') - ->where('e.client_id = ' . (int) $clientId) - ->where('type = ' . $db->quote('module')) - ->join('LEFT', '#__modules as m ON m.module=e.element AND m.client_id=e.client_id') - ->where('m.module IS NOT NULL') - ->group('element,name'); - - $db->setQuery($query); - $modules = $db->loadObjectList(); - $lang = Factory::getLanguage(); - - foreach ($modules as $i => $module) - { - $extension = $module->value; - $path = $clientId ? JPATH_ADMINISTRATOR : JPATH_SITE; - $source = $path . "/modules/$extension"; - $lang->load("$extension.sys", $path) - || $lang->load("$extension.sys", $source); - $modules[$i]->text = Text::_($module->text); - } - - $modules = ArrayHelper::sortObjects($modules, 'text', 1, true, true); - - return $modules; - } - - /** - * Get a list of the assignment options for modules to menus. - * - * @param int $clientId The client id. - * - * @return array - */ - public static function getAssignmentOptions($clientId) - { - $options = array(); - $options[] = HTMLHelper::_('select.option', '0', 'COM_MODULES_OPTION_MENU_ALL'); - $options[] = HTMLHelper::_('select.option', '-', 'COM_MODULES_OPTION_MENU_NONE'); - - if ($clientId == 0) - { - $options[] = HTMLHelper::_('select.option', '1', 'COM_MODULES_OPTION_MENU_INCLUDE'); - $options[] = HTMLHelper::_('select.option', '-1', 'COM_MODULES_OPTION_MENU_EXCLUDE'); - } - - return $options; - } - - /** - * Return a translated module position name - * - * @param integer $clientId Application client id 0: site | 1: admin - * @param string $template Template name - * @param string $position Position name - * - * @return string Return a translated position name - * - * @since 3.0 - */ - public static function getTranslatedModulePosition($clientId, $template, $position) - { - // Template translation - $lang = Factory::getLanguage(); - $path = $clientId ? JPATH_ADMINISTRATOR : JPATH_SITE; - - $loaded = $lang->getPaths('tpl_' . $template . '.sys'); - - // Only load the template's language file if it hasn't been already - if (!$loaded) - { - $lang->load('tpl_' . $template . '.sys', $path, null, false, false) - || $lang->load('tpl_' . $template . '.sys', $path . '/templates/' . $template, null, false, false) - || $lang->load('tpl_' . $template . '.sys', $path, $lang->getDefault(), false, false) - || $lang->load('tpl_' . $template . '.sys', $path . '/templates/' . $template, $lang->getDefault(), false, false); - } - - $langKey = strtoupper('TPL_' . $template . '_POSITION_' . $position); - $text = Text::_($langKey); - - // Avoid untranslated strings - if (!self::isTranslatedText($langKey, $text)) - { - // Modules component translation - $langKey = strtoupper('COM_MODULES_POSITION_' . $position); - $text = Text::_($langKey); - - // Avoid untranslated strings - if (!self::isTranslatedText($langKey, $text)) - { - // Try to humanize the position name - $text = ucfirst(preg_replace('/^' . $template . '\-/', '', $position)); - $text = ucwords(str_replace(array('-', '_'), ' ', $text)); - } - } - - return $text; - } - - /** - * Check if the string was translated - * - * @param string $langKey Language file text key - * @param string $text The "translated" text to be checked - * - * @return boolean Return true for translated text - * - * @since 3.0 - */ - public static function isTranslatedText($langKey, $text) - { - return $text !== $langKey; - } - - /** - * Create and return a new Option - * - * @param string $value The option value [optional] - * @param string $text The option text [optional] - * - * @return object The option as an object (\stdClass instance) - * - * @since 3.0 - */ - public static function createOption($value = '', $text = '') - { - if (empty($text)) - { - $text = $value; - } - - $option = new \stdClass; - $option->value = $value; - $option->text = $text; - - return $option; - } - - /** - * Create and return a new Option Group - * - * @param string $label Value and label for group [optional] - * @param array $options Array of options to insert into group [optional] - * - * @return array Return the new group as an array - * - * @since 3.0 - */ - public static function createOptionGroup($label = '', $options = array()) - { - $group = array(); - $group['value'] = $label; - $group['text'] = $label; - $group['items'] = $options; - - return $group; - } - - /** - * Method to filter transitions by given id of state - * - * @param array $transitions Array of transitions - * @param int $pk Id of state - * @param int $workflowId Id of the workflow - * - * @return array - * - * @since __DEPLOY_VERSION__ - */ - public static function filterTransitions(array $transitions, int $pk, int $workflowId = 0): array - { - return array_values( - array_filter( - $transitions, - function ($var) use ($pk, $workflowId) - { - return in_array($var['from_stage_id'], [-1, $pk]) && $workflowId == $var['workflow_id']; - } - ) - ); - } + /** + * Get a list of filter options for the state of a module. + * + * @return array An array of \JHtmlOption elements. + */ + public static function getStateOptions() + { + // Build the filter options. + $options = array(); + $options[] = HTMLHelper::_('select.option', '1', Text::_('JPUBLISHED')); + $options[] = HTMLHelper::_('select.option', '0', Text::_('JUNPUBLISHED')); + $options[] = HTMLHelper::_('select.option', '-2', Text::_('JTRASHED')); + $options[] = HTMLHelper::_('select.option', '*', Text::_('JALL')); + + return $options; + } + + /** + * Get a list of filter options for the application clients. + * + * @return array An array of \JHtmlOption elements. + */ + public static function getClientOptions() + { + // Build the filter options. + $options = array(); + $options[] = HTMLHelper::_('select.option', '0', Text::_('JSITE')); + $options[] = HTMLHelper::_('select.option', '1', Text::_('JADMINISTRATOR')); + + return $options; + } + + /** + * Get a list of modules positions + * + * @param integer $clientId Client ID + * @param boolean $editPositions Allow to edit the positions + * + * @return array A list of positions + */ + public static function getPositions($clientId, $editPositions = false) + { + $db = Factory::getDbo(); + $clientId = (int) $clientId; + $query = $db->getQuery(true) + ->select('DISTINCT ' . $db->quoteName('position')) + ->from($db->quoteName('#__modules')) + ->where($db->quoteName('client_id') . ' = :clientid') + ->order($db->quoteName('position')) + ->bind(':clientid', $clientId, ParameterType::INTEGER); + + $db->setQuery($query); + + try { + $positions = $db->loadColumn(); + $positions = is_array($positions) ? $positions : array(); + } catch (\RuntimeException $e) { + Factory::getApplication()->enqueueMessage($e->getMessage(), 'error'); + + return; + } + + // Build the list + $options = array(); + + foreach ($positions as $position) { + if (!$position && !$editPositions) { + $options[] = HTMLHelper::_('select.option', 'none', Text::_('COM_MODULES_NONE')); + } elseif (!$position) { + $options[] = HTMLHelper::_('select.option', '', Text::_('COM_MODULES_NONE')); + } else { + $options[] = HTMLHelper::_('select.option', $position, $position); + } + } + + return $options; + } + + /** + * Return a list of templates + * + * @param integer $clientId Client ID + * @param string $state State + * @param string $template Template name + * + * @return array List of templates + */ + public static function getTemplates($clientId = 0, $state = '', $template = '') + { + $db = Factory::getDbo(); + $clientId = (int) $clientId; + + // Get the database object and a new query object. + $query = $db->getQuery(true); + + // Build the query. + $query->select($db->quoteName(['element', 'name', 'enabled'])) + ->from($db->quoteName('#__extensions')) + ->where($db->quoteName('client_id') . ' = :clientid') + ->where($db->quoteName('type') . ' = ' . $db->quote('template')); + + if ($state != '') { + $query->where($db->quoteName('enabled') . ' = :state') + ->bind(':state', $state); + } + + if ($template != '') { + $query->where($db->quoteName('element') . ' = :element') + ->bind(':element', $template); + } + + $query->bind(':clientid', $clientId, ParameterType::INTEGER); + + // Set the query and load the templates. + $db->setQuery($query); + $templates = $db->loadObjectList('element'); + + return $templates; + } + + /** + * Get a list of the unique modules installed in the client application. + * + * @param int $clientId The client id. + * + * @return array Array of unique modules + */ + public static function getModules($clientId) + { + $db = Factory::getDbo(); + $query = $db->getQuery(true) + ->select('element AS value, name AS text') + ->from('#__extensions as e') + ->where('e.client_id = ' . (int) $clientId) + ->where('type = ' . $db->quote('module')) + ->join('LEFT', '#__modules as m ON m.module=e.element AND m.client_id=e.client_id') + ->where('m.module IS NOT NULL') + ->group('element,name'); + + $db->setQuery($query); + $modules = $db->loadObjectList(); + $lang = Factory::getLanguage(); + + foreach ($modules as $i => $module) { + $extension = $module->value; + $path = $clientId ? JPATH_ADMINISTRATOR : JPATH_SITE; + $source = $path . "/modules/$extension"; + $lang->load("$extension.sys", $path) + || $lang->load("$extension.sys", $source); + $modules[$i]->text = Text::_($module->text); + } + + $modules = ArrayHelper::sortObjects($modules, 'text', 1, true, true); + + return $modules; + } + + /** + * Get a list of the assignment options for modules to menus. + * + * @param int $clientId The client id. + * + * @return array + */ + public static function getAssignmentOptions($clientId) + { + $options = array(); + $options[] = HTMLHelper::_('select.option', '0', 'COM_MODULES_OPTION_MENU_ALL'); + $options[] = HTMLHelper::_('select.option', '-', 'COM_MODULES_OPTION_MENU_NONE'); + + if ($clientId == 0) { + $options[] = HTMLHelper::_('select.option', '1', 'COM_MODULES_OPTION_MENU_INCLUDE'); + $options[] = HTMLHelper::_('select.option', '-1', 'COM_MODULES_OPTION_MENU_EXCLUDE'); + } + + return $options; + } + + /** + * Return a translated module position name + * + * @param integer $clientId Application client id 0: site | 1: admin + * @param string $template Template name + * @param string $position Position name + * + * @return string Return a translated position name + * + * @since 3.0 + */ + public static function getTranslatedModulePosition($clientId, $template, $position) + { + // Template translation + $lang = Factory::getLanguage(); + $path = $clientId ? JPATH_ADMINISTRATOR : JPATH_SITE; + + $loaded = $lang->getPaths('tpl_' . $template . '.sys'); + + // Only load the template's language file if it hasn't been already + if (!$loaded) { + $lang->load('tpl_' . $template . '.sys', $path, null, false, false) + || $lang->load('tpl_' . $template . '.sys', $path . '/templates/' . $template, null, false, false) + || $lang->load('tpl_' . $template . '.sys', $path, $lang->getDefault(), false, false) + || $lang->load('tpl_' . $template . '.sys', $path . '/templates/' . $template, $lang->getDefault(), false, false); + } + + $langKey = strtoupper('TPL_' . $template . '_POSITION_' . $position); + $text = Text::_($langKey); + + // Avoid untranslated strings + if (!self::isTranslatedText($langKey, $text)) { + // Modules component translation + $langKey = strtoupper('COM_MODULES_POSITION_' . $position); + $text = Text::_($langKey); + + // Avoid untranslated strings + if (!self::isTranslatedText($langKey, $text)) { + // Try to humanize the position name + $text = ucfirst(preg_replace('/^' . $template . '\-/', '', $position)); + $text = ucwords(str_replace(array('-', '_'), ' ', $text)); + } + } + + return $text; + } + + /** + * Check if the string was translated + * + * @param string $langKey Language file text key + * @param string $text The "translated" text to be checked + * + * @return boolean Return true for translated text + * + * @since 3.0 + */ + public static function isTranslatedText($langKey, $text) + { + return $text !== $langKey; + } + + /** + * Create and return a new Option + * + * @param string $value The option value [optional] + * @param string $text The option text [optional] + * + * @return object The option as an object (\stdClass instance) + * + * @since 3.0 + */ + public static function createOption($value = '', $text = '') + { + if (empty($text)) { + $text = $value; + } + + $option = new \stdClass(); + $option->value = $value; + $option->text = $text; + + return $option; + } + + /** + * Create and return a new Option Group + * + * @param string $label Value and label for group [optional] + * @param array $options Array of options to insert into group [optional] + * + * @return array Return the new group as an array + * + * @since 3.0 + */ + public static function createOptionGroup($label = '', $options = array()) + { + $group = array(); + $group['value'] = $label; + $group['text'] = $label; + $group['items'] = $options; + + return $group; + } + + /** + * Method to filter transitions by given id of state + * + * @param array $transitions Array of transitions + * @param int $pk Id of state + * @param int $workflowId Id of the workflow + * + * @return array + * + * @since __DEPLOY_VERSION__ + */ + public static function filterTransitions(array $transitions, int $pk, int $workflowId = 0): array + { + return array_values( + array_filter( + $transitions, + function ($var) use ($pk, $workflowId) { + return in_array($var['from_stage_id'], [-1, $pk]) && $workflowId == $var['workflow_id']; + } + ) + ); + } } diff --git a/administrator/components/com_modules/src/Model/ModuleModel.php b/administrator/components/com_modules/src/Model/ModuleModel.php index 4d4c267c33419..cfbed6597a4ac 100644 --- a/administrator/components/com_modules/src/Model/ModuleModel.php +++ b/administrator/components/com_modules/src/Model/ModuleModel.php @@ -1,4 +1,5 @@ 'batchAccess', - 'language_id' => 'batchLanguage', - ); - - /** - * Constructor. - * - * @param array $config An optional associative array of configuration settings. - */ - public function __construct($config = array()) - { - $config = array_merge( - array( - 'event_after_delete' => 'onExtensionAfterDelete', - 'event_after_save' => 'onExtensionAfterSave', - 'event_before_delete' => 'onExtensionBeforeDelete', - 'event_before_save' => 'onExtensionBeforeSave', - 'events_map' => array( - 'save' => 'extension', - 'delete' => 'extension' - ) - ), $config - ); - - parent::__construct($config); - - $this->setUpWorkflow('com_modules.module'); - } - - /** - * Method to auto-populate the model state. - * - * Note. Calling getState in this method will result in recursion. - * - * @return void - * - * @since 1.6 - */ - protected function populateState() - { - $app = Factory::getApplication(); - - // Load the User state. - $pk = $app->input->getInt('id'); - - if (!$pk) - { - if ($extensionId = (int) $app->getUserState('com_modules.add.module.extension_id')) - { - $this->setState('extension.id', $extensionId); - } - } - - $this->setState('module.id', $pk); - - // Load the parameters. - $params = ComponentHelper::getParams('com_modules'); - $this->setState('params', $params); - } - - /** - * Batch copy modules to a new position or current. - * - * @param integer $value The new value matching a module position. - * @param array $pks An array of row IDs. - * @param array $contexts An array of item contexts. - * - * @return boolean True if successful, false otherwise and internal error is set. - * - * @since 2.5 - */ - protected function batchCopy($value, $pks, $contexts) - { - // Set the variables - $user = Factory::getUser(); - $table = $this->getTable(); - $newIds = array(); - - foreach ($pks as $pk) - { - if ($user->authorise('core.create', 'com_modules')) - { - $table->reset(); - $table->load($pk); - - // Set the new position - if ($value == 'noposition') - { - $position = ''; - } - elseif ($value == 'nochange') - { - $position = $table->position; - } - else - { - $position = $value; - } - - $table->position = $position; - - // Copy of the Asset ID - $oldAssetId = $table->asset_id; - - // Alter the title if necessary - $data = $this->generateNewTitle(0, $table->title, $table->position); - $table->title = $data['0']; - - // Reset the ID because we are making a copy - $table->id = 0; - - // Unpublish the new module - $table->published = 0; - - if (!$table->store()) - { - $this->setError($table->getError()); - - return false; - } - - // Get the new item ID - $newId = $table->get('id'); - - // Add the new ID to the array - $newIds[$pk] = $newId; - - // Now we need to handle the module assignments - $db = $this->getDatabase(); - $query = $db->getQuery(true) - ->select($db->quoteName('menuid')) - ->from($db->quoteName('#__modules_menu')) - ->where($db->quoteName('moduleid') . ' = :moduleid') - ->bind(':moduleid', $pk, ParameterType::INTEGER); - $db->setQuery($query); - $menus = $db->loadColumn(); - - // Insert the new records into the table - foreach ($menus as $i => $menu) - { - $query->clear() - ->insert($db->quoteName('#__modules_menu')) - ->columns($db->quoteName(['moduleid', 'menuid'])) - ->values(implode(', ', [':newid' . $i, ':menu' . $i])) - ->bind(':newid' . $i, $newId, ParameterType::INTEGER) - ->bind(':menu' . $i, $menu, ParameterType::INTEGER); - $db->setQuery($query); - $db->execute(); - } - - // Copy rules - $query->clear() - ->update($db->quoteName('#__assets', 't')) - ->join('INNER', $db->quoteName('#__assets', 's') . - ' ON ' . $db->quoteName('s.id') . ' = ' . $oldAssetId - ) - ->set($db->quoteName('t.rules') . ' = ' . $db->quoteName('s.rules')) - ->where($db->quoteName('t.id') . ' = ' . $table->asset_id); - - $db->setQuery($query)->execute(); - } - else - { - $this->setError(Text::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_CREATE')); - - return false; - } - } - - // Clean the cache - $this->cleanCache(); - - return $newIds; - } - - /** - * Batch move modules to a new position or current. - * - * @param integer $value The new value matching a module position. - * @param array $pks An array of row IDs. - * @param array $contexts An array of item contexts. - * - * @return boolean True if successful, false otherwise and internal error is set. - * - * @since 2.5 - */ - protected function batchMove($value, $pks, $contexts) - { - // Set the variables - $user = Factory::getUser(); - $table = $this->getTable(); - - foreach ($pks as $pk) - { - if ($user->authorise('core.edit', 'com_modules')) - { - $table->reset(); - $table->load($pk); - - // Set the new position - if ($value == 'noposition') - { - $position = ''; - } - elseif ($value == 'nochange') - { - $position = $table->position; - } - else - { - $position = $value; - } - - $table->position = $position; - - if (!$table->store()) - { - $this->setError($table->getError()); - - return false; - } - } - else - { - $this->setError(Text::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_EDIT')); - - return false; - } - } - - // Clean the cache - $this->cleanCache(); - - return true; - } - - /** - * Method to test whether a record can have its state edited. - * - * @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 3.2 - */ - protected function canEditState($record) - { - // Check for existing module. - if (!empty($record->id)) - { - return Factory::getUser()->authorise('core.edit.state', 'com_modules.module.' . (int) $record->id); - } - - // Default to component settings if module not known. - return parent::canEditState($record); - } - - /** - * Method to delete rows. - * - * @param array &$pks An array of item ids. - * - * @return boolean Returns true on success, false on failure. - * - * @since 1.6 - * @throws \Exception - */ - public function delete(&$pks) - { - $app = Factory::getApplication(); - $pks = (array) $pks; - $user = Factory::getUser(); - $table = $this->getTable(); - $context = $this->option . '.' . $this->name; - - // Include the plugins for the on delete events. - PluginHelper::importPlugin($this->events_map['delete']); - - // Iterate the items to delete each one. - foreach ($pks as $pk) - { - if ($table->load($pk)) - { - // Access checks. - if (!$user->authorise('core.delete', 'com_modules.module.' . (int) $pk) || $table->published != -2) - { - Factory::getApplication()->enqueueMessage(Text::_('JERROR_CORE_DELETE_NOT_PERMITTED'), 'error'); - - return; - } - - // Trigger the before delete event. - $result = $app->triggerEvent($this->event_before_delete, array($context, $table)); - - if (in_array(false, $result, true) || !$table->delete($pk)) - { - throw new \Exception($table->getError()); - } - else - { - // Delete the menu assignments - $pk = (int) $pk; - $db = $this->getDatabase(); - $query = $db->getQuery(true) - ->delete($db->quoteName('#__modules_menu')) - ->where($db->quoteName('moduleid') . ' = :moduleid') - ->bind(':moduleid', $pk, ParameterType::INTEGER); - $db->setQuery($query); - $db->execute(); - - // Trigger the after delete event. - $app->triggerEvent($this->event_after_delete, array($context, $table)); - } - - // Clear module cache - parent::cleanCache($table->module); - - $this->workflow->deleteAssociation($pks); - } - else - { - throw new \Exception($table->getError()); - } - } - - // Clear modules cache - $this->cleanCache(); - - return true; - } - - /** - * Method to duplicate modules. - * - * @param array &$pks An array of primary key IDs. - * - * @return boolean Boolean true on success - * - * @since 1.6 - * @throws \Exception - */ - public function duplicate(&$pks) - { - $user = Factory::getUser(); - $db = $this->getDatabase(); - - // Access checks. - if (!$user->authorise('core.create', 'com_modules')) - { - throw new \Exception(Text::_('JERROR_CORE_CREATE_NOT_PERMITTED')); - } - - $table = $this->getTable(); - - foreach ($pks as $pk) - { - if ($table->load($pk, true)) - { - // Reset the id to create a new record. - $table->id = 0; - - // Alter the title. - $m = null; - - if (preg_match('#\((\d+)\)$#', $table->title, $m)) - { - $table->title = preg_replace('#\(\d+\)$#', '(' . ($m[1] + 1) . ')', $table->title); - } - - $data = $this->generateNewTitle(0, $table->title, $table->position); - $table->title = $data[0]; - - // Unpublish duplicate module - $table->published = 0; - - if (!$table->check() || !$table->store()) - { - throw new \Exception($table->getError()); - } - - $pk = (int) $pk; - $query = $db->getQuery(true) - ->select($db->quoteName('menuid')) - ->from($db->quoteName('#__modules_menu')) - ->where($db->quoteName('moduleid') . ' = :moduleid') - ->bind(':moduleid', $pk, ParameterType::INTEGER); - - $db->setQuery($query); - $rows = $db->loadColumn(); - - foreach ($rows as $menuid) - { - $tuples[] = (int) $table->id . ',' . (int) $menuid; - } - - $query = $db->getQuery(true) - ->select($db->quoteName('stage_id')) - ->from($db->quoteName('#__workflow_associations')) - ->where($db->quoteName('extension') . ' = ' . $db->quote('com_modules.module')) - ->where($db->quoteName('item_id') . ' = :moduleid') - ->bind(':moduleid', $pk, ParameterType::INTEGER); - - $db->setQuery($query); - $stageIdTuples[] = (int) $table->id . ',' . (int) $db->loadResult() . ',' . $db->quote('com_modules.module'); - } - else - { - throw new \Exception($table->getError()); - } - } - - if (!empty($tuples)) - { - // Module-Menu Mapping: Do it in one query - $query = $db->getQuery(true) - ->insert($db->quoteName('#__modules_menu')) - ->columns($db->quoteName(array('moduleid', 'menuid'))) - ->values($tuples); - - $db->setQuery($query); - - try - { - $db->execute(); - } - catch (\RuntimeException $e) - { - Factory::getApplication()->enqueueMessage($e->getMessage(), 'error'); - - return false; - } - } - - if (!empty($stageIdTuples)) - { - $query = $db->getQuery(true) - ->insert($db->quoteName('#__workflow_associations')) - ->columns($db->quoteName(array('item_id', 'stage_id', 'extension'))) - ->values($stageIdTuples); - - $db->setQuery($query); - - try - { - $db->execute(); - } - catch (\RuntimeException $e) - { - Factory::getApplication()->enqueueMessage($e->getMessage(), 'error'); - - return false; - } - } - - // Clear modules cache - $this->cleanCache(); - - return true; - } - - /** - * Method to change the title. - * - * @param integer $categoryId The id of the category. Not used here. - * @param string $title The title. - * @param string $position The position. - * - * @return array Contains the modified title. - * - * @since 2.5 - */ - protected function generateNewTitle($categoryId, $title, $position) - { - // Alter the title & alias - $table = $this->getTable(); - - while ($table->load(array('position' => $position, 'title' => $title))) - { - $title = StringHelper::increment($title); - } - - return array($title); - } - - /** - * Method to get the client object - * - * @return void - * - * @since 1.6 - */ - public function &getClient() - { - return $this->_client; - } - - /** - * Method to get the record form. - * - * @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|bool A Form object on success, false on failure - * - * @since 1.6 - */ - public function getForm($data = array(), $loadData = true) - { - // The folder and element vars are passed when saving the form. - if (empty($data)) - { - $item = $this->getItem(); - $clientId = $item->client_id; - $module = $item->module; - $id = $item->id; - } - else - { - $clientId = ArrayHelper::getValue($data, 'client_id'); - $module = ArrayHelper::getValue($data, 'module'); - $id = ArrayHelper::getValue($data, 'id'); - } - - // Add the default fields directory - $baseFolder = $clientId ? JPATH_ADMINISTRATOR : JPATH_SITE; - Form::addFieldPath($baseFolder . '/modules/' . $module . '/field'); - - // These variables are used to add data from the plugin XML files. - $this->setState('item.client_id', $clientId); - $this->setState('item.module', $module); - - // Get the form. - if ($clientId == 1) - { - $form = $this->loadForm('com_modules.module.admin', 'moduleadmin', array('control' => 'jform', 'load_data' => $loadData), true); - - // Display language field to filter admin custom menus per language - if (!ModuleHelper::isAdminMultilang()) - { - $form->setFieldAttribute('language', 'type', 'hidden'); - } - } - else - { - $form = $this->loadForm('com_modules.module', 'module', array('control' => 'jform', 'load_data' => $loadData), true); - } - - if (empty($form)) - { - return false; - } - - $user = Factory::getUser(); - - /** - * Check for existing module - * Modify the form based on Edit State access controls. - */ - if ($id != 0 && (!$user->authorise('core.edit.state', 'com_modules.module.' . (int) $id)) - || ($id == 0 && !$user->authorise('core.edit.state', 'com_modules')) ) - { - // Disable fields for display. - $form->setFieldAttribute('ordering', 'disabled', 'true'); - $form->setFieldAttribute('published', 'disabled', 'true'); - $form->setFieldAttribute('publish_up', 'disabled', 'true'); - $form->setFieldAttribute('publish_down', 'disabled', 'true'); - - // Disable fields while saving. - // The controller has already verified this is a record you can edit. - $form->setFieldAttribute('ordering', 'filter', 'unset'); - $form->setFieldAttribute('published', 'filter', 'unset'); - $form->setFieldAttribute('publish_up', 'filter', 'unset'); - $form->setFieldAttribute('publish_down', 'filter', 'unset'); - } - - return $form; - } - - /** - * Method to get the data that should be injected in the form. - * - * @return mixed The data for the form. - * - * @since 1.6 - */ - protected function loadFormData() - { - $app = Factory::getApplication(); - - // Check the session for previously entered form data. - $data = $app->getUserState('com_modules.edit.module.data', array()); - - if (empty($data)) - { - $data = $this->getItem(); - - // Pre-select some filters (Status, Module Position, Language, Access Level) in edit form if those have been selected in Module Manager - if (!$data->id) - { - $clientId = $app->input->getInt('client_id', 0); - $filters = (array) $app->getUserState('com_modules.modules.' . $clientId . '.filter'); - $data->set('published', $app->input->getInt('published', ((isset($filters['state']) && $filters['state'] !== '') ? $filters['state'] : null))); - $data->set('position', $app->input->getInt('position', (!empty($filters['position']) ? $filters['position'] : null))); - $data->set('language', $app->input->getString('language', (!empty($filters['language']) ? $filters['language'] : null))); - $data->set('access', $app->input->getInt('access', (!empty($filters['access']) ? $filters['access'] : $app->get('access')))); - } - - // Avoid to delete params of a second module opened in a new browser tab while new one is not saved yet. - if (empty($data->params)) - { - // This allows us to inject parameter settings into a new module. - $params = $app->getUserState('com_modules.add.module.params'); - - if (is_array($params)) - { - $data->set('params', $params); - } - } - } - - $this->preprocessData('com_modules.module', $data); - - return $data; - } - - /** - * Method to get a single record. - * - * @param integer $pk The id of the primary key. - * - * @return mixed Object on success, false on failure. - * - * @since 1.6 - */ - public function getItem($pk = null) - { - $pk = (!empty($pk)) ? (int) $pk : (int) $this->getState('module.id'); - $db = $this->getDatabase(); - - if (!isset($this->_cache[$pk])) - { - // Get a row instance. - $table = $this->getTable(); - - // Attempt to load the row. - $return = $table->load($pk); - - // Check for a table object error. - if ($return === false && $error = $table->getError()) - { - $this->setError($error); - - return false; - } - - // Check if we are creating a new extension. - if (empty($pk)) - { - if ($extensionId = (int) $this->getState('extension.id')) - { - $query = $db->getQuery(true) - ->select($db->quoteName(['element', 'client_id'])) - ->from($db->quoteName('#__extensions')) - ->where($db->quoteName('extension_id') . ' = :extensionid') - ->where($db->quoteName('type') . ' = ' . $db->quote('module')) - ->bind(':extensionid', $extensionId, ParameterType::INTEGER); - $db->setQuery($query); - - try - { - $extension = $db->loadObject(); - } - catch (\RuntimeException $e) - { - $this->setError($e->getMessage()); - - return false; - } - - if (empty($extension)) - { - $this->setError('COM_MODULES_ERROR_CANNOT_FIND_MODULE'); - - return false; - } - - // Extension found, prime some module values. - $table->module = $extension->element; - $table->client_id = $extension->client_id; - } - else - { - Factory::getApplication()->redirect(Route::_('index.php?option=com_modules&view=modules', false)); - - return false; - } - } - - // Convert to the \Joomla\CMS\Object\CMSObject before adding other data. - $properties = $table->getProperties(1); - $this->_cache[$pk] = ArrayHelper::toObject($properties, CMSObject::class); - - // Convert the params field to an array. - $registry = new Registry($table->params); - $this->_cache[$pk]->params = $registry->toArray(); - - // Determine the page assignment mode. - $query = $db->getQuery(true) - ->select($db->quoteName('menuid')) - ->from($db->quoteName('#__modules_menu')) - ->where($db->quoteName('moduleid') . ' = :moduleid') - ->bind(':moduleid', $pk, ParameterType::INTEGER); - $db->setQuery($query); - $assigned = $db->loadColumn(); - - if (empty($pk)) - { - // If this is a new module, assign to all pages. - $assignment = 0; - } - elseif (empty($assigned)) - { - // For an existing module it is assigned to none. - $assignment = '-'; - } - else - { - if ($assigned[0] > 0) - { - $assignment = 1; - } - elseif ($assigned[0] < 0) - { - $assignment = -1; - } - else - { - $assignment = 0; - } - } - - $this->_cache[$pk]->assigned = $assigned; - $this->_cache[$pk]->assignment = $assignment; - - // Get the module XML. - $client = ApplicationHelper::getClientInfo($table->client_id); - $path = Path::clean($client->path . '/modules/' . $table->module . '/' . $table->module . '.xml'); - - if (file_exists($path)) - { - $this->_cache[$pk]->xml = simplexml_load_file($path); - } - else - { - $this->_cache[$pk]->xml = null; - } - } - - return $this->_cache[$pk]; - } - - /** - * Get the necessary data to load an item help screen. - * - * @return object An object with key, url, and local properties for loading the item help screen. - * - * @since 1.6 - */ - public function getHelp() - { - return (object) array('key' => $this->helpKey, 'url' => $this->helpURL); - } - - /** - * Returns a reference to the a Table object, always creating it. - * - * @param string $type The table type to instantiate - * @param string $prefix A prefix for the table class name. Optional. - * @param array $config Configuration array for model. Optional. - * - * @return Table A database object - * - * @since 1.6 - */ - public function getTable($type = 'Module', $prefix = 'JTable', $config = array()) - { - return Table::getInstance($type, $prefix, $config); - } - - /** - * Prepare and sanitise the table prior to saving. - * - * @param Table $table The database object - * - * @return void - * - * @since 1.6 - */ - protected function prepareTable($table) - { - // Set the publish date to now - if ($table->published == Workflow::CONDITION_PUBLISHED && (int) $table->publish_up == 0) - { - $table->publish_up = Factory::getDate()->toSql(); - } - - if ($table->published == Workflow::CONDITION_PUBLISHED && intval($table->publish_down) == 0) - { - $table->publish_down = null; - } - - $table->title = htmlspecialchars_decode($table->title, ENT_QUOTES); - $table->position = trim($table->position); - } - - /** - * 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 1.6 - * @throws \Exception if there is an error loading the form. - */ - protected function preprocessForm(Form $form, $data, $group = 'content') - { - $lang = Factory::getLanguage(); - $clientId = $this->getState('item.client_id'); - $module = $this->getState('item.module'); - - $client = ApplicationHelper::getClientInfo($clientId); - $formFile = Path::clean($client->path . '/modules/' . $module . '/' . $module . '.xml'); - - // Load the core and/or local language file(s). - $lang->load($module, $client->path) - || $lang->load($module, $client->path . '/modules/' . $module); - - if (file_exists($formFile)) - { - // Get the module form. - if (!$form->loadFile($formFile, false, '//config')) - { - throw new \Exception(Text::_('JERROR_LOADFILE_FAILED')); - } - - // Attempt to load the xml file. - if (!$xml = simplexml_load_file($formFile)) - { - throw new \Exception(Text::_('JERROR_LOADFILE_FAILED')); - } - - // Get the help data from the XML file if present. - $help = $xml->xpath('/extension/help'); - - if (!empty($help)) - { - $helpKey = trim((string) $help[0]['key']); - $helpURL = trim((string) $help[0]['url']); - - $this->helpKey = $helpKey ?: $this->helpKey; - $this->helpURL = $helpURL ?: $this->helpURL; - } - } - - // Load the default advanced params - Form::addFormPath(JPATH_ADMINISTRATOR . '/components/com_modules/models/forms'); - $form->loadFile('advanced', false); - - // Load chrome specific params for global files - $chromePath = JPATH_SITE . '/layouts/chromes'; - $chromeFormFiles = Folder::files($chromePath, '.*\.xml'); - - if ($chromeFormFiles) - { - Form::addFormPath($chromePath); - - foreach ($chromeFormFiles as $formFile) - { - $form->loadFile(basename($formFile, '.xml'), false); - } - } - - // Load chrome specific params for template files - $templates = ModulesHelper::getTemplates($clientId); - - foreach ($templates as $template) - { - $chromePath = $client->path . '/templates/' . $template->element . '/html/layouts/chromes'; - - // Skip if there is no chrome folder in that template. - if (!is_dir($chromePath)) - { - continue; - } - - $chromeFormFiles = Folder::files($chromePath, '.*\.xml'); - - if ($chromeFormFiles) - { - Form::addFormPath($chromePath); - - foreach ($chromeFormFiles as $formFile) - { - $form->loadFile(basename($formFile, '.xml'), false); - } - } - } - - if (ComponentHelper::getParams('com_modules')->get('workflow_enabled')) - { - Factory::getLanguage()->load('com_workflow', JPATH_ADMINISTRATOR); - - /** - * The workflowPreprocessForm function enables the workflow plugins and adds the - * transition field to the form. We do not need to add the transition field to the - * form in the case of items so we separately call the importWorkflowPlugins function. - */ - if (!empty(Factory::getApplication()->input->get('id'))) - { - $this->workflowPreprocessForm($form, $data); - } - else - { - // Import the workflow plugin group to allow form manipulation. - $this->importWorkflowPlugins(); - $this->prepareWorkflowField($form, $data); - } - } - - // Trigger the default form events. - parent::preprocessForm($form, $data, $group); - } - - /** - * Loads ContentHelper for filters before validating data. - * - * @param object $form The form to validate against. - * @param array $data The data to validate. - * @param string $group The name of the group(defaults to null). - * - * @return mixed Array of filtered data if valid, false otherwise. - * - * @since 1.1 - */ - public function validate($form, $data, $group = null) - { - if (!Factory::getUser()->authorise('core.admin', 'com_modules')) - { - if (isset($data['rules'])) - { - unset($data['rules']); - } - } - - return parent::validate($form, $data, $group); - } - - /** - * Method to save the form data. - * - * @param array $data The form data. - * - * @return boolean True on success. - * - * @since 1.6 - */ - public function save($data) - { - $input = Factory::getApplication()->input; - $table = $this->getTable(); - $pk = (!empty($data['id'])) ? $data['id'] : (int) $this->getState('module.id'); - $isNew = true; - $context = $this->option . '.' . $this->name; - - // Include the plugins for the save event. - PluginHelper::importPlugin($this->events_map['save']); - - // Load the row if saving an existing record. - if ($pk > 0) - { - $table->load($pk); - $isNew = false; - } - - // Alter the title and published state for Save as Copy - if ($input->get('task') == 'save2copy') - { - $orig_table = clone $this->getTable(); - $orig_table->load((int) $input->getInt('id')); - $data['published'] = 0; - - if ($data['title'] == $orig_table->title) - { - $data['title'] = StringHelper::increment($data['title']); - } - } - - // Bind the data. - if (!$table->bind($data)) - { - $this->setError($table->getError()); - - return false; - } - - // Prepare the row for saving - $this->prepareTable($table); - - // Check the data. - if (!$table->check()) - { - $this->setError($table->getError()); - - return false; - } - - // Trigger the before save event. - $result = Factory::getApplication()->triggerEvent($this->event_before_save, array($context, &$table, $isNew)); - - if (in_array(false, $result, true)) - { - $this->setError($table->getError()); - - return false; - } - - // Store the data. - if (!$table->store()) - { - $this->setError($table->getError()); - - return false; - } - - $this->workflowBeforeSave(); - - // Process the menu link mappings. - $assignment = $data['assignment'] ?? 0; - - $table->id = (int) $table->id; - - // Delete old module to menu item associations - $db = $this->getDatabase(); - $query = $db->getQuery(true) - ->delete($db->quoteName('#__modules_menu')) - ->where($db->quoteName('moduleid') . ' = :moduleid') - ->bind(':moduleid', $table->id, ParameterType::INTEGER); - $db->setQuery($query); - - try - { - $db->execute(); - } - catch (\RuntimeException $e) - { - $this->setError($e->getMessage()); - - return false; - } - - // If the assignment is numeric, then something is selected (otherwise it's none). - if (is_numeric($assignment)) - { - // Variable is numeric, but could be a string. - $assignment = (int) $assignment; - - // Logic check: if no module excluded then convert to display on all. - if ($assignment == -1 && empty($data['assigned'])) - { - $assignment = 0; - } - - // Check needed to stop a module being assigned to `All` - // and other menu items resulting in a module being displayed twice. - if ($assignment === 0) - { - // Assign new module to `all` menu item associations. - $query->clear() - ->insert($db->quoteName('#__modules_menu')) - ->columns($db->quoteName(['moduleid', 'menuid'])) - ->values(implode(', ', [':moduleid', 0])) - ->bind(':moduleid', $table->id, ParameterType::INTEGER); - $db->setQuery($query); - - try - { - $db->execute(); - } - catch (\RuntimeException $e) - { - $this->setError($e->getMessage()); - - return false; - } - } - elseif (!empty($data['assigned'])) - { - // Get the sign of the number. - $sign = $assignment < 0 ? -1 : 1; - - $query->clear() - ->insert($db->quoteName('#__modules_menu')) - ->columns($db->quoteName(array('moduleid', 'menuid'))); - - foreach ($data['assigned'] as &$pk) - { - $query->values((int) $table->id . ',' . (int) $pk * $sign); - } - - $db->setQuery($query); - - try - { - $db->execute(); - } - catch (\RuntimeException $e) - { - $this->setError($e->getMessage()); - - return false; - } - } - } - - // Trigger the after save event. - Factory::getApplication()->triggerEvent($this->event_after_save, array($context, &$table, $isNew)); - - // Compute the extension id of this module in case the controller wants it. - $query->clear() - ->select($db->quoteName('extension_id')) - ->from($db->quoteName('#__extensions', 'e')) - ->join( - 'LEFT', - $db->quoteName('#__modules', 'm') . ' ON ' . $db->quoteName('e.client_id') . ' = ' . (int) $table->client_id . - ' AND ' . $db->quoteName('e.element') . ' = ' . $db->quoteName('m.module') - ) - ->where($db->quoteName('m.id') . ' = :id') - ->bind(':id', $table->id, ParameterType::INTEGER); - $db->setQuery($query); - - try - { - $extensionId = $db->loadResult(); - } - catch (\RuntimeException $e) - { - Factory::getApplication()->enqueueMessage($e->getMessage(), 'error'); - - return false; - } - - $this->setState('module.extension_id', $extensionId); - $this->setState('module.id', $table->id); - $this->setState('module.new', $isNew); - - $this->workflowAfterSave($data); - - // Clear modules cache - $this->cleanCache(); - - // Clean module cache - parent::cleanCache($table->module); - - return true; - } - - /** - * 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 1.6 - */ - protected function getReorderConditions($table) - { - $db = $this->getDatabase(); - - return [ - $db->quoteName('client_id') . ' = ' . (int) $table->client_id, - $db->quoteName('position') . ' = ' . $db->quote($table->position), - ]; - } - - /** - * Custom clean cache method for different clients - * - * @param string $group The name of the plugin group to import (defaults to null). - * @param integer $clientId @deprecated 5.0 No longer used. - * - * @return void - * - * @since 1.6 - */ - protected function cleanCache($group = null, $clientId = 0) - { - parent::cleanCache('com_modules'); - } - - /** - * 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 __DEPLOY_VERSION__ - */ - public function publish(&$pks, $value = 1) - { - $this->workflowBeforeStageChange(); - - return parent::publish($pks, $value); - } - - /** - * Overrides the function in WorkflowBehaviorTrait to get the default - * stage ID while creating a new module. - * - * @param Form $form A Form object. - * @param mixed $data The data expected for the form. - * - * @return boolean|integer An integer, holding the stage ID or false - * - * @since __DEPLOY_VERSION__ - */ - protected function getStageForNewItem(Form $form, $data) - { - $db = $this->getDbo(); - - $query = $db->getQuery(true) - ->select($db->quoteName('id')) - ->from($db->quoteName('#__workflow_stages')) - ->where($db->quoteName('default') . '= 1'); - - if (isset($data['workflow_id'])) - { - // If workflow_id is set by the query then we find the stage corresponding to that workflow_id - $query->where($db->quoteName('workflow_id') . ' = :workflowid') - ->bind(':workflowid', $data['workflow_id'], ParameterType::INTEGER); - } - else - { - // Query to find the default workflow id of the extension type com_modules.module - $defaultWorkflowQuery = $db->getQuery(true) - ->select($db->quoteName('id')) - ->from($db->quoteName('#__workflows')) - ->where($db->quoteName('default') . ' = 1') - ->where($db->quoteName('extension') . ' = ' . $db->quote('com_modules.module')); - - $query->where($db->quoteName('workflow_id') . ' IN (' . $defaultWorkflowQuery . ')'); - } - - $db->setQuery($query); - $defaultStage = $db->loadResult(); - - if (empty($defaultStage)) - { - return false; - } - - return $defaultStage; - } - - /** - * Adds default stage to workflow field in the form. - * - * @param Form $form The form to change - * @param array|object $data The form data - * - * @return void - * - * @since __DEPLOY_VERSION__ - */ - public static function prepareWorkflowField(Form $form, $data) - { - $db = Factory::getDbo(); - - $data = (array) $data; - - $form->setFieldAttribute('workflow_id', 'default', 'inherit'); - - $query = $db->getQuery(true); - - $query->select([$db->quoteName('title'), $db->quoteName('id')]) - ->from($db->quoteName('#__workflows')) - ->where( - [ - $db->quoteName('default') . ' = 1', - $db->quoteName('published') . ' = 1', - $db->quoteName('extension') . ' = ' . $db->quote('com_modules.module'), - ] - ); - - $defaultWorkflow = $db->setQuery($query)->loadObject(); - $field = $form->getField('workflow_id'); - - $field->addOption(Text::sprintf('COM_WORKFLOW_USE_DEFAULT_WORKFLOW', Text::_($defaultWorkflow->title)), ['value' => $defaultWorkflow->id]); - - $field->addOption('- ' . Text::_('COM_MODULES_WORKFLOWS') . ' -', ['disabled' => 'true']); - } + use WorkflowBehaviorTrait; + + /** + * The type alias for this content type. + * + * @var string + * @since 3.4 + */ + public $typeAlias = 'com_modules.module'; + + /** + * @var string The prefix to use with controller messages. + * @since 1.6 + */ + protected $text_prefix = 'COM_MODULES'; + + /** + * @var string The help screen key for the module. + * @since 1.6 + */ + protected $helpKey = ''; + + /** + * @var string The help screen base URL for the module. + * @since 1.6 + */ + protected $helpURL; + + /** + * Batch copy/move command. If set to false, + * the batch copy/move command is not supported + * + * @var string + */ + protected $batch_copymove = 'position_id'; + + /** + * Allowed batch commands + * + * @var array + */ + protected $batch_commands = array( + 'assetgroup_id' => 'batchAccess', + 'language_id' => 'batchLanguage', + ); + + /** + * Constructor. + * + * @param array $config An optional associative array of configuration settings. + */ + public function __construct($config = array()) + { + $config = array_merge( + array( + 'event_after_delete' => 'onExtensionAfterDelete', + 'event_after_save' => 'onExtensionAfterSave', + 'event_before_delete' => 'onExtensionBeforeDelete', + 'event_before_save' => 'onExtensionBeforeSave', + 'events_map' => array( + 'save' => 'extension', + 'delete' => 'extension' + ) + ), + $config + ); + + parent::__construct($config); + + $this->setUpWorkflow('com_modules.module'); + } + + /** + * Method to auto-populate the model state. + * + * Note. Calling getState in this method will result in recursion. + * + * @return void + * + * @since 1.6 + */ + protected function populateState() + { + $app = Factory::getApplication(); + + // Load the User state. + $pk = $app->input->getInt('id'); + + if (!$pk) { + if ($extensionId = (int) $app->getUserState('com_modules.add.module.extension_id')) { + $this->setState('extension.id', $extensionId); + } + } + + $this->setState('module.id', $pk); + + // Load the parameters. + $params = ComponentHelper::getParams('com_modules'); + $this->setState('params', $params); + } + + /** + * Batch copy modules to a new position or current. + * + * @param integer $value The new value matching a module position. + * @param array $pks An array of row IDs. + * @param array $contexts An array of item contexts. + * + * @return boolean True if successful, false otherwise and internal error is set. + * + * @since 2.5 + */ + protected function batchCopy($value, $pks, $contexts) + { + // Set the variables + $user = Factory::getUser(); + $table = $this->getTable(); + $newIds = array(); + + foreach ($pks as $pk) { + if ($user->authorise('core.create', 'com_modules')) { + $table->reset(); + $table->load($pk); + + // Set the new position + if ($value == 'noposition') { + $position = ''; + } elseif ($value == 'nochange') { + $position = $table->position; + } else { + $position = $value; + } + + $table->position = $position; + + // Copy of the Asset ID + $oldAssetId = $table->asset_id; + + // Alter the title if necessary + $data = $this->generateNewTitle(0, $table->title, $table->position); + $table->title = $data['0']; + + // Reset the ID because we are making a copy + $table->id = 0; + + // Unpublish the new module + $table->published = 0; + + if (!$table->store()) { + $this->setError($table->getError()); + + return false; + } + + // Get the new item ID + $newId = $table->get('id'); + + // Add the new ID to the array + $newIds[$pk] = $newId; + + // Now we need to handle the module assignments + $db = $this->getDatabase(); + $query = $db->getQuery(true) + ->select($db->quoteName('menuid')) + ->from($db->quoteName('#__modules_menu')) + ->where($db->quoteName('moduleid') . ' = :moduleid') + ->bind(':moduleid', $pk, ParameterType::INTEGER); + $db->setQuery($query); + $menus = $db->loadColumn(); + + // Insert the new records into the table + foreach ($menus as $i => $menu) { + $query->clear() + ->insert($db->quoteName('#__modules_menu')) + ->columns($db->quoteName(['moduleid', 'menuid'])) + ->values(implode(', ', [':newid' . $i, ':menu' . $i])) + ->bind(':newid' . $i, $newId, ParameterType::INTEGER) + ->bind(':menu' . $i, $menu, ParameterType::INTEGER); + $db->setQuery($query); + $db->execute(); + } + + // Copy rules + $query->clear() + ->update($db->quoteName('#__assets', 't')) + ->join('INNER', $db->quoteName('#__assets', 's') . + ' ON ' . $db->quoteName('s.id') . ' = ' . $oldAssetId) + ->set($db->quoteName('t.rules') . ' = ' . $db->quoteName('s.rules')) + ->where($db->quoteName('t.id') . ' = ' . $table->asset_id); + + $db->setQuery($query)->execute(); + } else { + $this->setError(Text::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_CREATE')); + + return false; + } + } + + // Clean the cache + $this->cleanCache(); + + return $newIds; + } + + /** + * Batch move modules to a new position or current. + * + * @param integer $value The new value matching a module position. + * @param array $pks An array of row IDs. + * @param array $contexts An array of item contexts. + * + * @return boolean True if successful, false otherwise and internal error is set. + * + * @since 2.5 + */ + protected function batchMove($value, $pks, $contexts) + { + // Set the variables + $user = Factory::getUser(); + $table = $this->getTable(); + + foreach ($pks as $pk) { + if ($user->authorise('core.edit', 'com_modules')) { + $table->reset(); + $table->load($pk); + + // Set the new position + if ($value == 'noposition') { + $position = ''; + } elseif ($value == 'nochange') { + $position = $table->position; + } else { + $position = $value; + } + + $table->position = $position; + + if (!$table->store()) { + $this->setError($table->getError()); + + return false; + } + } else { + $this->setError(Text::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_EDIT')); + + return false; + } + } + + // Clean the cache + $this->cleanCache(); + + return true; + } + + /** + * Method to test whether a record can have its state edited. + * + * @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 3.2 + */ + protected function canEditState($record) + { + // Check for existing module. + if (!empty($record->id)) { + return Factory::getUser()->authorise('core.edit.state', 'com_modules.module.' . (int) $record->id); + } + + // Default to component settings if module not known. + return parent::canEditState($record); + } + + /** + * Method to delete rows. + * + * @param array &$pks An array of item ids. + * + * @return boolean Returns true on success, false on failure. + * + * @since 1.6 + * @throws \Exception + */ + public function delete(&$pks) + { + $app = Factory::getApplication(); + $pks = (array) $pks; + $user = Factory::getUser(); + $table = $this->getTable(); + $context = $this->option . '.' . $this->name; + + // Include the plugins for the on delete events. + PluginHelper::importPlugin($this->events_map['delete']); + + // Iterate the items to delete each one. + foreach ($pks as $pk) { + if ($table->load($pk)) { + // Access checks. + if (!$user->authorise('core.delete', 'com_modules.module.' . (int) $pk) || $table->published != -2) { + Factory::getApplication()->enqueueMessage(Text::_('JERROR_CORE_DELETE_NOT_PERMITTED'), 'error'); + + return; + } + + // Trigger the before delete event. + $result = $app->triggerEvent($this->event_before_delete, array($context, $table)); + + if (in_array(false, $result, true) || !$table->delete($pk)) { + throw new \Exception($table->getError()); + } else { + // Delete the menu assignments + $pk = (int) $pk; + $db = $this->getDatabase(); + $query = $db->getQuery(true) + ->delete($db->quoteName('#__modules_menu')) + ->where($db->quoteName('moduleid') . ' = :moduleid') + ->bind(':moduleid', $pk, ParameterType::INTEGER); + $db->setQuery($query); + $db->execute(); + + // Trigger the after delete event. + $app->triggerEvent($this->event_after_delete, array($context, $table)); + } + + // Clear module cache + parent::cleanCache($table->module); + + $this->workflow->deleteAssociation($pks); + } else { + throw new \Exception($table->getError()); + } + } + + // Clear modules cache + $this->cleanCache(); + + return true; + } + + /** + * Method to duplicate modules. + * + * @param array &$pks An array of primary key IDs. + * + * @return boolean Boolean true on success + * + * @since 1.6 + * @throws \Exception + */ + public function duplicate(&$pks) + { + $user = Factory::getUser(); + $db = $this->getDatabase(); + + // Access checks. + if (!$user->authorise('core.create', 'com_modules')) { + throw new \Exception(Text::_('JERROR_CORE_CREATE_NOT_PERMITTED')); + } + + $table = $this->getTable(); + + foreach ($pks as $pk) { + if ($table->load($pk, true)) { + // Reset the id to create a new record. + $table->id = 0; + + // Alter the title. + $m = null; + + if (preg_match('#\((\d+)\)$#', $table->title, $m)) { + $table->title = preg_replace('#\(\d+\)$#', '(' . ($m[1] + 1) . ')', $table->title); + } + + $data = $this->generateNewTitle(0, $table->title, $table->position); + $table->title = $data[0]; + + // Unpublish duplicate module + $table->published = 0; + + if (!$table->check() || !$table->store()) { + throw new \Exception($table->getError()); + } + + $pk = (int) $pk; + $query = $db->getQuery(true) + ->select($db->quoteName('menuid')) + ->from($db->quoteName('#__modules_menu')) + ->where($db->quoteName('moduleid') . ' = :moduleid') + ->bind(':moduleid', $pk, ParameterType::INTEGER); + + $db->setQuery($query); + $rows = $db->loadColumn(); + + foreach ($rows as $menuid) { + $tuples[] = (int) $table->id . ',' . (int) $menuid; + } + + $query = $db->getQuery(true) + ->select($db->quoteName('stage_id')) + ->from($db->quoteName('#__workflow_associations')) + ->where($db->quoteName('extension') . ' = ' . $db->quote('com_modules.module')) + ->where($db->quoteName('item_id') . ' = :moduleid') + ->bind(':moduleid', $pk, ParameterType::INTEGER); + + $db->setQuery($query); + $stageIdTuples[] = (int) $table->id . ',' . (int) $db->loadResult() . ',' . $db->quote('com_modules.module'); + } else { + throw new \Exception($table->getError()); + } + } + + if (!empty($tuples)) { + // Module-Menu Mapping: Do it in one query + $query = $db->getQuery(true) + ->insert($db->quoteName('#__modules_menu')) + ->columns($db->quoteName(array('moduleid', 'menuid'))) + ->values($tuples); + + $db->setQuery($query); + + try { + $db->execute(); + } catch (\RuntimeException $e) { + Factory::getApplication()->enqueueMessage($e->getMessage(), 'error'); + + return false; + } + } + + if (!empty($stageIdTuples)) { + $query = $db->getQuery(true) + ->insert($db->quoteName('#__workflow_associations')) + ->columns($db->quoteName(array('item_id', 'stage_id', 'extension'))) + ->values($stageIdTuples); + + $db->setQuery($query); + + try { + $db->execute(); + } catch (\RuntimeException $e) { + Factory::getApplication()->enqueueMessage($e->getMessage(), 'error'); + + return false; + } + } + + // Clear modules cache + $this->cleanCache(); + + return true; + } + + /** + * Method to change the title. + * + * @param integer $categoryId The id of the category. Not used here. + * @param string $title The title. + * @param string $position The position. + * + * @return array Contains the modified title. + * + * @since 2.5 + */ + protected function generateNewTitle($categoryId, $title, $position) + { + // Alter the title & alias + $table = $this->getTable(); + + while ($table->load(array('position' => $position, 'title' => $title))) { + $title = StringHelper::increment($title); + } + + return array($title); + } + + /** + * Method to get the client object + * + * @return void + * + * @since 1.6 + */ + public function &getClient() + { + return $this->_client; + } + + /** + * Method to get the record form. + * + * @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|bool A Form object on success, false on failure + * + * @since 1.6 + */ + public function getForm($data = array(), $loadData = true) + { + // The folder and element vars are passed when saving the form. + if (empty($data)) { + $item = $this->getItem(); + $clientId = $item->client_id; + $module = $item->module; + $id = $item->id; + } else { + $clientId = ArrayHelper::getValue($data, 'client_id'); + $module = ArrayHelper::getValue($data, 'module'); + $id = ArrayHelper::getValue($data, 'id'); + } + + // Add the default fields directory + $baseFolder = $clientId ? JPATH_ADMINISTRATOR : JPATH_SITE; + Form::addFieldPath($baseFolder . '/modules/' . $module . '/field'); + + // These variables are used to add data from the plugin XML files. + $this->setState('item.client_id', $clientId); + $this->setState('item.module', $module); + + // Get the form. + if ($clientId == 1) { + $form = $this->loadForm('com_modules.module.admin', 'moduleadmin', array('control' => 'jform', 'load_data' => $loadData), true); + + // Display language field to filter admin custom menus per language + if (!ModuleHelper::isAdminMultilang()) { + $form->setFieldAttribute('language', 'type', 'hidden'); + } + } else { + $form = $this->loadForm('com_modules.module', 'module', array('control' => 'jform', 'load_data' => $loadData), true); + } + + if (empty($form)) { + return false; + } + + $user = Factory::getUser(); + + /** + * Check for existing module + * Modify the form based on Edit State access controls. + */ + if ( + $id != 0 && (!$user->authorise('core.edit.state', 'com_modules.module.' . (int) $id)) + || ($id == 0 && !$user->authorise('core.edit.state', 'com_modules')) + ) { + // Disable fields for display. + $form->setFieldAttribute('ordering', 'disabled', 'true'); + $form->setFieldAttribute('published', 'disabled', 'true'); + $form->setFieldAttribute('publish_up', 'disabled', 'true'); + $form->setFieldAttribute('publish_down', 'disabled', 'true'); + + // Disable fields while saving. + // The controller has already verified this is a record you can edit. + $form->setFieldAttribute('ordering', 'filter', 'unset'); + $form->setFieldAttribute('published', 'filter', 'unset'); + $form->setFieldAttribute('publish_up', 'filter', 'unset'); + $form->setFieldAttribute('publish_down', 'filter', 'unset'); + } + + return $form; + } + + /** + * Method to get the data that should be injected in the form. + * + * @return mixed The data for the form. + * + * @since 1.6 + */ + protected function loadFormData() + { + $app = Factory::getApplication(); + + // Check the session for previously entered form data. + $data = $app->getUserState('com_modules.edit.module.data', array()); + + if (empty($data)) { + $data = $this->getItem(); + + // Pre-select some filters (Status, Module Position, Language, Access Level) in edit form if those have been selected in Module Manager + if (!$data->id) { + $clientId = $app->input->getInt('client_id', 0); + $filters = (array) $app->getUserState('com_modules.modules.' . $clientId . '.filter'); + $data->set('published', $app->input->getInt('published', ((isset($filters['state']) && $filters['state'] !== '') ? $filters['state'] : null))); + $data->set('position', $app->input->getInt('position', (!empty($filters['position']) ? $filters['position'] : null))); + $data->set('language', $app->input->getString('language', (!empty($filters['language']) ? $filters['language'] : null))); + $data->set('access', $app->input->getInt('access', (!empty($filters['access']) ? $filters['access'] : $app->get('access')))); + } + + // Avoid to delete params of a second module opened in a new browser tab while new one is not saved yet. + if (empty($data->params)) { + // This allows us to inject parameter settings into a new module. + $params = $app->getUserState('com_modules.add.module.params'); + + if (is_array($params)) { + $data->set('params', $params); + } + } + } + + $this->preprocessData('com_modules.module', $data); + + return $data; + } + + /** + * Method to get a single record. + * + * @param integer $pk The id of the primary key. + * + * @return mixed Object on success, false on failure. + * + * @since 1.6 + */ + public function getItem($pk = null) + { + $pk = (!empty($pk)) ? (int) $pk : (int) $this->getState('module.id'); + $db = $this->getDatabase(); + + if (!isset($this->_cache[$pk])) { + // Get a row instance. + $table = $this->getTable(); + + // Attempt to load the row. + $return = $table->load($pk); + + // Check for a table object error. + if ($return === false && $error = $table->getError()) { + $this->setError($error); + + return false; + } + + // Check if we are creating a new extension. + if (empty($pk)) { + if ($extensionId = (int) $this->getState('extension.id')) { + $query = $db->getQuery(true) + ->select($db->quoteName(['element', 'client_id'])) + ->from($db->quoteName('#__extensions')) + ->where($db->quoteName('extension_id') . ' = :extensionid') + ->where($db->quoteName('type') . ' = ' . $db->quote('module')) + ->bind(':extensionid', $extensionId, ParameterType::INTEGER); + $db->setQuery($query); + + try { + $extension = $db->loadObject(); + } catch (\RuntimeException $e) { + $this->setError($e->getMessage()); + + return false; + } + + if (empty($extension)) { + $this->setError('COM_MODULES_ERROR_CANNOT_FIND_MODULE'); + + return false; + } + + // Extension found, prime some module values. + $table->module = $extension->element; + $table->client_id = $extension->client_id; + } else { + Factory::getApplication()->redirect(Route::_('index.php?option=com_modules&view=modules', false)); + + return false; + } + } + + // Convert to the \Joomla\CMS\Object\CMSObject before adding other data. + $properties = $table->getProperties(1); + $this->_cache[$pk] = ArrayHelper::toObject($properties, CMSObject::class); + + // Convert the params field to an array. + $registry = new Registry($table->params); + $this->_cache[$pk]->params = $registry->toArray(); + + // Determine the page assignment mode. + $query = $db->getQuery(true) + ->select($db->quoteName('menuid')) + ->from($db->quoteName('#__modules_menu')) + ->where($db->quoteName('moduleid') . ' = :moduleid') + ->bind(':moduleid', $pk, ParameterType::INTEGER); + $db->setQuery($query); + $assigned = $db->loadColumn(); + + if (empty($pk)) { + // If this is a new module, assign to all pages. + $assignment = 0; + } elseif (empty($assigned)) { + // For an existing module it is assigned to none. + $assignment = '-'; + } else { + if ($assigned[0] > 0) { + $assignment = 1; + } elseif ($assigned[0] < 0) { + $assignment = -1; + } else { + $assignment = 0; + } + } + + $this->_cache[$pk]->assigned = $assigned; + $this->_cache[$pk]->assignment = $assignment; + + // Get the module XML. + $client = ApplicationHelper::getClientInfo($table->client_id); + $path = Path::clean($client->path . '/modules/' . $table->module . '/' . $table->module . '.xml'); + + if (file_exists($path)) { + $this->_cache[$pk]->xml = simplexml_load_file($path); + } else { + $this->_cache[$pk]->xml = null; + } + } + + return $this->_cache[$pk]; + } + + /** + * Get the necessary data to load an item help screen. + * + * @return object An object with key, url, and local properties for loading the item help screen. + * + * @since 1.6 + */ + public function getHelp() + { + return (object) array('key' => $this->helpKey, 'url' => $this->helpURL); + } + + /** + * Returns a reference to the a Table object, always creating it. + * + * @param string $type The table type to instantiate + * @param string $prefix A prefix for the table class name. Optional. + * @param array $config Configuration array for model. Optional. + * + * @return Table A database object + * + * @since 1.6 + */ + public function getTable($type = 'Module', $prefix = 'JTable', $config = array()) + { + return Table::getInstance($type, $prefix, $config); + } + + /** + * Prepare and sanitise the table prior to saving. + * + * @param Table $table The database object + * + * @return void + * + * @since 1.6 + */ + protected function prepareTable($table) + { + // Set the publish date to now + if ($table->published == Workflow::CONDITION_PUBLISHED && (int) $table->publish_up == 0) { + $table->publish_up = Factory::getDate()->toSql(); + } + + if ($table->published == Workflow::CONDITION_PUBLISHED && intval($table->publish_down) == 0) { + $table->publish_down = null; + } + + $table->title = htmlspecialchars_decode($table->title, ENT_QUOTES); + $table->position = trim($table->position); + } + + /** + * 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 1.6 + * @throws \Exception if there is an error loading the form. + */ + protected function preprocessForm(Form $form, $data, $group = 'content') + { + $lang = Factory::getLanguage(); + $clientId = $this->getState('item.client_id'); + $module = $this->getState('item.module'); + + $client = ApplicationHelper::getClientInfo($clientId); + $formFile = Path::clean($client->path . '/modules/' . $module . '/' . $module . '.xml'); + + // Load the core and/or local language file(s). + $lang->load($module, $client->path) + || $lang->load($module, $client->path . '/modules/' . $module); + + if (file_exists($formFile)) { + // Get the module form. + if (!$form->loadFile($formFile, false, '//config')) { + throw new \Exception(Text::_('JERROR_LOADFILE_FAILED')); + } + + // Attempt to load the xml file. + if (!$xml = simplexml_load_file($formFile)) { + throw new \Exception(Text::_('JERROR_LOADFILE_FAILED')); + } + + // Get the help data from the XML file if present. + $help = $xml->xpath('/extension/help'); + + if (!empty($help)) { + $helpKey = trim((string) $help[0]['key']); + $helpURL = trim((string) $help[0]['url']); + + $this->helpKey = $helpKey ?: $this->helpKey; + $this->helpURL = $helpURL ?: $this->helpURL; + } + } + + // Load the default advanced params + Form::addFormPath(JPATH_ADMINISTRATOR . '/components/com_modules/models/forms'); + $form->loadFile('advanced', false); + + // Load chrome specific params for global files + $chromePath = JPATH_SITE . '/layouts/chromes'; + $chromeFormFiles = Folder::files($chromePath, '.*\.xml'); + + if ($chromeFormFiles) { + Form::addFormPath($chromePath); + + foreach ($chromeFormFiles as $formFile) { + $form->loadFile(basename($formFile, '.xml'), false); + } + } + + // Load chrome specific params for template files + $templates = ModulesHelper::getTemplates($clientId); + + foreach ($templates as $template) { + $chromePath = $client->path . '/templates/' . $template->element . '/html/layouts/chromes'; + + // Skip if there is no chrome folder in that template. + if (!is_dir($chromePath)) { + continue; + } + + $chromeFormFiles = Folder::files($chromePath, '.*\.xml'); + + if ($chromeFormFiles) { + Form::addFormPath($chromePath); + + foreach ($chromeFormFiles as $formFile) { + $form->loadFile(basename($formFile, '.xml'), false); + } + } + } + + if (ComponentHelper::getParams('com_modules')->get('workflow_enabled')) { + Factory::getLanguage()->load('com_workflow', JPATH_ADMINISTRATOR); + + /** + * The workflowPreprocessForm function enables the workflow plugins and adds the + * transition field to the form. We do not need to add the transition field to the + * form in the case of items so we separately call the importWorkflowPlugins function. + */ + if (!empty(Factory::getApplication()->input->get('id'))) { + $this->workflowPreprocessForm($form, $data); + } else { + // Import the workflow plugin group to allow form manipulation. + $this->importWorkflowPlugins(); + $this->prepareWorkflowField($form, $data); + } + } + + // Trigger the default form events. + parent::preprocessForm($form, $data, $group); + } + + /** + * Loads ContentHelper for filters before validating data. + * + * @param object $form The form to validate against. + * @param array $data The data to validate. + * @param string $group The name of the group(defaults to null). + * + * @return mixed Array of filtered data if valid, false otherwise. + * + * @since 1.1 + */ + public function validate($form, $data, $group = null) + { + if (!Factory::getUser()->authorise('core.admin', 'com_modules')) { + if (isset($data['rules'])) { + unset($data['rules']); + } + } + + return parent::validate($form, $data, $group); + } + + /** + * Method to save the form data. + * + * @param array $data The form data. + * + * @return boolean True on success. + * + * @since 1.6 + */ + public function save($data) + { + $input = Factory::getApplication()->input; + $table = $this->getTable(); + $pk = (!empty($data['id'])) ? $data['id'] : (int) $this->getState('module.id'); + $isNew = true; + $context = $this->option . '.' . $this->name; + + // Include the plugins for the save event. + PluginHelper::importPlugin($this->events_map['save']); + + // Load the row if saving an existing record. + if ($pk > 0) { + $table->load($pk); + $isNew = false; + } + + // Alter the title and published state for Save as Copy + if ($input->get('task') == 'save2copy') { + $orig_table = clone $this->getTable(); + $orig_table->load((int) $input->getInt('id')); + $data['published'] = 0; + + if ($data['title'] == $orig_table->title) { + $data['title'] = StringHelper::increment($data['title']); + } + } + + // Bind the data. + if (!$table->bind($data)) { + $this->setError($table->getError()); + + return false; + } + + // Prepare the row for saving + $this->prepareTable($table); + + // Check the data. + if (!$table->check()) { + $this->setError($table->getError()); + + return false; + } + + // Trigger the before save event. + $result = Factory::getApplication()->triggerEvent($this->event_before_save, array($context, &$table, $isNew)); + + if (in_array(false, $result, true)) { + $this->setError($table->getError()); + + return false; + } + + // Store the data. + if (!$table->store()) { + $this->setError($table->getError()); + + return false; + } + + $this->workflowBeforeSave(); + + // Process the menu link mappings. + $assignment = $data['assignment'] ?? 0; + + $table->id = (int) $table->id; + + // Delete old module to menu item associations + $db = $this->getDatabase(); + $query = $db->getQuery(true) + ->delete($db->quoteName('#__modules_menu')) + ->where($db->quoteName('moduleid') . ' = :moduleid') + ->bind(':moduleid', $table->id, ParameterType::INTEGER); + $db->setQuery($query); + + try { + $db->execute(); + } catch (\RuntimeException $e) { + $this->setError($e->getMessage()); + + return false; + } + + // If the assignment is numeric, then something is selected (otherwise it's none). + if (is_numeric($assignment)) { + // Variable is numeric, but could be a string. + $assignment = (int) $assignment; + + // Logic check: if no module excluded then convert to display on all. + if ($assignment == -1 && empty($data['assigned'])) { + $assignment = 0; + } + + // Check needed to stop a module being assigned to `All` + // and other menu items resulting in a module being displayed twice. + if ($assignment === 0) { + // Assign new module to `all` menu item associations. + $query->clear() + ->insert($db->quoteName('#__modules_menu')) + ->columns($db->quoteName(['moduleid', 'menuid'])) + ->values(implode(', ', [':moduleid', 0])) + ->bind(':moduleid', $table->id, ParameterType::INTEGER); + $db->setQuery($query); + + try { + $db->execute(); + } catch (\RuntimeException $e) { + $this->setError($e->getMessage()); + + return false; + } + } elseif (!empty($data['assigned'])) { + // Get the sign of the number. + $sign = $assignment < 0 ? -1 : 1; + + $query->clear() + ->insert($db->quoteName('#__modules_menu')) + ->columns($db->quoteName(array('moduleid', 'menuid'))); + + foreach ($data['assigned'] as &$pk) { + $query->values((int) $table->id . ',' . (int) $pk * $sign); + } + + $db->setQuery($query); + + try { + $db->execute(); + } catch (\RuntimeException $e) { + $this->setError($e->getMessage()); + + return false; + } + } + } + + // Trigger the after save event. + Factory::getApplication()->triggerEvent($this->event_after_save, array($context, &$table, $isNew)); + + // Compute the extension id of this module in case the controller wants it. + $query->clear() + ->select($db->quoteName('extension_id')) + ->from($db->quoteName('#__extensions', 'e')) + ->join( + 'LEFT', + $db->quoteName('#__modules', 'm') . ' ON ' . $db->quoteName('e.client_id') . ' = ' . (int) $table->client_id . + ' AND ' . $db->quoteName('e.element') . ' = ' . $db->quoteName('m.module') + ) + ->where($db->quoteName('m.id') . ' = :id') + ->bind(':id', $table->id, ParameterType::INTEGER); + $db->setQuery($query); + + try { + $extensionId = $db->loadResult(); + } catch (\RuntimeException $e) { + Factory::getApplication()->enqueueMessage($e->getMessage(), 'error'); + + return false; + } + + $this->setState('module.extension_id', $extensionId); + $this->setState('module.id', $table->id); + $this->setState('module.new', $isNew); + + $this->workflowAfterSave($data); + + // Clear modules cache + $this->cleanCache(); + + // Clean module cache + parent::cleanCache($table->module); + + return true; + } + + /** + * 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 1.6 + */ + protected function getReorderConditions($table) + { + $db = $this->getDatabase(); + + return [ + $db->quoteName('client_id') . ' = ' . (int) $table->client_id, + $db->quoteName('position') . ' = ' . $db->quote($table->position), + ]; + } + + /** + * Custom clean cache method for different clients + * + * @param string $group The name of the plugin group to import (defaults to null). + * @param integer $clientId @deprecated 5.0 No longer used. + * + * @return void + * + * @since 1.6 + */ + protected function cleanCache($group = null, $clientId = 0) + { + parent::cleanCache('com_modules'); + } + + /** + * 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 __DEPLOY_VERSION__ + */ + public function publish(&$pks, $value = 1) + { + $this->workflowBeforeStageChange(); + + return parent::publish($pks, $value); + } + + /** + * Overrides the function in WorkflowBehaviorTrait to get the default + * stage ID while creating a new module. + * + * @param Form $form A Form object. + * @param mixed $data The data expected for the form. + * + * @return boolean|integer An integer, holding the stage ID or false + * + * @since __DEPLOY_VERSION__ + */ + protected function getStageForNewItem(Form $form, $data) + { + $db = $this->getDbo(); + + $query = $db->getQuery(true) + ->select($db->quoteName('id')) + ->from($db->quoteName('#__workflow_stages')) + ->where($db->quoteName('default') . '= 1'); + + if (isset($data['workflow_id'])) { + // If workflow_id is set by the query then we find the stage corresponding to that workflow_id + $query->where($db->quoteName('workflow_id') . ' = :workflowid') + ->bind(':workflowid', $data['workflow_id'], ParameterType::INTEGER); + } else { + // Query to find the default workflow id of the extension type com_modules.module + $defaultWorkflowQuery = $db->getQuery(true) + ->select($db->quoteName('id')) + ->from($db->quoteName('#__workflows')) + ->where($db->quoteName('default') . ' = 1') + ->where($db->quoteName('extension') . ' = ' . $db->quote('com_modules.module')); + + $query->where($db->quoteName('workflow_id') . ' IN (' . $defaultWorkflowQuery . ')'); + } + + $db->setQuery($query); + $defaultStage = $db->loadResult(); + + if (empty($defaultStage)) { + return false; + } + + return $defaultStage; + } + + /** + * Adds default stage to workflow field in the form. + * + * @param Form $form The form to change + * @param array|object $data The form data + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public static function prepareWorkflowField(Form $form, $data) + { + $db = Factory::getDbo(); + + $data = (array) $data; + + $form->setFieldAttribute('workflow_id', 'default', 'inherit'); + + $query = $db->getQuery(true); + + $query->select([$db->quoteName('title'), $db->quoteName('id')]) + ->from($db->quoteName('#__workflows')) + ->where( + [ + $db->quoteName('default') . ' = 1', + $db->quoteName('published') . ' = 1', + $db->quoteName('extension') . ' = ' . $db->quote('com_modules.module'), + ] + ); + + $defaultWorkflow = $db->setQuery($query)->loadObject(); + $field = $form->getField('workflow_id'); + + $field->addOption(Text::sprintf('COM_WORKFLOW_USE_DEFAULT_WORKFLOW', Text::_($defaultWorkflow->title)), ['value' => $defaultWorkflow->id]); + + $field->addOption('- ' . Text::_('COM_MODULES_WORKFLOWS') . ' -', ['disabled' => 'true']); + } } diff --git a/administrator/components/com_modules/src/Model/ModulesModel.php b/administrator/components/com_modules/src/Model/ModulesModel.php index c2fd9358f936a..b3877a96269d2 100644 --- a/administrator/components/com_modules/src/Model/ModulesModel.php +++ b/administrator/components/com_modules/src/Model/ModulesModel.php @@ -1,4 +1,5 @@ input->get('layout', '', 'cmd'); - - // Adjust the context to support modal layouts. - if ($layout) - { - $this->context .= '.' . $layout; - } - - // Make context client aware - $this->context .= '.' . $app->input->get->getInt('client_id', 0); - - // Load the filter state. - $this->setState('filter.search', $this->getUserStateFromRequest($this->context . '.filter.search', 'filter_search', '', 'string')); - $this->setState('filter.position', $this->getUserStateFromRequest($this->context . '.filter.position', 'filter_position', '', 'string')); - $this->setState('filter.module', $this->getUserStateFromRequest($this->context . '.filter.module', 'filter_module', '', 'string')); - $this->setState('filter.menuitem', $this->getUserStateFromRequest($this->context . '.filter.menuitem', 'filter_menuitem', '', 'cmd')); - $this->setState('filter.access', $this->getUserStateFromRequest($this->context . '.filter.access', 'filter_access', '', 'cmd')); - - // If in modal layout on the frontend, state and language are always forced. - if ($app->isClient('site') && $layout === 'modal') - { - $this->setState('filter.language', 'current'); - $this->setState('filter.state', 1); - } - // If in backend (modal or not) we get the same fields from the user request. - else - { - $this->setState('filter.language', $this->getUserStateFromRequest($this->context . '.filter.language', 'filter_language', '', 'string')); - $this->setState('filter.state', $this->getUserStateFromRequest($this->context . '.filter.state', 'filter_state', '', 'string')); - } - - // Special case for the client id. - if ($app->isClient('site') || $layout === 'modal') - { - $this->setState('client_id', 0); - $clientId = 0; - } - else - { - $clientId = (int) $this->getUserStateFromRequest($this->context . '.client_id', 'client_id', 0, 'int'); - $clientId = (!in_array($clientId, array(0, 1))) ? 0 : $clientId; - $this->setState('client_id', $clientId); - } - - // Use a different filter file when client is administrator - if ($clientId == 1) - { - $this->filterFormName = 'filter_modulesadmin'; - } - - // Load the parameters. - $params = ComponentHelper::getParams('com_modules'); - $this->setState('params', $params); - - // List state information. - parent::populateState($ordering, $direction); - } - - /** - * Method to get a store id based on model configuration state. - * - * This is necessary because the model is used by the component and - * different modules that might need different sets of data or different - * ordering requirements. - * - * @param string $id A prefix for the store id. - * - * @return string A store id. - */ - protected function getStoreId($id = '') - { - // Compile the store id. - $id .= ':' . $this->getState('client_id'); - $id .= ':' . $this->getState('filter.search'); - $id .= ':' . $this->getState('filter.state'); - $id .= ':' . $this->getState('filter.position'); - $id .= ':' . $this->getState('filter.module'); - $id .= ':' . $this->getState('filter.menuitem'); - $id .= ':' . $this->getState('filter.access'); - $id .= ':' . $this->getState('filter.language'); - - return parent::getStoreId($id); - } - - /** - * Returns an object list - * - * @param DatabaseQuery $query The query - * @param int $limitstart Offset - * @param int $limit The number of records - * - * @return array - */ - protected function _getList($query, $limitstart = 0, $limit = 0) - { - $listOrder = $this->getState('list.ordering', 'a.position'); - $listDirn = $this->getState('list.direction', 'asc'); - - $db = $this->getDatabase(); - - // If ordering by fields that need translate we need to sort the array of objects after translating them. - if (in_array($listOrder, array('pages', 'name'))) - { - // Fetch the results. - $db->setQuery($query); - $result = $db->loadObjectList(); - - // Translate the results. - $this->translate($result); - - // Sort the array of translated objects. - $result = ArrayHelper::sortObjects($result, $listOrder, strtolower($listDirn) == 'desc' ? -1 : 1, true, true); - - // Process pagination. - $total = count($result); - $this->cache[$this->getStoreId('getTotal')] = $total; - - if ($total < $limitstart) - { - $limitstart = 0; - $this->setState('list.start', 0); - } - - return array_slice($result, $limitstart, $limit ?: null); - } - - // If ordering by fields that doesn't need translate just order the query. - if ($listOrder === 'a.ordering') - { - $query->order($db->quoteName('a.position') . ' ASC') - ->order($db->quoteName($listOrder) . ' ' . $db->escape($listDirn)); - } - elseif ($listOrder === 'a.position') - { - $query->order($db->quoteName($listOrder) . ' ' . $db->escape($listDirn)) - ->order($db->quoteName('a.ordering') . ' ASC'); - } - else - { - $query->order($db->quoteName($listOrder) . ' ' . $db->escape($listDirn)); - } - - // Process pagination. - $result = parent::_getList($query, $limitstart, $limit); - - // Translate the results. - $this->translate($result); - - return $result; - } - - /** - * Get the filter form - * - * @param array $data data - * @param boolean $loadData load current data - * - * @return Form|null The \JForm object or null if the form can't be found - * - * @since __DEPLOY_VERSION__ - */ - public function getFilterForm($data = array(), $loadData = true) - { - $form = parent::getFilterForm($data, $loadData); - - $params = ComponentHelper::getParams('com_modules'); - - if (!$params->get('workflow_enabled')) - { - $form->removeField('stage', 'filter'); - } - else - { - $ordering = $form->getField('fullordering', 'list'); - - $ordering->addOption('JSTAGE_ASC', ['value' => 'ws.title ASC']); - $ordering->addOption('JSTAGE_DESC', ['value' => 'ws.title DESC']); - } - - return $form; - } - - /** - * Translate a list of objects - * - * @param array &$items The array of objects - * - * @return array The array of translated objects - */ - protected function translate(&$items) - { - $lang = Factory::getLanguage(); - $clientPath = $this->getState('client_id') ? JPATH_ADMINISTRATOR : JPATH_SITE; - - foreach ($items as $item) - { - $extension = $item->module; - $source = $clientPath . "/modules/$extension"; - $lang->load("$extension.sys", $clientPath) - || $lang->load("$extension.sys", $source); - $item->name = Text::_($item->name); - - if (is_null($item->pages)) - { - $item->pages = Text::_('JNONE'); - } - elseif ($item->pages < 0) - { - $item->pages = Text::_('COM_MODULES_ASSIGNED_VARIES_EXCEPT'); - } - elseif ($item->pages > 0) - { - $item->pages = Text::_('COM_MODULES_ASSIGNED_VARIES_ONLY'); - } - else - { - $item->pages = Text::_('JALL'); - } - } - } - - /** - * Build an SQL query to load the list data. - * - * @return DatabaseQuery - */ - protected function getListQuery() - { - // Create a new query object. - $db = $this->getDatabase(); - $query = $db->getQuery(true); - $params = ComponentHelper::getParams('com_modules'); - - // Select the required fields. - $query->select( - $this->getState( - 'list.select', - 'a.id, a.title, a.note, a.position, a.module, a.language,' . - 'a.checked_out, a.checked_out_time, a.published AS published, e.enabled AS enabled, a.access, a.ordering, a.publish_up, a.publish_down' - ) - ); - - // From modules table. - $query->from($db->quoteName('#__modules', 'a')); - - // Join over the language - $query->select($db->quoteName('l.title', 'language_title')) - ->select($db->quoteName('l.image', 'language_image')) - ->join('LEFT', $db->quoteName('#__languages', 'l') . ' ON ' . $db->quoteName('l.lang_code') . ' = ' . $db->quoteName('a.language')); - - // Join over the users for the checked out user. - $query->select($db->quoteName('uc.name', 'editor')) - ->join('LEFT', $db->quoteName('#__users', 'uc') . ' ON ' . $db->quoteName('uc.id') . ' = ' . $db->quoteName('a.checked_out')); - - // Join over the asset groups. - $query->select($db->quoteName('ag.title', 'access_level')) - ->join('LEFT', $db->quoteName('#__viewlevels', 'ag') . ' ON ' . $db->quoteName('ag.id') . ' = ' . $db->quoteName('a.access')); - - // Join over the module menus - $query->select('MIN(mm.menuid) AS pages') - ->join('LEFT', $db->quoteName('#__modules_menu', 'mm') . ' ON ' . $db->quoteName('mm.moduleid') . ' = ' . $db->quoteName('a.id')); - - // Join over the extensions - $query->select($db->quoteName('e.name', 'name')) - ->join('LEFT', $db->quoteName('#__extensions', 'e') . ' ON ' . $db->quoteName('e.element') . ' = ' . $db->quoteName('a.module')); - - // Join over the workflows association - $query->select($db->quoteName('wa.stage_id', 'stage_id')) - ->join('INNER', $db->quoteName('#__workflow_associations', 'wa'), $db->quoteName('wa.item_id') . ' = ' . $db->quoteName('a.id')) - ->where($db->quoteName('wa.extension') . ' = ' . $db->quote('com_modules.module')); - - // Join over the workflows stage - $query->select( - [ - $db->quoteName('ws.title', 'stage_title'), - $db->quoteName('ws.workflow_id', 'workflow_id') - ] - ) - ->join('INNER', $db->quoteName('#__workflow_stages', 'ws'), $db->quoteName('ws.id') . ' = ' . $db->quoteName('wa.stage_id')); - - // Join over the workflows - $query->select($db->quoteName('w.title', 'workflow_title')) - ->join('INNER', $db->quoteName('#__workflows', 'w'), $db->quoteName('w.id') . ' = ' . $db->quoteName('ws.workflow_id')); - - // Group (careful with PostgreSQL) - $query->group( - 'a.id, a.title, a.note, a.position, a.module, a.language, a.checked_out, ' - . 'a.checked_out_time, a.published, a.access, a.ordering, l.title, l.image, uc.name, ag.title, e.name, ' - . 'l.lang_code, uc.id, ag.id, mm.moduleid, e.element, a.publish_up, a.publish_down, e.enabled' - ); - - // Filter by client. - $clientId = (int) $this->getState('client_id'); - $query->where($db->quoteName('a.client_id') . ' = :aclientid') - ->where($db->quoteName('e.client_id') . ' = :eclientid') - ->bind(':aclientid', $clientId, ParameterType::INTEGER) - ->bind(':eclientid', $clientId, ParameterType::INTEGER); - - // Filter by current user access level. - $user = Factory::getUser(); - - // Get the current user for authorisation checks - if ($user->authorise('core.admin') !== true) - { - $groups = $user->getAuthorisedViewLevels(); - $query->whereIn($db->quoteName('a.access'), $groups); - } - - // Filter by access level. - if ($access = $this->getState('filter.access')) - { - $access = (int) $access; - $query->where($db->quoteName('a.access') . ' = :access') - ->bind(':access', $access, ParameterType::INTEGER); - } - - // Filter by stage - $workflowStage = (string) $this->getState('filter.stage'); - - if ($params->get('workflow_enabled') && is_numeric($workflowStage)) - { - $workflowStage = (int) $workflowStage; - $query->where($db->quoteName('wa.stage_id') . ' = :stage') - ->bind(':stage', $workflowStage, ParameterType::INTEGER); - } - - // Filter by published state. - $state = $this->getState('filter.state'); - - if (is_numeric($state)) - { - $state = (int) $state; - $query->where($db->quoteName('a.published') . ' = :state') - ->bind(':state', $state, ParameterType::INTEGER); - } - elseif (!is_numeric($workflowStage)) - { - $query->whereIn($db->quoteName('a.published'), [0, 1]); - } - - // Filter by position. - if ($position = $this->getState('filter.position')) - { - $position = ($position === 'none') ? '' : $position; - $query->where($db->quoteName('a.position') . ' = :position') - ->bind(':position', $position); - } - - // Filter by module. - if ($module = $this->getState('filter.module')) - { - $query->where($db->quoteName('a.module') . ' = :module') - ->bind(':module', $module); - } - - // Filter by menuitem id (only for site client). - if ((int) $clientId === 0 && $menuItemId = $this->getState('filter.menuitem')) - { - // If user selected the modules not assigned to any page (menu item). - if ((int) $menuItemId === -1) - { - $query->having('MIN(' . $db->quoteName('mm.menuid') . ') IS NULL'); - } - // If user selected the modules assigned to some particular page (menu item). - else - { - // Modules in "All" pages. - $subQuery1 = $db->getQuery(true); - $subQuery1->select('MIN(' . $db->quoteName('menuid') . ')') - ->from($db->quoteName('#__modules_menu')) - ->where($db->quoteName('moduleid') . ' = ' . $db->quoteName('a.id')); - - // Modules in "Selected" pages that have the chosen menu item id. - $menuItemId = (int) $menuItemId; - $minusMenuItemId = $menuItemId * -1; - $subQuery2 = $db->getQuery(true); - $subQuery2->select($db->quoteName('moduleid')) - ->from($db->quoteName('#__modules_menu')) - ->where($db->quoteName('menuid') . ' = :menuitemid2'); - - // Modules in "All except selected" pages that doesn't have the chosen menu item id. - $subQuery3 = $db->getQuery(true); - $subQuery3->select($db->quoteName('moduleid')) - ->from($db->quoteName('#__modules_menu')) - ->where($db->quoteName('menuid') . ' = :menuitemid3'); - - // Filter by modules assigned to the selected menu item. - $query->where('( + /** + * Constructor. + * + * @param array $config An optional associative array of configuration settings. + * + * @see \JController + * @since 1.6 + */ + public function __construct($config = array()) + { + if (empty($config['filter_fields'])) { + $config['filter_fields'] = array( + 'id', 'a.id', + 'title', 'a.title', + 'checked_out', 'a.checked_out', + 'checked_out_time', 'a.checked_out_time', + 'published', 'a.published', 'state', + 'access', 'a.access', + 'ag.title', 'access_level', + 'ordering', 'a.ordering', + 'module', 'a.module', + 'language', 'a.language', + 'l.title', 'language_title', + 'publish_up', 'a.publish_up', + 'publish_down', 'a.publish_down', + 'client_id', 'a.client_id', + 'position', 'a.position', + 'pages', + 'name', 'e.name', + 'menuitem', + ); + } + + parent::__construct($config); + } + + /** + * Method to auto-populate the model state. + * + * 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 1.6 + */ + protected function populateState($ordering = 'a.position', $direction = 'asc') + { + $app = Factory::getApplication(); + + $layout = $app->input->get('layout', '', 'cmd'); + + // Adjust the context to support modal layouts. + if ($layout) { + $this->context .= '.' . $layout; + } + + // Make context client aware + $this->context .= '.' . $app->input->get->getInt('client_id', 0); + + // Load the filter state. + $this->setState('filter.search', $this->getUserStateFromRequest($this->context . '.filter.search', 'filter_search', '', 'string')); + $this->setState('filter.position', $this->getUserStateFromRequest($this->context . '.filter.position', 'filter_position', '', 'string')); + $this->setState('filter.module', $this->getUserStateFromRequest($this->context . '.filter.module', 'filter_module', '', 'string')); + $this->setState('filter.menuitem', $this->getUserStateFromRequest($this->context . '.filter.menuitem', 'filter_menuitem', '', 'cmd')); + $this->setState('filter.access', $this->getUserStateFromRequest($this->context . '.filter.access', 'filter_access', '', 'cmd')); + + // If in modal layout on the frontend, state and language are always forced. + if ($app->isClient('site') && $layout === 'modal') { + $this->setState('filter.language', 'current'); + $this->setState('filter.state', 1); + } + // If in backend (modal or not) we get the same fields from the user request. + else { + $this->setState('filter.language', $this->getUserStateFromRequest($this->context . '.filter.language', 'filter_language', '', 'string')); + $this->setState('filter.state', $this->getUserStateFromRequest($this->context . '.filter.state', 'filter_state', '', 'string')); + } + + // Special case for the client id. + if ($app->isClient('site') || $layout === 'modal') { + $this->setState('client_id', 0); + $clientId = 0; + } else { + $clientId = (int) $this->getUserStateFromRequest($this->context . '.client_id', 'client_id', 0, 'int'); + $clientId = (!in_array($clientId, array(0, 1))) ? 0 : $clientId; + $this->setState('client_id', $clientId); + } + + // Use a different filter file when client is administrator + if ($clientId == 1) { + $this->filterFormName = 'filter_modulesadmin'; + } + + // Load the parameters. + $params = ComponentHelper::getParams('com_modules'); + $this->setState('params', $params); + + // List state information. + parent::populateState($ordering, $direction); + } + + /** + * Method to get a store id based on model configuration state. + * + * This is necessary because the model is used by the component and + * different modules that might need different sets of data or different + * ordering requirements. + * + * @param string $id A prefix for the store id. + * + * @return string A store id. + */ + protected function getStoreId($id = '') + { + // Compile the store id. + $id .= ':' . $this->getState('client_id'); + $id .= ':' . $this->getState('filter.search'); + $id .= ':' . $this->getState('filter.state'); + $id .= ':' . $this->getState('filter.position'); + $id .= ':' . $this->getState('filter.module'); + $id .= ':' . $this->getState('filter.menuitem'); + $id .= ':' . $this->getState('filter.access'); + $id .= ':' . $this->getState('filter.language'); + + return parent::getStoreId($id); + } + + /** + * Returns an object list + * + * @param DatabaseQuery $query The query + * @param int $limitstart Offset + * @param int $limit The number of records + * + * @return array + */ + protected function _getList($query, $limitstart = 0, $limit = 0) + { + $listOrder = $this->getState('list.ordering', 'a.position'); + $listDirn = $this->getState('list.direction', 'asc'); + + $db = $this->getDatabase(); + + // If ordering by fields that need translate we need to sort the array of objects after translating them. + if (in_array($listOrder, array('pages', 'name'))) { + // Fetch the results. + $db->setQuery($query); + $result = $db->loadObjectList(); + + // Translate the results. + $this->translate($result); + + // Sort the array of translated objects. + $result = ArrayHelper::sortObjects($result, $listOrder, strtolower($listDirn) == 'desc' ? -1 : 1, true, true); + + // Process pagination. + $total = count($result); + $this->cache[$this->getStoreId('getTotal')] = $total; + + if ($total < $limitstart) { + $limitstart = 0; + $this->setState('list.start', 0); + } + + return array_slice($result, $limitstart, $limit ?: null); + } + + // If ordering by fields that doesn't need translate just order the query. + if ($listOrder === 'a.ordering') { + $query->order($db->quoteName('a.position') . ' ASC') + ->order($db->quoteName($listOrder) . ' ' . $db->escape($listDirn)); + } elseif ($listOrder === 'a.position') { + $query->order($db->quoteName($listOrder) . ' ' . $db->escape($listDirn)) + ->order($db->quoteName('a.ordering') . ' ASC'); + } else { + $query->order($db->quoteName($listOrder) . ' ' . $db->escape($listDirn)); + } + + // Process pagination. + $result = parent::_getList($query, $limitstart, $limit); + + // Translate the results. + $this->translate($result); + + return $result; + } + + /** + * Get the filter form + * + * @param array $data data + * @param boolean $loadData load current data + * + * @return Form|null The \JForm object or null if the form can't be found + * + * @since __DEPLOY_VERSION__ + */ + public function getFilterForm($data = array(), $loadData = true) + { + $form = parent::getFilterForm($data, $loadData); + + $params = ComponentHelper::getParams('com_modules'); + + if (!$params->get('workflow_enabled')) { + $form->removeField('stage', 'filter'); + } else { + $ordering = $form->getField('fullordering', 'list'); + + $ordering->addOption('JSTAGE_ASC', ['value' => 'ws.title ASC']); + $ordering->addOption('JSTAGE_DESC', ['value' => 'ws.title DESC']); + } + + return $form; + } + + /** + * Translate a list of objects + * + * @param array &$items The array of objects + * + * @return array The array of translated objects + */ + protected function translate(&$items) + { + $lang = Factory::getLanguage(); + $clientPath = $this->getState('client_id') ? JPATH_ADMINISTRATOR : JPATH_SITE; + + foreach ($items as $item) { + $extension = $item->module; + $source = $clientPath . "/modules/$extension"; + $lang->load("$extension.sys", $clientPath) + || $lang->load("$extension.sys", $source); + $item->name = Text::_($item->name); + + if (is_null($item->pages)) { + $item->pages = Text::_('JNONE'); + } elseif ($item->pages < 0) { + $item->pages = Text::_('COM_MODULES_ASSIGNED_VARIES_EXCEPT'); + } elseif ($item->pages > 0) { + $item->pages = Text::_('COM_MODULES_ASSIGNED_VARIES_ONLY'); + } else { + $item->pages = Text::_('JALL'); + } + } + } + + /** + * Build an SQL query to load the list data. + * + * @return DatabaseQuery + */ + protected function getListQuery() + { + // Create a new query object. + $db = $this->getDatabase(); + $query = $db->getQuery(true); + $params = ComponentHelper::getParams('com_modules'); + + // Select the required fields. + $query->select( + $this->getState( + 'list.select', + 'a.id, a.title, a.note, a.position, a.module, a.language,' . + 'a.checked_out, a.checked_out_time, a.published AS published, e.enabled AS enabled, a.access, a.ordering, a.publish_up, a.publish_down' + ) + ); + + // From modules table. + $query->from($db->quoteName('#__modules', 'a')); + + // Join over the language + $query->select($db->quoteName('l.title', 'language_title')) + ->select($db->quoteName('l.image', 'language_image')) + ->join('LEFT', $db->quoteName('#__languages', 'l') . ' ON ' . $db->quoteName('l.lang_code') . ' = ' . $db->quoteName('a.language')); + + // Join over the users for the checked out user. + $query->select($db->quoteName('uc.name', 'editor')) + ->join('LEFT', $db->quoteName('#__users', 'uc') . ' ON ' . $db->quoteName('uc.id') . ' = ' . $db->quoteName('a.checked_out')); + + // Join over the asset groups. + $query->select($db->quoteName('ag.title', 'access_level')) + ->join('LEFT', $db->quoteName('#__viewlevels', 'ag') . ' ON ' . $db->quoteName('ag.id') . ' = ' . $db->quoteName('a.access')); + + // Join over the module menus + $query->select('MIN(mm.menuid) AS pages') + ->join('LEFT', $db->quoteName('#__modules_menu', 'mm') . ' ON ' . $db->quoteName('mm.moduleid') . ' = ' . $db->quoteName('a.id')); + + // Join over the extensions + $query->select($db->quoteName('e.name', 'name')) + ->join('LEFT', $db->quoteName('#__extensions', 'e') . ' ON ' . $db->quoteName('e.element') . ' = ' . $db->quoteName('a.module')); + + // Join over the workflows association + $query->select($db->quoteName('wa.stage_id', 'stage_id')) + ->join('INNER', $db->quoteName('#__workflow_associations', 'wa'), $db->quoteName('wa.item_id') . ' = ' . $db->quoteName('a.id')) + ->where($db->quoteName('wa.extension') . ' = ' . $db->quote('com_modules.module')); + + // Join over the workflows stage + $query->select( + [ + $db->quoteName('ws.title', 'stage_title'), + $db->quoteName('ws.workflow_id', 'workflow_id') + ] + ) + ->join('INNER', $db->quoteName('#__workflow_stages', 'ws'), $db->quoteName('ws.id') . ' = ' . $db->quoteName('wa.stage_id')); + + // Join over the workflows + $query->select($db->quoteName('w.title', 'workflow_title')) + ->join('INNER', $db->quoteName('#__workflows', 'w'), $db->quoteName('w.id') . ' = ' . $db->quoteName('ws.workflow_id')); + + // Group (careful with PostgreSQL) + $query->group( + 'a.id, a.title, a.note, a.position, a.module, a.language, a.checked_out, ' + . 'a.checked_out_time, a.published, a.access, a.ordering, l.title, l.image, uc.name, ag.title, e.name, ' + . 'l.lang_code, uc.id, ag.id, mm.moduleid, e.element, a.publish_up, a.publish_down, e.enabled' + ); + + // Filter by client. + $clientId = (int) $this->getState('client_id'); + $query->where($db->quoteName('a.client_id') . ' = :aclientid') + ->where($db->quoteName('e.client_id') . ' = :eclientid') + ->bind(':aclientid', $clientId, ParameterType::INTEGER) + ->bind(':eclientid', $clientId, ParameterType::INTEGER); + + // Filter by current user access level. + $user = Factory::getUser(); + + // Get the current user for authorisation checks + if ($user->authorise('core.admin') !== true) { + $groups = $user->getAuthorisedViewLevels(); + $query->whereIn($db->quoteName('a.access'), $groups); + } + + // Filter by access level. + if ($access = $this->getState('filter.access')) { + $access = (int) $access; + $query->where($db->quoteName('a.access') . ' = :access') + ->bind(':access', $access, ParameterType::INTEGER); + } + + // Filter by stage + $workflowStage = (string) $this->getState('filter.stage'); + + if ($params->get('workflow_enabled') && is_numeric($workflowStage)) { + $workflowStage = (int) $workflowStage; + $query->where($db->quoteName('wa.stage_id') . ' = :stage') + ->bind(':stage', $workflowStage, ParameterType::INTEGER); + } + + // Filter by published state. + $state = $this->getState('filter.state'); + + if (is_numeric($state)) { + $state = (int) $state; + $query->where($db->quoteName('a.published') . ' = :state') + ->bind(':state', $state, ParameterType::INTEGER); + } elseif (!is_numeric($workflowStage)) { + $query->whereIn($db->quoteName('a.published'), [0, 1]); + } + + // Filter by position. + if ($position = $this->getState('filter.position')) { + $position = ($position === 'none') ? '' : $position; + $query->where($db->quoteName('a.position') . ' = :position') + ->bind(':position', $position); + } + + // Filter by module. + if ($module = $this->getState('filter.module')) { + $query->where($db->quoteName('a.module') . ' = :module') + ->bind(':module', $module); + } + + // Filter by menuitem id (only for site client). + if ((int) $clientId === 0 && $menuItemId = $this->getState('filter.menuitem')) { + // If user selected the modules not assigned to any page (menu item). + if ((int) $menuItemId === -1) { + $query->having('MIN(' . $db->quoteName('mm.menuid') . ') IS NULL'); + } + // If user selected the modules assigned to some particular page (menu item). + else { + // Modules in "All" pages. + $subQuery1 = $db->getQuery(true); + $subQuery1->select('MIN(' . $db->quoteName('menuid') . ')') + ->from($db->quoteName('#__modules_menu')) + ->where($db->quoteName('moduleid') . ' = ' . $db->quoteName('a.id')); + + // Modules in "Selected" pages that have the chosen menu item id. + $menuItemId = (int) $menuItemId; + $minusMenuItemId = $menuItemId * -1; + $subQuery2 = $db->getQuery(true); + $subQuery2->select($db->quoteName('moduleid')) + ->from($db->quoteName('#__modules_menu')) + ->where($db->quoteName('menuid') . ' = :menuitemid2'); + + // Modules in "All except selected" pages that doesn't have the chosen menu item id. + $subQuery3 = $db->getQuery(true); + $subQuery3->select($db->quoteName('moduleid')) + ->from($db->quoteName('#__modules_menu')) + ->where($db->quoteName('menuid') . ' = :menuitemid3'); + + // Filter by modules assigned to the selected menu item. + $query->where('( (' . $subQuery1 . ') = 0 OR ((' . $subQuery1 . ') > 0 AND ' . $db->quoteName('a.id') . ' IN (' . $subQuery2 . ')) OR ((' . $subQuery1 . ') < 0 AND ' . $db->quoteName('a.id') . ' NOT IN (' . $subQuery3 . ')) - )' - ); - $query->bind(':menuitemid2', $menuItemId, ParameterType::INTEGER); - $query->bind(':menuitemid3', $minusMenuItemId, ParameterType::INTEGER); - } - } - - // Filter by search in title or note or id:. - $search = $this->getState('filter.search'); - - if (!empty($search)) - { - if (stripos($search, 'id:') === 0) - { - $ids = (int) substr($search, 3); - $query->where($db->quoteName('a.id') . ' = :id') - ->bind(':id', $ids, ParameterType::INTEGER); - } - else - { - $search = '%' . StringHelper::strtolower($search) . '%'; - $query->extendWhere( - 'AND', - [ - 'LOWER(' . $db->quoteName('a.title') . ') LIKE :title', - 'LOWER(' . $db->quoteName('a.note') . ') LIKE :note', - ], - 'OR' - ) - ->bind(':title', $search) - ->bind(':note', $search); - } - } - - // Filter on the language. - if ($language = $this->getState('filter.language')) - { - if ($language === 'current') - { - $language = [Factory::getLanguage()->getTag(), '*']; - $query->whereIn($db->quoteName('a.language'), $language, ParameterType::STRING); - } - else - { - $query->where($db->quoteName('a.language') . ' = :language') - ->bind(':language', $language); - } - } - - return $query; - } - - /** - * Method to get all transitions at once for all modules - * - * @return array|boolean - * - * @since __DEPLOY_VERSION__ - */ - public function getTransitions() - { - // Get a storage key. - $store = $this->getStoreId('getTransitions'); - - // Try to load the data from internal storage. - if (isset($this->cache[$store])) - { - return $this->cache[$store]; - } - - $db = $this->getDbo(); - $user = Factory::getUser(); - - $items = $this->getItems(); - - if ($items === false) - { - return false; - } - - $stageIds = ArrayHelper::getColumn($items, 'stage_id'); - $stageIds = ArrayHelper::toInteger($stageIds); - $stageIds = array_values(array_unique(array_filter($stageIds))); - - $workflowIds = ArrayHelper::getColumn($items, 'workflow_id'); - $workflowIds = ArrayHelper::toInteger($workflowIds); - $workflowIds = array_values(array_unique(array_filter($workflowIds))); - - $this->cache[$store] = array(); - - try - { - if (count($stageIds) || count($workflowIds)) - { - Factory::getLanguage()->load('com_workflow', JPATH_ADMINISTRATOR); - - $query = $db->getQuery(true); - - $query ->select( - [ - $db->quoteName('t.id', 'value'), - $db->quoteName('t.title', 'text'), - $db->quoteName('t.from_stage_id'), - $db->quoteName('t.to_stage_id'), - $db->quoteName('s.id', 'stage_id'), - $db->quoteName('s.title', 'stage_title'), - $db->quoteName('t.workflow_id'), - ] - ) - ->from($db->quoteName('#__workflow_transitions', 't')) - ->innerJoin( - $db->quoteName('#__workflow_stages', 's'), - $db->quoteName('t.to_stage_id') . ' = ' . $db->quoteName('s.id') - ) - ->where( - [ - $db->quoteName('t.published') . ' = 1', - $db->quoteName('s.published') . ' = 1', - ] - ) - ->order($db->quoteName('t.ordering')); - - $where = []; - - if (count($stageIds)) - { - $where[] = $db->quoteName('t.from_stage_id') . ' IN (' . implode(',', $query->bindArray($stageIds)) . ')'; - } - - if (count($workflowIds)) - { - $where[] = '(' . $db->quoteName('t.from_stage_id') . ' = -1 AND ' . $db->quoteName('t.workflow_id') . ' IN (' . implode(',', $query->bindArray($workflowIds)) . '))'; - } - - $query->where('((' . implode(') OR (', $where) . '))'); - - $transitions = $db->setQuery($query)->loadAssocList(); - - foreach ($transitions as $key => $transition) - { - if (!$user->authorise('core.execute.transition', 'com_modules.transition.' . (int) $transition['value'])) - { - unset($transitions[$key]); - } - } - - $this->cache[$store] = $transitions; - } - } - catch (\RuntimeException $e) - { - $this->setError($e->getMessage()); - - return false; - } - - return $this->cache[$store]; - } - - /** - * Manipulate the query to be used to evaluate if this is an Empty State to provide specific conditions for this extension. - * - * @return DatabaseQuery - * - * @since 4.0.0 - */ - protected function getEmptyStateQuery() - { - $query = parent::getEmptyStateQuery(); - - $clientId = (int) $this->getState('client_id'); - - $query->where($this->getDatabase()->quoteName('a.client_id') . ' = :client_id') - ->bind(':client_id', $clientId, ParameterType::INTEGER); - - return $query; - } + )'); + $query->bind(':menuitemid2', $menuItemId, ParameterType::INTEGER); + $query->bind(':menuitemid3', $minusMenuItemId, ParameterType::INTEGER); + } + } + + // Filter by search in title or note or id:. + $search = $this->getState('filter.search'); + + if (!empty($search)) { + if (stripos($search, 'id:') === 0) { + $ids = (int) substr($search, 3); + $query->where($db->quoteName('a.id') . ' = :id') + ->bind(':id', $ids, ParameterType::INTEGER); + } else { + $search = '%' . StringHelper::strtolower($search) . '%'; + $query->extendWhere( + 'AND', + [ + 'LOWER(' . $db->quoteName('a.title') . ') LIKE :title', + 'LOWER(' . $db->quoteName('a.note') . ') LIKE :note', + ], + 'OR' + ) + ->bind(':title', $search) + ->bind(':note', $search); + } + } + + // Filter on the language. + if ($language = $this->getState('filter.language')) { + if ($language === 'current') { + $language = [Factory::getLanguage()->getTag(), '*']; + $query->whereIn($db->quoteName('a.language'), $language, ParameterType::STRING); + } else { + $query->where($db->quoteName('a.language') . ' = :language') + ->bind(':language', $language); + } + } + + return $query; + } + + /** + * Method to get all transitions at once for all modules + * + * @return array|boolean + * + * @since __DEPLOY_VERSION__ + */ + public function getTransitions() + { + // Get a storage key. + $store = $this->getStoreId('getTransitions'); + + // Try to load the data from internal storage. + if (isset($this->cache[$store])) { + return $this->cache[$store]; + } + + $db = $this->getDbo(); + $user = Factory::getUser(); + + $items = $this->getItems(); + + if ($items === false) { + return false; + } + + $stageIds = ArrayHelper::getColumn($items, 'stage_id'); + $stageIds = ArrayHelper::toInteger($stageIds); + $stageIds = array_values(array_unique(array_filter($stageIds))); + + $workflowIds = ArrayHelper::getColumn($items, 'workflow_id'); + $workflowIds = ArrayHelper::toInteger($workflowIds); + $workflowIds = array_values(array_unique(array_filter($workflowIds))); + + $this->cache[$store] = array(); + + try { + if (count($stageIds) || count($workflowIds)) { + Factory::getLanguage()->load('com_workflow', JPATH_ADMINISTRATOR); + + $query = $db->getQuery(true); + + $query ->select( + [ + $db->quoteName('t.id', 'value'), + $db->quoteName('t.title', 'text'), + $db->quoteName('t.from_stage_id'), + $db->quoteName('t.to_stage_id'), + $db->quoteName('s.id', 'stage_id'), + $db->quoteName('s.title', 'stage_title'), + $db->quoteName('t.workflow_id'), + ] + ) + ->from($db->quoteName('#__workflow_transitions', 't')) + ->innerJoin( + $db->quoteName('#__workflow_stages', 's'), + $db->quoteName('t.to_stage_id') . ' = ' . $db->quoteName('s.id') + ) + ->where( + [ + $db->quoteName('t.published') . ' = 1', + $db->quoteName('s.published') . ' = 1', + ] + ) + ->order($db->quoteName('t.ordering')); + + $where = []; + + if (count($stageIds)) { + $where[] = $db->quoteName('t.from_stage_id') . ' IN (' . implode(',', $query->bindArray($stageIds)) . ')'; + } + + if (count($workflowIds)) { + $where[] = '(' . $db->quoteName('t.from_stage_id') . ' = -1 AND ' . $db->quoteName('t.workflow_id') . ' IN (' . implode(',', $query->bindArray($workflowIds)) . '))'; + } + + $query->where('((' . implode(') OR (', $where) . '))'); + + $transitions = $db->setQuery($query)->loadAssocList(); + + foreach ($transitions as $key => $transition) { + if (!$user->authorise('core.execute.transition', 'com_modules.transition.' . (int) $transition['value'])) { + unset($transitions[$key]); + } + } + + $this->cache[$store] = $transitions; + } + } catch (\RuntimeException $e) { + $this->setError($e->getMessage()); + + return false; + } + + return $this->cache[$store]; + } + + /** + * Manipulate the query to be used to evaluate if this is an Empty State to provide specific conditions for this extension. + * + * @return DatabaseQuery + * + * @since 4.0.0 + */ + protected function getEmptyStateQuery() + { + $query = parent::getEmptyStateQuery(); + + $clientId = (int) $this->getState('client_id'); + + $query->where($this->getDatabase()->quoteName('a.client_id') . ' = :client_id') + ->bind(':client_id', $clientId, ParameterType::INTEGER); + + return $query; + } } diff --git a/administrator/components/com_modules/src/View/Modules/HtmlView.php b/administrator/components/com_modules/src/View/Modules/HtmlView.php index 9ee8e50b118bd..94a320527f3dc 100644 --- a/administrator/components/com_modules/src/View/Modules/HtmlView.php +++ b/administrator/components/com_modules/src/View/Modules/HtmlView.php @@ -1,4 +1,5 @@ items = $this->get('Items'); - $this->pagination = $this->get('Pagination'); - $this->state = $this->get('State'); - $this->total = $this->get('Total'); - $this->filterForm = $this->get('FilterForm'); - $this->activeFilters = $this->get('ActiveFilters'); - $this->clientId = $this->state->get('client_id'); - - if (!count($this->items) && $this->isEmptyState = $this->get('IsEmptyState')) - { - $this->setLayout('emptystate'); - } - - if (ComponentHelper::getParams('com_modules')->get('workflow_enabled')) - { - PluginHelper::importPlugin('workflow'); - - $this->transitions = $this->get('Transitions'); - } - - /** - * The code below make sure the remembered position will be available from filter dropdown even if there are no - * modules available for this position. This will make the UI less confusing for users in case there is only one - * module in the selected position and user: - * 1. Edit the module, change it to new position, save it and come back to Modules Management Screen - * 2. Or move that module to new position using Batch action - */ - if (count($this->items) === 0 && $this->state->get('filter.position')) - { - $selectedPosition = $this->state->get('filter.position'); - $positionField = $this->filterForm->getField('position', 'filter'); - - $positionExists = false; - - foreach ($positionField->getOptions() as $option) - { - if ($option->value === $selectedPosition) - { - $positionExists = true; - break; - } - } - - if ($positionExists === false) - { - $positionField->addOption($selectedPosition, ['value' => $selectedPosition]); - } - } - - // Check for errors. - if (count($errors = $this->get('Errors'))) - { - throw new GenericDataException(implode("\n", $errors), 500); - } - - // We do not need the Language filter when modules are not filtered - if ($this->clientId == 1 && !ModuleHelper::isAdminMultilang()) - { - unset($this->activeFilters['language']); - $this->filterForm->removeField('language', 'filter'); - } - - // We don't need the toolbar in the modal window. - if ($this->getLayout() !== 'modal') - { - $this->addToolbar(); - - // We do not need to filter by language when multilingual is disabled - if (!Multilanguage::isEnabled()) - { - unset($this->activeFilters['language']); - $this->filterForm->removeField('language', 'filter'); - } - } - // If in modal layout. - else - { - // Client id selector should not exist. - $this->filterForm->removeField('client_id', ''); - - // If in the frontend state and language should not activate the search tools. - if (Factory::getApplication()->isClient('site')) - { - unset($this->activeFilters['state']); - unset($this->activeFilters['language']); - } - } - - parent::display($tpl); - } - - /** - * Add the page title and toolbar. - * - * @return void - * - * @since 1.6 - */ - protected function addToolbar() - { - $state = $this->get('State'); - $canDo = ContentHelper::getActions('com_modules'); - $user = $this->getCurrentUser(); - - // Get the toolbar object instance - $toolbar = Toolbar::getInstance('toolbar'); - - if ($state->get('client_id') == 1) - { - ToolbarHelper::title(Text::_('COM_MODULES_MANAGER_MODULES_ADMIN'), 'cube module'); - } - else - { - ToolbarHelper::title(Text::_('COM_MODULES_MANAGER_MODULES_SITE'), 'cube module'); - } - - if ($canDo->get('core.create')) - { - $toolbar->standardButton('new', 'JTOOLBAR_NEW') - ->onclick("location.href='index.php?option=com_modules&view=select&client_id=" . $this->state->get('client_id', 0) . "'"); - } - - if (!$this->isEmptyState && ($canDo->get('core.edit.state') || $this->getCurrentUser()->authorise('core.admin'))) - { - $dropdown = $toolbar->dropdownButton('status-group') - ->text('JTOOLBAR_CHANGE_STATUS') - ->toggleSplit(false) - ->icon('icon-ellipsis-h') - ->buttonClass('btn btn-action') - ->listCheck(true); - - $childBar = $dropdown->getChildToolbar(); - - if ($canDo->get('core.edit.state')) - { - $childBar->publish('modules.publish')->listCheck(true); - - $childBar->unpublish('modules.unpublish')->listCheck(true); - } - - if ($this->getCurrentUser()->authorise('core.admin')) - { - $childBar->checkin('modules.checkin')->listCheck(true); - } - - if ($canDo->get('core.edit.state') && $this->state->get('filter.published') != -2) - { - $childBar->trash('modules.trash')->listCheck(true); - } - - // Add a batch button - if ($user->authorise('core.create', 'com_modules') && $user->authorise('core.edit', 'com_modules') - && $user->authorise('core.edit.state', 'com_modules')) - { - $childBar->popupButton('batch') - ->text('JTOOLBAR_BATCH') - ->selector('collapseModal') - ->listCheck(true); - } - - if ($canDo->get('core.create')) - { - $childBar->standardButton('copy') - ->text('JTOOLBAR_DUPLICATE') - ->task('modules.duplicate') - ->listCheck(true); - } - } - - if (!$this->isEmptyState && ($state->get('filter.state') == -2 && $canDo->get('core.delete'))) - { - $toolbar->delete('modules.delete') - ->text('JTOOLBAR_EMPTY_TRASH') - ->message('JGLOBAL_CONFIRM_DELETE') - ->listCheck(true); - } - - if ($canDo->get('core.admin')) - { - $toolbar->preferences('com_modules'); - } - - $toolbar->help('Modules'); - } + /** + * An array of items + * + * @var array + */ + protected $items; + + /** + * The pagination object + * + * @var \Joomla\CMS\Pagination\Pagination + */ + protected $pagination; + + /** + * The model state + * + * @var \Joomla\CMS\Object\CMSObject + */ + protected $state; + + /** + * 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; + + /** + * Is this view an Empty State + * + * @var boolean + * @since 4.0.0 + */ + private $isEmptyState = false; + + /** + * Display the view + * + * @param string $tpl The name of the template file to parse; automatically searches through the template paths. + * + * @return void + * + * @since 1.6 + */ + public function display($tpl = null) + { + $this->items = $this->get('Items'); + $this->pagination = $this->get('Pagination'); + $this->state = $this->get('State'); + $this->total = $this->get('Total'); + $this->filterForm = $this->get('FilterForm'); + $this->activeFilters = $this->get('ActiveFilters'); + $this->clientId = $this->state->get('client_id'); + + if (!count($this->items) && $this->isEmptyState = $this->get('IsEmptyState')) { + $this->setLayout('emptystate'); + } + + if (ComponentHelper::getParams('com_modules')->get('workflow_enabled')) { + PluginHelper::importPlugin('workflow'); + + $this->transitions = $this->get('Transitions'); + } + + /** + * The code below make sure the remembered position will be available from filter dropdown even if there are no + * modules available for this position. This will make the UI less confusing for users in case there is only one + * module in the selected position and user: + * 1. Edit the module, change it to new position, save it and come back to Modules Management Screen + * 2. Or move that module to new position using Batch action + */ + if (count($this->items) === 0 && $this->state->get('filter.position')) { + $selectedPosition = $this->state->get('filter.position'); + $positionField = $this->filterForm->getField('position', 'filter'); + + $positionExists = false; + + foreach ($positionField->getOptions() as $option) { + if ($option->value === $selectedPosition) { + $positionExists = true; + break; + } + } + + if ($positionExists === false) { + $positionField->addOption($selectedPosition, ['value' => $selectedPosition]); + } + } + + // Check for errors. + if (count($errors = $this->get('Errors'))) { + throw new GenericDataException(implode("\n", $errors), 500); + } + + // We do not need the Language filter when modules are not filtered + if ($this->clientId == 1 && !ModuleHelper::isAdminMultilang()) { + unset($this->activeFilters['language']); + $this->filterForm->removeField('language', 'filter'); + } + + // We don't need the toolbar in the modal window. + if ($this->getLayout() !== 'modal') { + $this->addToolbar(); + + // We do not need to filter by language when multilingual is disabled + if (!Multilanguage::isEnabled()) { + unset($this->activeFilters['language']); + $this->filterForm->removeField('language', 'filter'); + } + } + // If in modal layout. + else { + // Client id selector should not exist. + $this->filterForm->removeField('client_id', ''); + + // If in the frontend state and language should not activate the search tools. + if (Factory::getApplication()->isClient('site')) { + unset($this->activeFilters['state']); + unset($this->activeFilters['language']); + } + } + + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @return void + * + * @since 1.6 + */ + protected function addToolbar() + { + $state = $this->get('State'); + $canDo = ContentHelper::getActions('com_modules'); + $user = $this->getCurrentUser(); + + // Get the toolbar object instance + $toolbar = Toolbar::getInstance('toolbar'); + + if ($state->get('client_id') == 1) { + ToolbarHelper::title(Text::_('COM_MODULES_MANAGER_MODULES_ADMIN'), 'cube module'); + } else { + ToolbarHelper::title(Text::_('COM_MODULES_MANAGER_MODULES_SITE'), 'cube module'); + } + + if ($canDo->get('core.create')) { + $toolbar->standardButton('new', 'JTOOLBAR_NEW') + ->onclick("location.href='index.php?option=com_modules&view=select&client_id=" . $this->state->get('client_id', 0) . "'"); + } + + if (!$this->isEmptyState && ($canDo->get('core.edit.state') || $this->getCurrentUser()->authorise('core.admin'))) { + $dropdown = $toolbar->dropdownButton('status-group') + ->text('JTOOLBAR_CHANGE_STATUS') + ->toggleSplit(false) + ->icon('icon-ellipsis-h') + ->buttonClass('btn btn-action') + ->listCheck(true); + + $childBar = $dropdown->getChildToolbar(); + + if ($canDo->get('core.edit.state')) { + $childBar->publish('modules.publish')->listCheck(true); + + $childBar->unpublish('modules.unpublish')->listCheck(true); + } + + if ($this->getCurrentUser()->authorise('core.admin')) { + $childBar->checkin('modules.checkin')->listCheck(true); + } + + if ($canDo->get('core.edit.state') && $this->state->get('filter.published') != -2) { + $childBar->trash('modules.trash')->listCheck(true); + } + + // Add a batch button + if ( + $user->authorise('core.create', 'com_modules') && $user->authorise('core.edit', 'com_modules') + && $user->authorise('core.edit.state', 'com_modules') + ) { + $childBar->popupButton('batch') + ->text('JTOOLBAR_BATCH') + ->selector('collapseModal') + ->listCheck(true); + } + + if ($canDo->get('core.create')) { + $childBar->standardButton('copy') + ->text('JTOOLBAR_DUPLICATE') + ->task('modules.duplicate') + ->listCheck(true); + } + } + + if (!$this->isEmptyState && ($state->get('filter.state') == -2 && $canDo->get('core.delete'))) { + $toolbar->delete('modules.delete') + ->text('JTOOLBAR_EMPTY_TRASH') + ->message('JGLOBAL_CONFIRM_DELETE') + ->listCheck(true); + } + + if ($canDo->get('core.admin')) { + $toolbar->preferences('com_modules'); + } + + $toolbar->help('Modules'); + } } diff --git a/administrator/components/com_modules/tmpl/module/edit.php b/administrator/components/com_modules/tmpl/module/edit.php index 04601a130eaed..147f374025727 100644 --- a/administrator/components/com_modules/tmpl/module/edit.php +++ b/administrator/components/com_modules/tmpl/module/edit.php @@ -1,4 +1,5 @@ document->getWebAssetManager(); $wa->useScript('keepalive') - ->useScript('form.validate') - ->useScript('com_modules.admin-module-edit'); + ->useScript('form.validate') + ->useScript('com_modules.admin-module-edit'); $input = Factory::getApplication()->input; @@ -57,152 +57,145 @@
- - -
- 'general', 'recall' => true, 'breakpoint' => 768]); ?> - - - -
-
- item->xml) : ?> - item->xml->description) : ?> -

- item->xml) - { - echo ($text = (string) $this->item->xml->name) ? Text::_($text) : $this->item->module; - } - else - { - echo Text::_('COM_MODULES_ERR_XML'); - } - ?> -

-
- - item->client_id == 0 ? Text::_('JSITE') : Text::_('JADMINISTRATOR'); ?> - -
-
- fieldset = 'description'; - $short_description = Text::_($this->item->xml->description); - $long_description = LayoutHelper::render('joomla.edit.fieldset', $this); - - if (!$long_description) - { - $truncated = HTMLHelper::_('string.truncate', $short_description, 550, true, false); - - if (strlen($truncated) > 500) - { - $long_description = $short_description; - $short_description = HTMLHelper::_('string.truncate', $truncated, 250); - - if ($short_description == $long_description) - { - $long_description = ''; - } - } - } - ?> -

- -

- - - -

- -
- - -
- - -
- - form->getInput($hasContentFieldName); - } - $this->fieldset = 'basic'; - $html = LayoutHelper::render('joomla.edit.fieldset', $this); - echo $html ? '
' . $html : ''; - ?> -
-
- fields = array( - $workflowField, - 'showtitle', - 'position', - 'published', - 'publish_up', - 'publish_down', - 'access', - 'ordering', - 'language', - 'note' - ); - - ?> - item->client_id == 0) : ?> - - - - -
-
- - - - -
-
- -
-
- - - - item->client_id == 0) : ?> - -
- -
- loadTemplate('assignment'); ?> -
-
- - - - fieldsets = array(); - $this->ignore_fieldsets = array('basic', 'description', 'workflow'); - echo LayoutHelper::render('joomla.edit.params', $this); - ?> - - canDo->get('core.admin')) : ?> - -
- -
- form->getInput('rules'); ?> -
-
- - - - - - - - - form->getInput('module'); ?> - form->getInput('client_id'); ?> -
+ + +
+ 'general', 'recall' => true, 'breakpoint' => 768]); ?> + + + +
+
+ item->xml) : ?> + item->xml->description) : ?> +

+ item->xml) { + echo ($text = (string) $this->item->xml->name) ? Text::_($text) : $this->item->module; + } else { + echo Text::_('COM_MODULES_ERR_XML'); + } + ?> +

+
+ + item->client_id == 0 ? Text::_('JSITE') : Text::_('JADMINISTRATOR'); ?> + +
+
+ fieldset = 'description'; + $short_description = Text::_($this->item->xml->description); + $long_description = LayoutHelper::render('joomla.edit.fieldset', $this); + + if (!$long_description) { + $truncated = HTMLHelper::_('string.truncate', $short_description, 550, true, false); + + if (strlen($truncated) > 500) { + $long_description = $short_description; + $short_description = HTMLHelper::_('string.truncate', $truncated, 250); + + if ($short_description == $long_description) { + $long_description = ''; + } + } + } + ?> +

+ +

+ + + +

+ +
+ + +
+ + +
+ + form->getInput($hasContentFieldName); + } + $this->fieldset = 'basic'; + $html = LayoutHelper::render('joomla.edit.fieldset', $this); + echo $html ? '
' . $html : ''; + ?> +
+
+ fields = array( + $workflowField, + 'showtitle', + 'position', + 'published', + 'publish_up', + 'publish_down', + 'access', + 'ordering', + 'language', + 'note' + ); + + ?> + item->client_id == 0) : ?> + + + + +
+
+ + + + +
+
+ +
+
+ + + + item->client_id == 0) : ?> + +
+ +
+ loadTemplate('assignment'); ?> +
+
+ + + + fieldsets = array(); + $this->ignore_fieldsets = array('basic', 'description', 'workflow'); + echo LayoutHelper::render('joomla.edit.params', $this); + ?> + + canDo->get('core.admin')) : ?> + +
+ +
+ form->getInput('rules'); ?> +
+
+ + + + + + + + + form->getInput('module'); ?> + form->getInput('client_id'); ?> +
diff --git a/administrator/components/com_modules/tmpl/modules/default.php b/administrator/components/com_modules/tmpl/modules/default.php index 9aa7e4259c307..e4bd365a7efc0 100644 --- a/administrator/components/com_modules/tmpl/modules/default.php +++ b/administrator/components/com_modules/tmpl/modules/default.php @@ -1,4 +1,5 @@ document->getWebAssetManager(); $wa->useScript('table.columns') - ->useScript('multiselect'); + ->useScript('multiselect'); $clientId = (int) $this->state->get('client_id', 0); $user = Factory::getUser(); @@ -34,19 +35,17 @@ $listDirn = $this->escape($this->state->get('list.direction')); $saveOrder = ($listOrder == 'a.ordering'); -if ($saveOrder && !empty($this->items)) -{ - $saveOrderingUrl = 'index.php?option=com_modules&task=modules.saveOrderAjax&tmpl=component&' . Session::getFormToken() . '=1'; - HTMLHelper::_('draggablelist.draggable'); +if ($saveOrder && !empty($this->items)) { + $saveOrderingUrl = 'index.php?option=com_modules&task=modules.saveOrderAjax&tmpl=component&' . Session::getFormToken() . '=1'; + HTMLHelper::_('draggablelist.draggable'); } $workflow_enabled = ComponentHelper::getParams('com_modules')->get('workflow_enabled'); $workflow_state = false; if ($workflow_enabled) : - // @todo move the script to a file -$js = <<document->getWebAssetManager(); - - $wa->getRegistry()->addExtensionRegistryFile('com_workflow'); - $wa->useScript('com_workflow.admin-items-workflow-buttons') - ->addInlineScript($js, [], ['type' => 'module']); + /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ + $wa = $this->document->getWebAssetManager(); - $workflow_state = Factory::getApplication()->bootComponent('com_modules')->isFunctionalityUsed('core.state', 'com_modules.module'); + $wa->getRegistry()->addExtensionRegistryFile('com_workflow'); + $wa->useScript('com_workflow.admin-items-workflow-buttons') + ->addInlineScript($js, [], ['type' => 'module']); + $workflow_state = Factory::getApplication()->bootComponent('com_modules')->isFunctionalityUsed('core.state', 'com_modules.module'); endif; ?>
-
- $this)); ?> - total > 0) : ?> - - - - - - - - - - - - - - - - - - - - - - - - - - class="js-draggable" data-url="" data-direction="" data-nested="false"> - items as $i => $item) : - $ordering = ($listOrder == 'a.ordering'); - $canCreate = $user->authorise('core.create', 'com_modules'); - $canEdit = $user->authorise('core.edit', 'com_modules.module.' . $item->id); - $canCheckin = $user->authorise('core.manage', 'com_checkin') || $item->checked_out == $user->get('id')|| is_null($item->checked_out); - $canChange = $user->authorise('core.edit.state', 'com_modules.module.' . $item->id) && $canCheckin; - if ($workflow_enabled) - { - $transitions = ContentHelper::filterTransitions($this->transitions, (int) $item->stage_id, (int) $item->workflow_id); +
+ $this)); ?> + total > 0) : ?> +
- , - , - -
- - - - - - - - - - - - - - - - - - - - - - - -
+ + + + + + + + + + + + + + + + + + + + + + + + + class="js-draggable" data-url="" data-direction="" data-nested="false"> + items as $i => $item) : + $ordering = ($listOrder == 'a.ordering'); + $canCreate = $user->authorise('core.create', 'com_modules'); + $canEdit = $user->authorise('core.edit', 'com_modules.module.' . $item->id); + $canCheckin = $user->authorise('core.manage', 'com_checkin') || $item->checked_out == $user->get('id') || is_null($item->checked_out); + $canChange = $user->authorise('core.edit.state', 'com_modules.module.' . $item->id) && $canCheckin; + if ($workflow_enabled) { + $transitions = ContentHelper::filterTransitions($this->transitions, (int) $item->stage_id, (int) $item->workflow_id); - $transitionIds = ArrayHelper::getColumn($transitions, 'value'); - $transitionIds = ArrayHelper::toInteger($transitionIds); - } - ?> - - - - - + + + + - + - - - - + + - - - - - - - - - - - - - - - -
+ , + , + +
+ + + + + + + + + + + + + + + + + + + + + + + +
- id, false, 'cid', 'cb', $item->title); ?> - - - - - - - - - - $transitions, - 'title' => Text::_($item->stage_title), - 'tip_content' => Text::sprintf('JWORKFLOW', Text::_($item->workflow_title)), - 'id' => 'workflow-' . $item->id, - 'task' => 'modules.runTransition' - ]; + $transitionIds = ArrayHelper::getColumn($transitions, 'value'); + $transitionIds = ArrayHelper::toInteger($transitionIds); + } + ?> +
+ id, false, 'cid', 'cb', $item->title); ?> + + + + + + + + + + $transitions, + 'title' => Text::_($item->stage_title), + 'tip_content' => Text::sprintf('JWORKFLOW', Text::_($item->workflow_title)), + 'id' => 'workflow-' . $item->id, + 'task' => 'modules.runTransition' + ]; - echo (new TransitionButton($options)) - ->render(0, $i); - ?> - - 'modules.', - 'disabled' => $workflow_state || !$canChange, - 'id' => 'state-' . $item->id - ]; + echo (new TransitionButton($options)) + ->render(0, $i); + ?> + + 'modules.', + 'disabled' => $workflow_state || !$canChange, + 'id' => 'state-' . $item->id + ]; - echo (new PublishedButton)->render((int) $item->published, $i, $options, $item->publish_up, $item->publish_down); - ?> - - - enabled > 0) : ?> - published, $i, 'modules.', $canChange, 'cb', $item->publish_up, $item->publish_down); ?> - - - - - - - -
- checked_out) : ?> - editor, $item->checked_out_time, 'modules.', $canCheckin); ?> - - - - escape($item->title); ?> - - escape($item->title); ?> - + echo (new PublishedButton())->render((int) $item->published, $i, $options, $item->publish_up, $item->publish_down); + ?> + + +
+ + enabled > 0) : ?> + published, $i, 'modules.', $canChange, 'cb', $item->publish_up, $item->publish_down); ?> + + + + + + + +
+ checked_out) : ?> + editor, $item->checked_out_time, 'modules.', $canCheckin); ?> + + + + escape($item->title); ?> + + escape($item->title); ?> + - note)) : ?> -
- escape($item->note)); ?> -
- -
-
- position) : ?> - - position; ?> - - - - - - - - name; ?> - - pages; ?> - - escape($item->access_level); ?> - - - - language == ''):?> - - language == '*'):?> - - - escape($item->language); ?> - - - id; ?> -
+ note)) : ?> +
+ escape($item->note)); ?> +
+ +
+ + + position) : ?> + + position; ?> + + + + + + + + + name; ?> + + + + pages; ?> + + + + escape($item->access_level); ?> + + + + + + + + language == '') :?> + + language == '*') :?> + + + escape($item->language); ?> + + + + + id; ?> + + + + + - - pagination->getListFooter(); ?> + + pagination->getListFooter(); ?> - + - - authorise('core.create', 'com_modules') - && $user->authorise('core.edit', 'com_modules') - && $user->authorise('core.edit.state', 'com_modules')) : ?> - Text::_('COM_MODULES_BATCH_OPTIONS'), - 'footer' => $this->loadTemplate('batch_footer'), - ), - $this->loadTemplate('batch_body') - ); ?> - + + authorise('core.create', 'com_modules') + && $user->authorise('core.edit', 'com_modules') + && $user->authorise('core.edit.state', 'com_modules') +) : ?> + Text::_('COM_MODULES_BATCH_OPTIONS'), + 'footer' => $this->loadTemplate('batch_footer'), + ), + $this->loadTemplate('batch_body') + ); ?> + - - - + + + - - - - + + + +
diff --git a/administrator/components/com_modules/tmpl/modules/default_batch_body.php b/administrator/components/com_modules/tmpl/modules/default_batch_body.php index d70543f87e9ca..a275865115f4a 100644 --- a/administrator/components/com_modules/tmpl/modules/default_batch_body.php +++ b/administrator/components/com_modules/tmpl/modules/default_batch_body.php @@ -1,4 +1,5 @@ 'batch-position-id', + 'id' => 'batch-position-id', ); Text::script('JGLOBAL_SELECT_NO_RESULTS_MATCH'); Text::script('JGLOBAL_SELECT_PRESS_TO_SELECT'); $this->document->getWebAssetManager() - ->usePreset('choicesjs') - ->useScript('webcomponent.field-fancy-select') - ->useScript('joomla.batch-copymove'); + ->usePreset('choicesjs') + ->useScript('webcomponent.field-fancy-select') + ->useScript('joomla.batch-copymove'); ?>
-

-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- authorise('core.admin', 'com_modules') && $params->get('workflow_enabled')) : ?> -
-
- 'com_modules']); ?> -
-
- -
-
- = 0) : ?> -
-
- -
- - - -
- -
-
-
- -
-
+

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ authorise('core.admin', 'com_modules') && $params->get('workflow_enabled')) : ?> +
+
+ 'com_modules']); ?> +
+
+ +
+
+ = 0) : ?> +
+
+ +
+ + + +
+ +
+
+
+ +
+
diff --git a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php index 5418a1dc6f582..2419fb44b074b 100644 --- a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php +++ b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php @@ -1,4 +1,5 @@ extension = array_shift($parts); - - if (count($parts)) - { - $this->section = array_shift($parts); - } - - $this->workflow = new Workflow($extension); - - $params = ComponentHelper::getParams($this->extension); - - $this->workflowEnabled = $params->get('workflow_enabled'); - - $this->enableWorkflowBatch(); - } - - /** - * Add the workflow batch to the command list. Can be overwritten bei the child class - * - * @return void - * - * @since 4.0.0 - */ - protected function enableWorkflowBatch() - { - // Enable batch - if ($this->workflowEnabled && property_exists($this, 'batch_commands')) - { - $this->batch_commands['workflowstage_id'] = 'batchWorkflowStage'; - } - } - - /** - * Method to allow derived classes to preprocess the form. - * - * @param Form $form A Form object. - * @param mixed $data The data expected for the form. - * - * @return void - * - * @since 4.0.0 - * @see FormField - */ - public function workflowPreprocessForm(Form $form, $data) - { - $this->addTransitionField($form, $data); - - if (!$this->workflowEnabled) - { - return; - } - - // Import the workflow plugin group to allow form manipulation. - $this->importWorkflowPlugins(); - } - - /** - * Let plugins access stage change events - * - * @return void - * - * @since 4.0.0 - */ - public function workflowBeforeStageChange() - { - if (!$this->workflowEnabled) - { - return; - } - - $this->importWorkflowPlugins(); - } - - /** - * Preparation of workflow data/plugins - * - * @return void - * - * @since 4.0.0 - */ - public function workflowBeforeSave() - { - if (!$this->workflowEnabled) - { - return; - } - - $this->importWorkflowPlugins(); - } - - /** - * Executing of relevant workflow methods - * - * @return void - * - * @since 4.0.0 - */ - public function workflowAfterSave($data) - { - // Regardless if workflow is active or not, we have to set the default stage - // So we can work with the workflow, when the user activates it later - $id = $this->getState($this->getName() . '.id'); - $isNew = $this->getState($this->getName() . '.new'); - - // We save the first stage - if ($isNew) - { - // We have to add the paths, because it could be called outside of the extension context - $path = JPATH_BASE . '/components/' . $this->extension; - - $path = Path::check($path); - - Form::addFormPath($path . '/forms'); - Form::addFormPath($path . '/models/forms'); - Form::addFieldPath($path . '/models/fields'); - Form::addFormPath($path . '/model/form'); - Form::addFieldPath($path . '/model/field'); - - $form = $this->getForm(); - - $stage_id = $this->getStageForNewItem($form, $data); - - $this->workflow->createAssociation($id, $stage_id); - } - - if (!$this->workflowEnabled) - { - return; - } - - // Execute transition - if (!empty($data['transition'])) - { - $this->executeTransition([$id], $data['transition']); - } - } - - /** - * Batch change workflow stage or current. - * - * @param integer $value The workflow stage ID. - * @param array $pks An array of row IDs. - * @param array $contexts An array of item contexts. - * - * @return mixed An array of new IDs on success, boolean false on failure. - * - * @since 4.0.0 - */ - public function batchWorkflowStage(int $value, array $pks, array $contexts) - { - $user = Factory::getApplication()->getIdentity(); - - $workflow = Factory::getApplication()->bootComponent('com_workflow'); - - if (!$user->authorise('core.admin', $this->option)) - { - $this->setError(Text::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_EXECUTE_TRANSITION')); - } - - // Get workflow stage information - $stage = $workflow->getMVCFactory()->createTable('Stage', 'Administrator'); - - if (empty($value) || !$stage->load($value)) - { - Factory::getApplication()->enqueueMessage(Text::sprintf('JGLOBAL_BATCH_WORKFLOW_STAGE_ROW_NOT_FOUND'), 'error'); - - return false; - } - - if (empty($pks)) - { - Factory::getApplication()->enqueueMessage(Text::sprintf('JGLOBAL_BATCH_WORKFLOW_STAGE_ROW_NOT_FOUND'), 'error'); - - return false; - } - - // Update workflow associations - return $this->workflow->updateAssociations($pks, $value); - } - - /** - * Batch change workflow stage or current. - * - * @param integer $oldId The ID of the item copied from - * @param integer $newId The ID of the new item - * - * @return null - * - * @since 4.0.0 - */ - public function workflowCleanupBatchMove($oldId, $newId) - { - // Trigger workflow plugins only if enable (will be triggered from parent class) - if ($this->workflowEnabled) - { - $this->importWorkflowPlugins(); - } - - // We always need an association, so create one - $table = $this->getTable(); - - $table->load($newId); - - $catKey = $table->getColumnAlias('catid'); - - $stage_id = $this->workflow->getDefaultStageByCategory($table->$catKey); - - if (empty($stage_id)) - { - return; - } - - $this->workflow->createAssociation((int) $newId, (int) $stage_id); - } - - /** - * Runs transition for item. - * - * @param array $pks Id of items to execute the transition - * @param integer $transitionId Id of transition - * - * @return boolean - * - * @since 4.0.0 - */ - public function executeTransition(array $pks, int $transitionId) - { - $result = $this->workflow->executeTransition($pks, $transitionId); - - if (!$result) - { - $app = Factory::getApplication(); - - $app->enqueueMessage(Text::_('COM_CONTENT_ERROR_UPDATE_STAGE', $app::MSG_WARNING)); - - return false; - } - - return true; - } - - /** - * Import the Workflow plugins. - * - * @param Form $form A Form object. - * @param mixed $data The data expected for the form. - * - * @return void - */ - protected function importWorkflowPlugins() - { - PluginHelper::importPlugin('workflow'); - } - - /** - * Adds a transition field to the form. Can be overwritten by the child class if not needed - * - * @param Form $form A Form object. - * @param mixed $data The data expected for the form. - * - * @return void - * @since 4.0.0 - */ - protected function addTransitionField(Form $form, $data) - { - $extension = $this->extension . ($this->section ? '.' . $this->section : ''); - - $field = new \SimpleXMLElement(''); - - $field->addAttribute('name', 'transition'); - $field->addAttribute('type', $this->workflowEnabled ? 'transition' : 'hidden'); - $field->addAttribute('label', 'JWORKFLOW_TITLE'); - $field->addAttribute('extension', $extension); - - $form->setField($field); - - $table = $this->getTable(); - - $key = $table->getKeyName(); - - $id = isset($data->$key) ? $data->$key : $form->getValue($key); - - if ($id) - { - // Transition field - $assoc = $this->workflow->getAssociation($id); - - if (!empty($assoc->stage_id)) - { - $form->setFieldAttribute('transition', 'workflow_stage', (int) $assoc->stage_id); - } - } - else - { - $stage_id = $this->getStageForNewItem($form, $data); - - if (!empty($stage_id)) - { - $form->setFieldAttribute('transition', 'workflow_stage', (int) $stage_id); - } - } - } - - /** - * Try to load a workflow stage for newly created items - * which does not have a workflow assigned yet. If the category is not the - * carrier, overwrite it on your model and deliver your own carrier. - * - * @param Form $form A Form object. - * @param mixed $data The data expected for the form. - * - * @return boolean|integer An integer, holding the stage ID or false - * @since 4.0.0 - */ - protected function getStageForNewItem(Form $form, $data) - { - $table = $this->getTable(); - - $hasKey = $table->hasField('catid'); - - if (!$hasKey) - { - return false; - } - - $catKey = $table->getColumnAlias('catid'); - - $field = $form->getField($catKey); - - if (!$field) - { - return false; - } - - $catId = isset(((object) $data)->$catKey) ? ((object) $data)->$catKey : $form->getValue($catKey); - - // Try to get the category from the html code of the field - if (empty($catId)) - { - $catId = $field->getAttribute('default', null); - - if (!$catId) - { - // Choose the first category available - $catOptions = $field->options; - - if ($catOptions && !empty($catOptions[0]->value)) - { - $catId = (int) $catOptions[0]->value; - } - } - } - - if (empty($catId)) - { - return false; - } - - return $this->workflow->getDefaultStageByCategory($catId); - } + /** + * The name of the component. + * + * @var string + * @since 4.0.0 + */ + protected $extension = null; + + /** + * The section of the component. + * + * @var string + * @since 4.0.0 + */ + protected $section = ''; + + /** + * Is workflow for this component enabled? + * + * @var boolean + * @since 4.0.0 + */ + protected $workflowEnabled = false; + + /** + * The workflow object + * + * @var Workflow + * @since 4.0.0 + */ + protected $workflow; + + /** + * Set Up the workflow + * + * @param string $extension The option and section separated by. + * + * @return void + * + * @since 4.0.0 + */ + public function setUpWorkflow($extension) + { + $parts = explode('.', $extension); + + $this->extension = array_shift($parts); + + if (count($parts)) { + $this->section = array_shift($parts); + } + + $this->workflow = new Workflow($extension); + + $params = ComponentHelper::getParams($this->extension); + + $this->workflowEnabled = $params->get('workflow_enabled'); + + $this->enableWorkflowBatch(); + } + + /** + * Add the workflow batch to the command list. Can be overwritten bei the child class + * + * @return void + * + * @since 4.0.0 + */ + protected function enableWorkflowBatch() + { + // Enable batch + if ($this->workflowEnabled && property_exists($this, 'batch_commands')) { + $this->batch_commands['workflowstage_id'] = 'batchWorkflowStage'; + } + } + + /** + * Method to allow derived classes to preprocess the form. + * + * @param Form $form A Form object. + * @param mixed $data The data expected for the form. + * + * @return void + * + * @since 4.0.0 + * @see FormField + */ + public function workflowPreprocessForm(Form $form, $data) + { + $this->addTransitionField($form, $data); + + if (!$this->workflowEnabled) { + return; + } + + // Import the workflow plugin group to allow form manipulation. + $this->importWorkflowPlugins(); + } + + /** + * Let plugins access stage change events + * + * @return void + * + * @since 4.0.0 + */ + public function workflowBeforeStageChange() + { + if (!$this->workflowEnabled) { + return; + } + + $this->importWorkflowPlugins(); + } + + /** + * Preparation of workflow data/plugins + * + * @return void + * + * @since 4.0.0 + */ + public function workflowBeforeSave() + { + if (!$this->workflowEnabled) { + return; + } + + $this->importWorkflowPlugins(); + } + + /** + * Executing of relevant workflow methods + * + * @return void + * + * @since 4.0.0 + */ + public function workflowAfterSave($data) + { + // Regardless if workflow is active or not, we have to set the default stage + // So we can work with the workflow, when the user activates it later + $id = $this->getState($this->getName() . '.id'); + $isNew = $this->getState($this->getName() . '.new'); + + // We save the first stage + if ($isNew) { + // We have to add the paths, because it could be called outside of the extension context + $path = JPATH_BASE . '/components/' . $this->extension; + + $path = Path::check($path); + + Form::addFormPath($path . '/forms'); + Form::addFormPath($path . '/models/forms'); + Form::addFieldPath($path . '/models/fields'); + Form::addFormPath($path . '/model/form'); + Form::addFieldPath($path . '/model/field'); + + $form = $this->getForm(); + + $stage_id = $this->getStageForNewItem($form, $data); + + $this->workflow->createAssociation($id, $stage_id); + } + + if (!$this->workflowEnabled) { + return; + } + + // Execute transition + if (!empty($data['transition'])) { + $this->executeTransition([$id], $data['transition']); + } + } + + /** + * Batch change workflow stage or current. + * + * @param integer $value The workflow stage ID. + * @param array $pks An array of row IDs. + * @param array $contexts An array of item contexts. + * + * @return mixed An array of new IDs on success, boolean false on failure. + * + * @since 4.0.0 + */ + public function batchWorkflowStage(int $value, array $pks, array $contexts) + { + $user = Factory::getApplication()->getIdentity(); + + $workflow = Factory::getApplication()->bootComponent('com_workflow'); + + if (!$user->authorise('core.admin', $this->option)) { + $this->setError(Text::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_EXECUTE_TRANSITION')); + } + + // Get workflow stage information + $stage = $workflow->getMVCFactory()->createTable('Stage', 'Administrator'); + + if (empty($value) || !$stage->load($value)) { + Factory::getApplication()->enqueueMessage(Text::sprintf('JGLOBAL_BATCH_WORKFLOW_STAGE_ROW_NOT_FOUND'), 'error'); + + return false; + } + + if (empty($pks)) { + Factory::getApplication()->enqueueMessage(Text::sprintf('JGLOBAL_BATCH_WORKFLOW_STAGE_ROW_NOT_FOUND'), 'error'); + + return false; + } + + // Update workflow associations + return $this->workflow->updateAssociations($pks, $value); + } + + /** + * Batch change workflow stage or current. + * + * @param integer $oldId The ID of the item copied from + * @param integer $newId The ID of the new item + * + * @return null + * + * @since 4.0.0 + */ + public function workflowCleanupBatchMove($oldId, $newId) + { + // Trigger workflow plugins only if enable (will be triggered from parent class) + if ($this->workflowEnabled) { + $this->importWorkflowPlugins(); + } + + // We always need an association, so create one + $table = $this->getTable(); + + $table->load($newId); + + $catKey = $table->getColumnAlias('catid'); + + $stage_id = $this->workflow->getDefaultStageByCategory($table->$catKey); + + if (empty($stage_id)) { + return; + } + + $this->workflow->createAssociation((int) $newId, (int) $stage_id); + } + + /** + * Runs transition for item. + * + * @param array $pks Id of items to execute the transition + * @param integer $transitionId Id of transition + * + * @return boolean + * + * @since 4.0.0 + */ + public function executeTransition(array $pks, int $transitionId) + { + $result = $this->workflow->executeTransition($pks, $transitionId); + + if (!$result) { + $app = Factory::getApplication(); + + $app->enqueueMessage(Text::_('COM_CONTENT_ERROR_UPDATE_STAGE', $app::MSG_WARNING)); + + return false; + } + + return true; + } + + /** + * Import the Workflow plugins. + * + * @param Form $form A Form object. + * @param mixed $data The data expected for the form. + * + * @return void + */ + protected function importWorkflowPlugins() + { + PluginHelper::importPlugin('workflow'); + } + + /** + * Adds a transition field to the form. Can be overwritten by the child class if not needed + * + * @param Form $form A Form object. + * @param mixed $data The data expected for the form. + * + * @return void + * @since 4.0.0 + */ + protected function addTransitionField(Form $form, $data) + { + $extension = $this->extension . ($this->section ? '.' . $this->section : ''); + + $field = new \SimpleXMLElement(''); + + $field->addAttribute('name', 'transition'); + $field->addAttribute('type', $this->workflowEnabled ? 'transition' : 'hidden'); + $field->addAttribute('label', 'JWORKFLOW_TITLE'); + $field->addAttribute('extension', $extension); + + $form->setField($field); + + $table = $this->getTable(); + + $key = $table->getKeyName(); + + $id = isset($data->$key) ? $data->$key : $form->getValue($key); + + if ($id) { + // Transition field + $assoc = $this->workflow->getAssociation($id); + + if (!empty($assoc->stage_id)) { + $form->setFieldAttribute('transition', 'workflow_stage', (int) $assoc->stage_id); + } + } else { + $stage_id = $this->getStageForNewItem($form, $data); + + if (!empty($stage_id)) { + $form->setFieldAttribute('transition', 'workflow_stage', (int) $stage_id); + } + } + } + + /** + * Try to load a workflow stage for newly created items + * which does not have a workflow assigned yet. If the category is not the + * carrier, overwrite it on your model and deliver your own carrier. + * + * @param Form $form A Form object. + * @param mixed $data The data expected for the form. + * + * @return boolean|integer An integer, holding the stage ID or false + * @since 4.0.0 + */ + protected function getStageForNewItem(Form $form, $data) + { + $table = $this->getTable(); + + $hasKey = $table->hasField('catid'); + + if (!$hasKey) { + return false; + } + + $catKey = $table->getColumnAlias('catid'); + + $field = $form->getField($catKey); + + if (!$field) { + return false; + } + + $catId = isset(((object) $data)->$catKey) ? ((object) $data)->$catKey : $form->getValue($catKey); + + // Try to get the category from the html code of the field + if (empty($catId)) { + $catId = $field->getAttribute('default', null); + + if (!$catId) { + // Choose the first category available + $catOptions = $field->options; + + if ($catOptions && !empty($catOptions[0]->value)) { + $catId = (int) $catOptions[0]->value; + } + } + } + + if (empty($catId)) { + return false; + } + + return $this->workflow->getDefaultStageByCategory($catId); + } } From ab22bb748a713cdcac580afc42c9b6acb49c5e13 Mon Sep 17 00:00:00 2001 From: Joomla! Bot Date: Mon, 27 Jun 2022 23:38:21 +0200 Subject: [PATCH 85/85] Phase 2 convert BRANCH to PSR-12 --- .../com_content/src/Model/ArticlesModel.php | 8 ++------ .../com_modules/src/Extension/ModulesComponent.php | 10 ++++------ .../com_modules/src/Helper/ModulesHelper.php | 2 -- .../components/com_modules/src/Model/ModuleModel.php | 2 -- .../com_modules/src/Model/ModulesModel.php | 12 ++++-------- .../com_modules/src/View/Modules/HtmlView.php | 7 ++----- libraries/src/MVC/Model/WorkflowBehaviorTrait.php | 2 -- 7 files changed, 12 insertions(+), 31 deletions(-) diff --git a/administrator/components/com_content/src/Model/ArticlesModel.php b/administrator/components/com_content/src/Model/ArticlesModel.php index d467512173bea..dd6631448dc5a 100644 --- a/administrator/components/com_content/src/Model/ArticlesModel.php +++ b/administrator/components/com_content/src/Model/ArticlesModel.php @@ -10,8 +10,6 @@ namespace Joomla\Component\Content\Administrator\Model; -\defined('_JEXEC') or die; - use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\Language\Associations; @@ -418,10 +416,8 @@ protected function getListQuery() } $query->where('(' . implode(' OR ', $subCatItemsWhere) . ')'); - } - - // Case: Using only the by level filter - elseif ($level = (int) $level) { + } elseif ($level = (int) $level) { + // Case: Using only the by level filter $query->where($db->quoteName('c.level') . ' <= :level') ->bind(':level', $level, ParameterType::INTEGER); } diff --git a/administrator/components/com_modules/src/Extension/ModulesComponent.php b/administrator/components/com_modules/src/Extension/ModulesComponent.php index 4bdccd860df3a..ff167c5b4ebe2 100644 --- a/administrator/components/com_modules/src/Extension/ModulesComponent.php +++ b/administrator/components/com_modules/src/Extension/ModulesComponent.php @@ -10,8 +10,6 @@ namespace Joomla\Component\Modules\Administrator\Extension; -\defined('JPATH_PLATFORM') or die; - use Joomla\CMS\Factory; use Joomla\CMS\Extension\BootableExtensionInterface; use Joomla\CMS\Extension\MVCComponent; @@ -48,7 +46,7 @@ class ModulesComponent extends MVCComponent implements * * @since __DEPLOY_VERSION__ */ - const CONDITION_NAMES = [ + public const CONDITION_NAMES = [ self::CONDITION_PUBLISHED => 'JPUBLISHED', self::CONDITION_UNPUBLISHED => 'JUNPUBLISHED', self::CONDITION_TRASHED => 'JTRASHED', @@ -59,21 +57,21 @@ class ModulesComponent extends MVCComponent implements * * @since __DEPLOY_VERSION__ */ - const CONDITION_PUBLISHED = 1; + public const CONDITION_PUBLISHED = 1; /** * The unpublished condition * * @since __DEPLOY_VERSION__ */ - const CONDITION_UNPUBLISHED = 0; + public const CONDITION_UNPUBLISHED = 0; /** * The trashed condition * * @since __DEPLOY_VERSION__ */ - const CONDITION_TRASHED = -2; + public const CONDITION_TRASHED = -2; /** diff --git a/administrator/components/com_modules/src/Helper/ModulesHelper.php b/administrator/components/com_modules/src/Helper/ModulesHelper.php index 4c4f1f1cea8bb..fd9d8057f22c4 100644 --- a/administrator/components/com_modules/src/Helper/ModulesHelper.php +++ b/administrator/components/com_modules/src/Helper/ModulesHelper.php @@ -10,8 +10,6 @@ namespace Joomla\Component\Modules\Administrator\Helper; -\defined('_JEXEC') or die; - use Joomla\CMS\Factory; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; diff --git a/administrator/components/com_modules/src/Model/ModuleModel.php b/administrator/components/com_modules/src/Model/ModuleModel.php index cfbed6597a4ac..585207b69941f 100644 --- a/administrator/components/com_modules/src/Model/ModuleModel.php +++ b/administrator/components/com_modules/src/Model/ModuleModel.php @@ -10,8 +10,6 @@ namespace Joomla\Component\Modules\Administrator\Model; -\defined('_JEXEC') or die; - use Joomla\CMS\Application\ApplicationHelper; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; diff --git a/administrator/components/com_modules/src/Model/ModulesModel.php b/administrator/components/com_modules/src/Model/ModulesModel.php index b3877a96269d2..a09248347d1bd 100644 --- a/administrator/components/com_modules/src/Model/ModulesModel.php +++ b/administrator/components/com_modules/src/Model/ModulesModel.php @@ -10,8 +10,6 @@ namespace Joomla\Component\Modules\Administrator\Model; -\defined('_JEXEC') or die; - use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\Language\Text; @@ -101,9 +99,8 @@ protected function populateState($ordering = 'a.position', $direction = 'asc') if ($app->isClient('site') && $layout === 'modal') { $this->setState('filter.language', 'current'); $this->setState('filter.state', 1); - } - // If in backend (modal or not) we get the same fields from the user request. - else { + } else { + // If in backend (modal or not) we get the same fields from the user request. $this->setState('filter.language', $this->getUserStateFromRequest($this->context . '.filter.language', 'filter_language', '', 'string')); $this->setState('filter.state', $this->getUserStateFromRequest($this->context . '.filter.state', 'filter_state', '', 'string')); } @@ -407,9 +404,8 @@ protected function getListQuery() // If user selected the modules not assigned to any page (menu item). if ((int) $menuItemId === -1) { $query->having('MIN(' . $db->quoteName('mm.menuid') . ') IS NULL'); - } - // If user selected the modules assigned to some particular page (menu item). - else { + } else { + // If user selected the modules assigned to some particular page (menu item). // Modules in "All" pages. $subQuery1 = $db->getQuery(true); $subQuery1->select('MIN(' . $db->quoteName('menuid') . ')') diff --git a/administrator/components/com_modules/src/View/Modules/HtmlView.php b/administrator/components/com_modules/src/View/Modules/HtmlView.php index 94a320527f3dc..a9710096b4c0d 100644 --- a/administrator/components/com_modules/src/View/Modules/HtmlView.php +++ b/administrator/components/com_modules/src/View/Modules/HtmlView.php @@ -10,8 +10,6 @@ namespace Joomla\Component\Modules\Administrator\View\Modules; -\defined('_JEXEC') or die; - use Joomla\CMS\Factory; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Helper\ContentHelper; @@ -151,9 +149,8 @@ public function display($tpl = null) unset($this->activeFilters['language']); $this->filterForm->removeField('language', 'filter'); } - } - // If in modal layout. - else { + } else { + // If in modal layout. // Client id selector should not exist. $this->filterForm->removeField('client_id', ''); diff --git a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php index 2419fb44b074b..5d5527f252ad3 100644 --- a/libraries/src/MVC/Model/WorkflowBehaviorTrait.php +++ b/libraries/src/MVC/Model/WorkflowBehaviorTrait.php @@ -9,8 +9,6 @@ namespace Joomla\CMS\MVC\Model; -\defined('JPATH_PLATFORM') or die; - use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\Filesystem\Path;