diff --git a/src/Helpers/UwFeatureRevert.php b/src/Helpers/UwFeatureRevert.php new file mode 100644 index 0000000000000000000000000000000000000000..a53325e17eb78dabbc16f9ca094ba727a770a498 --- /dev/null +++ b/src/Helpers/UwFeatureRevert.php @@ -0,0 +1,203 @@ +<?php + +namespace Drupal\uw_cfg_common\Helpers; + +use Drupal\features\FeaturesManagerInterface; +use Drupal\features\ConfigurationItem; +use Drupal\features\Package; +use Drupal\config_update\ConfigRevertInterface; + +/** + * Class to perform feature revert. + */ +class UwFeatureRevert { + + /** + * Features manager. + * + * @var \Drupal\features\FeaturesManagerInterface + */ + private $featuresManager; + + /** + * Config update revert. + * + * @var \Drupal\config_update\ConfigRevertInterface + */ + private $configRevert; + + /** + * Default constructor. + * + * @param \Drupal\features\FeaturesManagerInterface $featuresManager + * Features manager. + * @param Drupal\config_update\ConfigRevertInterface $configRevert + * The config update revert. + */ + public function __construct( + FeaturesManagerInterface $featuresManager, + ConfigRevertInterface $configRevert + ) { + $this->featuresManager = $featuresManager; + $this->configRevert = $configRevert; + } + + /** + * Load the features from the module. + * + * @param array $module + * Array of modules. + * @param bool $any + * Flag for all modules. + * + * @return \Drupal\features\Package + * The list of packages. + */ + private function drushFeaturesLoadFeature(array $module, bool $any = FALSE): Package { + + // Get the features manager. + $manager = $this->featuresManager; + + // Get teh feature. + $feature = $manager->getPackage($module); + + // Check if this get any or not a feature module. + if ($any && !isset($feature)) { + + // See if this is a non-features module. + $module_handler = \Drupal::moduleHandler(); + $modules = $module_handler->getModuleList(); + + // If it is not a feature module, set it up as one. + if (!empty($modules[$module])) { + $extension = $modules[$module]; + $feature = $manager->initPackageFromExtension($extension); + $config = $manager->listExtensionConfig($extension); + $feature->setConfig($config); + $feature->setStatus(FeaturesManagerInterface::STATUS_INSTALLED); + } + } + + return $feature; + } + + /** + * Copy from file features.drush.inc. + */ + public function import($args) { + + // Determine if revert should be forced. + $force = TRUE; + + // Determine if -y was supplied. If so, we can filter out needless output + // from this command. + $skip_confirmation = TRUE; + + // Get the feature manager. + $manager = $this->featuresManager; + + // Get the config update revert. + $config_revert = $this->configRevert; + + // Parse list of arguments. + $modules = []; + + foreach ($args as $arg) { + $arg = explode(':', $arg); + $module = array_shift($arg); + $component = array_shift($arg); + + if (isset($module)) { + if (empty($component)) { + // If we received just a feature name, this means that we need all of + // its components. + $modules[$module] = TRUE; + } + elseif ($modules[$module] !== TRUE) { + if (!isset($modules[$module])) { + $modules[$module] = []; + } + $modules[$module][] = $component; + } + } + } + + // Process modules. + foreach ($modules as $module => $components_needed) { + + // Setup the modules array. + $dt_args['@module'] = $module; + + // Get the feature information. + $feature = $this->drushFeaturesLoadFeature($module, TRUE); + + // If the feature is empty, throw an error and exit. + if (empty($feature)) { + \Drupal::logger('UwFeatureRevert') + ->error('No such feature is available: @module', $dt_args); + return; + } + + // If the feature status is not set as active, throw error and exit. + if ($feature->getStatus() != FeaturesManagerInterface::STATUS_INSTALLED) { + \Drupal::logger('UwFeatureRevert') + ->error('No such feature is installed: @module', $dt_args); + return; + } + + // Forcefully revert all components of a feature. + if ($force) { + $components = $feature->getConfigOrig(); + } + // Only revert components that are detected to be Overridden. + else { + $components = $manager->detectOverrides($feature); + $missing = $manager->reorderMissing($manager->detectMissing($feature)); + // Be sure to import missing components first. + $components = array_merge($missing, $components); + } + + if (!empty($components_needed) && is_array($components_needed)) { + $components = array_intersect($components, $components_needed); + } + + if (empty($components)) { + \Drupal::logger('UwFeatureRevert') + ->notice('Current state already matches active config, aborting.'); + } + else { + $config = $manager->getConfigCollection(); + foreach ($components as $component) { + $dt_args['@component'] = $component; + if ($skip_confirmation) { + + // If there is no config for this present, import it. + if (!isset($config[$component])) { + + // Import missing component. + $item = $manager->getConfigType($component); + $type = ConfigurationItem::fromConfigStringToConfigType($item['type']); + $config_revert->import($type, $item['name_short']); + \Drupal::logger('d_application_api') + ->notice('Import @module : @component.', $dt_args); + } + else { + + // Revert existing component. + $item = $config[$component]; + $type = ConfigurationItem::fromConfigStringToConfigType($item->getType()); + $config_revert->revert($type, $item->getShortName()); + \Drupal::logger('UwFeatureRevert') + ->notice('Reverted @module : @component.', $dt_args); + } + } + else { + \Drupal::logger('UwFeatureRevert') + ->notice('Skipping @module : @component.', $dt_args); + } + } + } + } + } + +} diff --git a/uw_cfg_common.services.yml b/uw_cfg_common.services.yml index e787861646999974cfc12aa360a4a5f27c2265db..9cd4b91831bd054849fc820ba3ee072d7c1e411c 100644 --- a/uw_cfg_common.services.yml +++ b/uw_cfg_common.services.yml @@ -29,3 +29,7 @@ services: class: '\Drupal\uw_cfg_common\EventSubscriber\UwLayoutBuilderEventSubscriber' tags: - { name: 'event_subscriber' } + uw_cfg_common.features: + class: Drupal\uw_cfg_common\Helpers\UwFeatureRevert + arguments: ['@features.manager'] +