Corrrect me if I'm wrong.
I found there is no function packed in the module to do a simple features_revert() as in D7,
This is currently I am using to revert a feature, usually I call this in hook_update_N().

<?php
function _revert_features($modules){
  module_load_include('inc', 'features','drush/features.drush');
  $config_revert = \Drupal::service('features.config_update');
  $manager = \Drupal::service('features.manager');
  foreach($modules as $module){

    $feature = _drush_features_load_feature($module, TRUE);
    $components = $feature->getConfigOrig();
    $config = $manager->getConfigCollection();
    foreach ($components as $component) {
              $item = $config[$component];
              $type = ConfigurationItem::fromConfigStringToConfigType($item->getType());
              $config_revert->revert($type, $item->getShortName());
    }

  }

}
?>

Maybe we should include this function in module.

Comments

youfei.sun created an issue. See original summary.

mpotter’s picture

Status: Active » Needs work

This is almost right.

1) You should move the line:
$config = $manager->getConfigCollection();
outside of the "foreach ($modules)..." loop since you only need to do that once.

2) Probably shouldn't depend on a function in the drush.inc file (file might not be loaded). Probably need to move the _drush_features_load_feature() into a new public method in FeaturesManager instead.

Also, would be useful to run this through coder and then submit this as a patch to add to the features.module file as a useful helpful function for people. Then we can review the patch and get it committed.

o&#039;briat’s picture

Hi,
I'm also missing this function.

I try yours but I get the following error on reverting a simple feature :
Call to a member function getType() on null in _revert_features()

I think you have to add a test on $config[$component] as found into the original drush_features_import(),

Here's my own attempt:


$module = 'features_to_revert';

use Drupal\features\ConfigurationItem;
use Drupal\features\FeaturesManagerInterface;

/** @var \Drupal\features\FeaturesManagerInterface $manager */
$manager = \Drupal::service('features.manager');
/** @var \Drupal\config_update\ConfigRevertInterface $config_revert */
$config_revert = \Drupal::service('features.config_update');

// code from _drush_features_load_feature
$feature = $manager->getPackage($module);
if (!isset($feature)) {
  // See if this is a non-features module.
  $module_handler = \Drupal::moduleHandler();
  $modules = $module_handler->getModuleList();
  if (!empty($modules[$module])) {
    $extension = $modules[$module];
    $feature = $manager->initPackageFromExtension($extension);
    $config = $manager->listExtensionConfig($extension);
    $feature->setConfig($config);
    $feature->setStatus(FeaturesManagerInterface::STATUS_INSTALLED);
  }
}

$components = $feature->getConfigOrig();
$config = $manager->getConfigCollection();
foreach ($components as $component) {
  if (!isset($config[$component])) {
    // Import missing component.
    $item = $manager->getConfigType($component);
    $type = ConfigurationItem::fromConfigStringToConfigType($item['type']);
    $config_revert->import($type, $item['name_short']);
  }
  else {
    // Revert existing component.
    $item = $config[$component];
    $type = ConfigurationItem::fromConfigStringToConfigType($item->getType());
    $config_revert->revert($type, $item->getShortName());

  }
}

But I got the following error :

Drupal\Core\Field\FieldException: Attempt to create a field myfield that does not exist on entity type node. in Drupal\field\Entity\FieldConfig->getFieldStorageDefinition() (line 286 of core\modules\field\src\Entity\FieldConfig.php).

Everything is fine using drush features-import

mpotter’s picture

Note to people wanting this and working on it, please post an actual patch to get it reviewed, tested and merged.

grzegorz.bartman’s picture

This is how I solved this problem: https://github.com/grzegorzbartman/d_application_api

mpotter’s picture

Yep, I have some other ideas on this actually and hope to get it added soon. I think it's a bit easier, but I also want to support an import() method on both Packages and Bundles. So you'll be able to say:

\Drupal::service('features.manager')->getPackage('featureName')->import();
\Drupal::service('features_assigner')->getBundle('bundleName')->import();

which is a better OOP way of doing it rather than writing a programatic helper function.

mpotter’s picture

Status: Needs work » Needs review
StatusFileSize
new17.71 KB

Here is a patch that adds a \Drupal::service('features.manager')->import($module_list) function. Also added a ::loadPackage($name) function to replace the common code used in the drush commands.

Added a test for it also. In doing the testing, also found a bug in the ::getConfigType function where it wasn't properly checking the result of strpos for simple config.

I didn't modify the drush feature-import command to use the new ::import() method because it needs to be able to prompt for confirmation of each import change, whereas the programatic method doesn't. Maybe somebody has an idea how this could better be handled to share the code. Hate to have the revert code in two places, but also don't want to burden the FeaturesManager with confirmation checking.

  • mpotter committed e030a73 on 8.x-3.x
    Issue #2741403 by mpotter: Revert(Import) a feature programmatically
    
mpotter’s picture

Status: Needs review » Fixed

Going to push this to try and get the 3.0 stable out this week. Open a new issue if you want to refactor the code to improve, but this patch worked.

Committed toe030a73.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

podarok’s picture

We've added support for reverting features into confi module https://www.drupal.org/node/2850073