diff --git a/modules/update_helper_checklist/update_helper_checklist.module b/modules/update_helper_checklist/update_helper_checklist.module index 7e49fa1..a091820 100644 --- a/modules/update_helper_checklist/update_helper_checklist.module +++ b/modules/update_helper_checklist/update_helper_checklist.module @@ -13,6 +13,7 @@ use Drupal\Core\Url; use Drupal\update_helper_checklist\UpdateChecklist; use Symfony\Component\Yaml\Yaml; use Drupal\update_helper_checklist\Entity\Update; +use Drupal\update_helper\Updater; /** * Implements hook_checklistapi_checklist_info(). @@ -62,10 +63,10 @@ function _update_helper_checklist_checklistapi_checklist_items() { $entry = Update::load($update_key); $status = ($entry && $entry->wasSuccessfulByHook()) ? TRUE : FALSE; - if ($status && !empty($update['#description_successful'])) { + if ($entry && $status && !empty($update['#description_successful'])) { $update['#description'] .= $update['#description_successful']; } - elseif (!$status && !empty($update['#description_failed'])) { + elseif ($entry && !$status && !empty($update['#description_failed'])) { $update['#description'] .= $update['#description_failed']; } } @@ -107,6 +108,7 @@ function _update_helper_checklist_checklistapi_checklist_items() { function update_helper_checklist_modules_installed(array $modules) { /** @var \Drupal\Core\Extension\ModuleHandler $module_handler */ $module_handler = \Drupal::service('module_handler'); + $updateHelper = \Drupal::service('update_helper.updater'); $modules_checklist = []; $module_directories = $module_handler->getModuleDirectories(); @@ -120,6 +122,10 @@ function update_helper_checklist_modules_installed(array $modules) { foreach ($updates_checklist as $version_items) { foreach ($version_items as $update_hook_name => $checklist_definition) { if (is_array($checklist_definition)) { + + $status = $updateHelper->checkUpdate($module_name, $update_hook_name); + if ($status != Updater::CONFIG_ALREADY_APPLIED && $status != Updater::CONFIG_APPLIED_SUCCESSFULLY) continue; + if (!isset($modules_checklist[$module_name])) { $modules_checklist[$module_name] = []; } diff --git a/src/Updater.php b/src/Updater.php index 6f91b36..8f2ced6 100644 --- a/src/Updater.php +++ b/src/Updater.php @@ -20,6 +20,12 @@ class Updater implements UpdaterInterface { use StringTranslationTrait; + const CONFIG_NOT_FOUND = 0; + const CONFIG_ALREADY_APPLIED = 1; + const CONFIG_NOT_EXPECTED = 2; + const CONFIG_APPLIED_SUCCESSFULLY = 3; + const MODULES_FOUND = 4; + const MODULES_NOT_FOUND = 5; /** * Site configFactory object. * @@ -130,7 +136,7 @@ protected function logInfo($message) { /** * {@inheritdoc} */ - public function executeUpdate($module, $update_definition_name) { + public function executeUpdate($module, $update_definition_name, $force = FALSE) { $this->warningCount = 0; $update_definitions = $this->configHandler->loadUpdate($module, $update_definition_name); @@ -141,7 +147,7 @@ public function executeUpdate($module, $update_definition_name) { } if (!empty($update_definitions)) { - $this->executeConfigurationActions($update_definitions); + $this->executeConfigurationActions($update_definitions, $force); } // Dispatch event after update has finished. @@ -151,6 +157,44 @@ public function executeUpdate($module, $update_definition_name) { return $this->warningCount === 0; } + /** + * Check update status of configuration from update definitions. + * + * @param string $module + * Module name where update definition is saved. + * @param string $update_definition_name + * Update definition name. Usually same name as update hook. + * + * @return bool + * Returns update status. + */ + public function checkUpdate($module, $update_definition_name) { + $this->warningCount = 0; + $moduleHandler = \Drupal::service('module_handler'); + $modulesInstalled = []; + $update_definitions = $this->configHandler->loadUpdate($module, $update_definition_name); + if (isset($update_definitions[UpdateDefinitionInterface::GLOBAL_ACTIONS])) { + if (isset($update_definitions[UpdateDefinitionInterface::GLOBAL_ACTIONS][UpdateDefinitionInterface::GLOBAL_ACTION_INSTALL_MODULES])) { + $modules = $update_definitions[UpdateDefinitionInterface::GLOBAL_ACTIONS][UpdateDefinitionInterface::GLOBAL_ACTION_INSTALL_MODULES]; + foreach ($modules as $module) { + if (!$moduleHandler->moduleExists($module)) return Updater::MODULES_NOT_FOUND; + $modulesInstalled[] = $module; + } + } + unset($update_definitions[UpdateDefinitionInterface::GLOBAL_ACTIONS]); + } + + if (!empty($update_definitions)) { + return $this->executeConfigurationActions($update_definitions, FALSE, TRUE); + } + + if (empty($update_definitions) && !empty($modulesInstalled)) { + return Updater::MODULES_FOUND; + } + + return Updater::CONFIG_NOT_FOUND; + } + /** * Get array with defined global actions. * @@ -176,8 +220,15 @@ protected function executeGlobalActions(array $global_actions) { * * @param array $update_definitions * List of configurations with update definitions for them. + * @param bool $force + * Force the update. + * @param bool $checkOnly + * Check the update status and don't apply the update. + * + * @return bool + * Returns update status if checkOnly flag is set. */ - protected function executeConfigurationActions(array $update_definitions) { + protected function executeConfigurationActions(array $update_definitions, $force = FALSE, $checkOnly = FALSE) { foreach ($update_definitions as $configName => $configChange) { $update_actions = $configChange['update_actions']; @@ -198,15 +249,33 @@ protected function executeConfigurationActions(array $update_definitions) { $new_config = NestedArray::mergeDeep($new_config, $update_actions['add']); } - if ($this->updateConfig($configName, $new_config, $configChange['expected_config'], $delete_keys)) { - $this->logInfo($this->t('Configuration @configName has been successfully updated.', ['@configName' => $configName])); + $result = $this->updateConfig($configName, $new_config, $configChange['expected_config'], $delete_keys, $force, $checkOnly); + + if ($checkOnly) { + return $result; } - else { - $this->logWarning($this->t('Unable to update configuration for @configName.', ['@configName' => $configName])); + + switch ($result) { + case Updater::CONFIG_APPLIED_SUCCESSFULLY: + $this->logInfo($this->t('Configuration @configName has been successfully updated.', ['@configName' => $configName])); + break; + + case Updater::CONFIG_ALREADY_APPLIED: + $this->logWarning($this->t('Configuration @configName is already updated.', ['@configName' => $configName])); + break; + + case Updater::CONFIG_NOT_EXPECTED: + $this->logWarning($this->t('Expected current configuration for @configName is not matching. Unable to apply new config.', ['@configName' => $configName])); + break; + + case Updater::CONFIG_NOT_FOUND: + $this->logWarning($this->t('Unable to find config @configName. Skipping update.', ['@configName' => $configName])); + break; } } } + /** * Installs modules. * @@ -321,41 +390,54 @@ protected function getFlatKeys(array $nested_array) { * Only if current config is same like old config we are updating. * @param array $delete_keys * List of parent keys to remove. @see NestedArray::unsetValue() + * @param bool $force + * Force the update. + * @param bool $checkOnly + * Check the update status and don't apply the update. * * @return bool * Returns TRUE if update of configuration was successful. */ - protected function updateConfig($config_name, array $configuration, array $expected_configuration = [], array $delete_keys = []) { + protected function updateConfig($config_name, array $configuration, array $expected_configuration = [], array $delete_keys = [], $force = FALSE, $checkOnly = FALSE) { $config = $this->configFactory->getEditable($config_name); $config_data = $config->get(); + // Reset expected_config in case of force flag. + if ($force) { + $expected_configuration = []; + } + // Check that configuration exists before executing update. if (empty($config_data)) { - return FALSE; + return Updater::CONFIG_NOT_FOUND; } // Check if configuration is already in new state. $merged_data = NestedArray::mergeDeep($expected_configuration, $configuration); - if (empty(DiffArray::diffAssocRecursive($merged_data, $config_data))) { - return TRUE; + if (!$force && empty(DiffArray::diffAssocRecursive($configuration, $config_data))) { + return Updater::CONFIG_ALREADY_APPLIED; } - if (!empty($expected_configuration) && DiffArray::diffAssocRecursive($expected_configuration, $config_data)) { - return FALSE; - } + if (empty($expected_configuration) || !DiffArray::diffAssocRecursive($expected_configuration, $config_data)) { + // Delete configuration keys from config. + if($checkOnly){ + return Updater::CONFIG_APPLIED_SUCCESSFULLY; + } - // Delete configuration keys from config. - if (!empty($delete_keys)) { - foreach ($delete_keys as $key_path) { - NestedArray::unsetValue($config_data, $key_path); + if (!empty($delete_keys)) { + foreach ($delete_keys as $key_path) { + NestedArray::unsetValue($config_data, $key_path); + } } - } - $config->setData(NestedArray::mergeDeep($config_data, $configuration)); - $config->save(); + $config->setData(NestedArray::mergeDeep($config_data, $configuration)); + $config->save(); - return TRUE; + return Updater::CONFIG_APPLIED_SUCCESSFULLY; + }else{ + return Updater::CONFIG_NOT_EXPECTED; + } } }