updated core and modules

This commit is contained in:
Bachir Soussi Chiadmi
2017-09-09 16:27:51 +02:00
parent 027aa99b32
commit 41863f872c
7810 changed files with 318922 additions and 83631 deletions
@@ -3,8 +3,8 @@
namespace Drupal\features\Entity;
use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\features\FeaturesAssignmentMethodInterface;
use Drupal\features\FeaturesBundleInterface;
use Drupal\Core\Site\Settings;
/**
* Defines a features bundle.
@@ -63,7 +63,7 @@ class FeaturesBundle extends ConfigEntityBase implements FeaturesBundleInterface
/**
* @var bool
*/
protected $is_profile;
protected $is_profile = FALSE;
public function id() {
// @todo Convert it to $this->id in the long run.
@@ -109,7 +109,11 @@ class FeaturesBundle extends ConfigEntityBase implements FeaturesBundleInterface
* {@inheritdoc}
*/
public function getFullName($short_name) {
if ($this->isDefault() || $this->inBundle($short_name)) {
if ($this->isDefault() ||
// If it's already prefixed, don't repeat the prefix.
$this->inBundle($short_name) ||
// If we are a profile, don't duplicate the bundle if same as profile.
$this->isProfilePackage($short_name)) {
return $short_name;
}
else {
@@ -174,7 +178,8 @@ class FeaturesBundle extends ConfigEntityBase implements FeaturesBundleInterface
*/
public function getProfileName() {
$name = $this->isProfile() ? $this->profile_name : '';
return !empty($name) ? $name : drupal_get_profile();
// Use Settings::get to fetch current profile name so we can easily test.
return !empty($name) ? $name : Settings::get('install_profile');
}
/**
@@ -5,7 +5,7 @@ namespace Drupal\features;
use Drupal\Component\Plugin\PluginManagerInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\ExtensionInstallStorage;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Config\StorageInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\features\Entity\FeaturesBundle;
@@ -45,11 +45,11 @@ class FeaturesAssigner implements FeaturesAssignerInterface {
protected $configStorage;
/**
* The entity manager.
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityManagerInterface
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityManager;
protected $entityTypeManager;
/**
* Local cache for package assignment method instances.
@@ -79,17 +79,17 @@ class FeaturesAssigner implements FeaturesAssignerInterface {
* The features manager.
* @param \Drupal\Component\Plugin\PluginManagerInterface $assigner_manager
* The package assignment methods plugin manager.
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The configuration factory.
* @param \Drupal\Core\Config\StorageInterface $config_storage
* The configuration factory.
*/
public function __construct(FeaturesManagerInterface $features_manager, PluginManagerInterface $assigner_manager, EntityManagerInterface $entity_manager, ConfigFactoryInterface $config_factory, StorageInterface $config_storage) {
public function __construct(FeaturesManagerInterface $features_manager, PluginManagerInterface $assigner_manager, EntityTypeManagerInterface $entity_type_manager, ConfigFactoryInterface $config_factory, StorageInterface $config_storage) {
$this->featuresManager = $features_manager;
$this->assignerManager = $assigner_manager;
$this->entityManager = $entity_manager;
$this->entityTypeManager = $entity_type_manager;
$this->configFactory = $config_factory;
$this->configStorage = $config_storage;
$this->bundles = $this->getBundleList();
@@ -184,7 +184,7 @@ class FeaturesAssigner implements FeaturesAssignerInterface {
$instance = $this->assignerManager->createInstance($method_id, array());
$instance->setFeaturesManager($this->featuresManager);
$instance->setAssigner($this);
$instance->setEntityManager($this->entityManager);
$instance->setEntityTypeManager($this->entityTypeManager);
$instance->setConfigFactory($this->configFactory);
$this->methods[$method_id] = $instance;
}
@@ -262,7 +262,7 @@ class FeaturesAssigner implements FeaturesAssignerInterface {
public function getBundleList() {
if (empty($this->bundles)) {
$this->bundles = array();
foreach ($this->entityManager->getStorage('features_bundle')->loadMultiple() as $machine_name => $bundle) {
foreach ($this->entityTypeManager->getStorage('features_bundle')->loadMultiple() as $machine_name => $bundle) {
$this->bundles[$machine_name] = $bundle;
}
}
@@ -297,7 +297,7 @@ class FeaturesAssigner implements FeaturesAssignerInterface {
// config file.
$ext_storage = new ExtensionInstallStorage($this->configStorage);
$record = $ext_storage->read('features.bundle.default');
$bundle_storage = $this->entityManager->getStorage('features_bundle');
$bundle_storage = $this->entityTypeManager->getStorage('features_bundle');
$default = $bundle_storage->createFromStorageRecord($record);
}
@@ -305,6 +305,7 @@ class FeaturesAssigner implements FeaturesAssignerInterface {
$bundle = $default->createDuplicate();
$bundle->setMachineName($machine_name);
$name = !empty($name) ? $name : $machine_name;
$bundle->setName($name);
if (isset($description)) {
$bundle->setDescription($description);
@@ -3,7 +3,7 @@
namespace Drupal\features;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Plugin\PluginBase;
/**
@@ -25,11 +25,11 @@ abstract class FeaturesAssignmentMethodBase extends PluginBase implements Featur
protected $assigner;
/**
* The entity manager.
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityManagerInterface
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityManager;
protected $entityTypeManager;
/**
* The configuration factory.
@@ -55,8 +55,8 @@ abstract class FeaturesAssignmentMethodBase extends PluginBase implements Featur
/**
* {@inheritdoc}
*/
public function setEntityManager(EntityManagerInterface $entity_manager) {
$this->entityManager = $entity_manager;
public function setEntityTypeManager(EntityTypeManagerInterface $entity_type_manager) {
$this->entityTypeManager = $entity_type_manager;
}
/**
@@ -4,7 +4,7 @@ namespace Drupal\features;
use Drupal\Component\Plugin\PluginInspectionInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
/**
* Interface for package assignment classes.
@@ -31,10 +31,10 @@ interface FeaturesAssignmentMethodInterface extends PluginInspectionInterface {
/**
* Injects the entity manager.
*
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager to be used to retrieve entity information.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager to be used to retrieve entity information.
*/
public function setEntityManager(EntityManagerInterface $entity_manager);
public function setEntityTypeManager(EntityTypeManagerInterface $entity_type_manager);
/**
* Injects the configuration factory.
@@ -3,30 +3,78 @@
namespace Drupal\features;
use Drupal\Core\Config\ConfigInstaller;
use Drupal\Core\Config\ConfigInstallerInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\StorageInterface;
use Drupal\Core\Config\TypedConfigManagerInterface;
use Drupal\Core\Config\ConfigManagerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
* Class for customizing the test for pre existing configuration.
*
* Copy of ConfigInstaller with findPreExistingConfiguration() modified to
* allow Feature modules to be installed.
* Decorates the ConfigInstaller with findPreExistingConfiguration() modified
* to allow Feature modules to be installed.
*/
class FeaturesConfigInstaller extends ConfigInstaller {
/**
* The configuration installer.
*
* @var \Drupal\Core\Config\ConfigInstallerInterface
*/
protected $configInstaller;
/**
* The features manager.
*
* @var \Drupal\features\FeaturesManagerInterface
*/
protected $featuresManager;
/**
* Constructs the configuration installer.
*
* @param \Drupal\Core\Config\ConfigInstallerInterface $config_installer
* The configuration installer.
* @param \Drupal\features\FeaturesManagerInterface $features_manager
* The features manager.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The configuration factory.
* @param \Drupal\Core\Config\StorageInterface $active_storage
* The active configuration storage.
* @param \Drupal\Core\Config\TypedConfigManagerInterface $typed_config
* The typed configuration manager.
* @param \Drupal\Core\Config\ConfigManagerInterface $config_manager
* The configuration manager.
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
* The event dispatcher.
*/
public function __construct(ConfigInstallerInterface $config_installer, FeaturesManagerInterface $features_manager, ConfigFactoryInterface $config_factory, StorageInterface $active_storage, TypedConfigManagerInterface $typed_config, ConfigManagerInterface $config_manager, EventDispatcherInterface $event_dispatcher) {
$this->configInstaller = $config_installer;
$this->featuresManager = $features_manager;
list($major, $minor, ) = explode('.', \Drupal::VERSION);
if ($major == 8 && $minor > 2) {
// D8.3 added the %install_profile% argument.
$install_profile = drupal_get_profile();
parent::__construct($config_factory, $active_storage, $typed_config, $config_manager, $event_dispatcher, $install_profile);
}
else {
parent::__construct($config_factory, $active_storage, $typed_config, $config_manager, $event_dispatcher);
}
}
/**
* {@inheritdoc}
*/
protected function findPreExistingConfiguration(StorageInterface $storage) {
// CHANGE START
// Override
// Drupal\Core\Config\ConfigInstaller::findPreExistingConfiguration().
// Allow config that already exists coming from Features.
/** @var \Drupal\features\FeaturesManagerInterface $manager */
$manager = \Drupal::service('features.manager');
$features_config = array_keys($manager->listExistingConfig());
$features_config = array_keys($this->featuresManager->listExistingConfig());
// Map array so we can use isset instead of in_array for faster access.
$features_config = array_combine($features_config, $features_config);
// CHANGE END.
$existing_configuration = array();
// Gather information about all the supported collections.
$collection_info = $this->configManager->getConfigCollectionInfo();
@@ -36,10 +84,8 @@ class FeaturesConfigInstaller extends ConfigInstaller {
$active_storage = $this->getActiveStorages($collection);
foreach ($config_to_create as $config_name) {
if ($active_storage->exists($config_name)) {
// CHANGE START
// Test if config is part of a Feature package.
if (!isset($features_config[$config_name])) {
// CHANGE END.
$existing_configuration[$collection][] = $config_name;
}
}
@@ -48,4 +94,16 @@ class FeaturesConfigInstaller extends ConfigInstaller {
return $existing_configuration;
}
/**
* Creates configuration in a collection based on the provided list.
*
* @param string $collection
* The configuration collection.
* @param array $config_to_create
* An array of configuration data to create, keyed by name.
*/
public function createConfiguration($collection, array $config_to_create) {
return parent::createConfiguration($collection, $config_to_create);
}
}
@@ -82,7 +82,11 @@ abstract class FeaturesGenerationMethodBase implements FeaturesGenerationMethodI
// If this is the profile, its directory is already assigned.
if (!isset($bundle) || !$bundle->isProfilePackage($package->getMachineName())) {
$package->setDirectory($package->getDirectory() . '/' . $full_name);
$current_path = $package->getDirectory();
if (strpos($current_path, $full_name) < strlen($current_path) - strlen($full_name)) {
// Only append package name if it isn't already there.
$package->setDirectory($package->getDirectory() . '/' . $full_name);
}
}
$this->preparePackage($package, $existing_packages, $bundle);
@@ -68,10 +68,8 @@ class FeaturesInstallStorage extends ExtensionInstallStorage {
$listing = new ExtensionDiscovery(\Drupal::root());
// CHANGED START: Add profile directories for any bundles that use a profile.
$profile_directories = [];
if ($profile) {
$profile_directories[] = drupal_get_path('profile', $profile);
}
$listing->setProfileDirectoriesFromSettings();
$profile_directories = $listing->getProfileDirectories();
if ($this->includeProfile) {
// Add any profiles used in bundles.
/** @var \Drupal\features\FeaturesAssignerInterface $assigner */
@@ -8,12 +8,13 @@ use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\ConfigManagerInterface;
use Drupal\Core\Config\InstallStorage;
use Drupal\Core\Config\StorageInterface;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Extension\Extension;
use Drupal\Core\Extension\ExtensionDiscovery;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\config_update\ConfigRevertInterface;
/**
* The FeaturesManager provides helper functions for building packages.
@@ -22,11 +23,11 @@ class FeaturesManager implements FeaturesManagerInterface {
use StringTranslationTrait;
/**
* The entity manager.
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityManagerInterface
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityManager;
protected $entityTypeManager;
/**
* The target storage.
@@ -63,6 +64,13 @@ class FeaturesManager implements FeaturesManagerInterface {
*/
protected $moduleHandler;
/**
* The config reverter.
*
* @var \Drupal\config_update\ConfigRevertInterface
*/
protected $configReverter;
/**
* The Features settings.
*
@@ -117,8 +125,8 @@ class FeaturesManager implements FeaturesManagerInterface {
*
* @param string $root
* The app root.
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The configuration factory.
* @param \Drupal\Core\Config\StorageInterface $config_storage
@@ -127,16 +135,18 @@ class FeaturesManager implements FeaturesManagerInterface {
* The configuration manager.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
* @param \Drupal\config_update\ConfigRevertInterface $config_reverter
*/
public function __construct($root, EntityManagerInterface $entity_manager, ConfigFactoryInterface $config_factory,
public function __construct($root, EntityTypeManagerInterface $entity_type_manager, ConfigFactoryInterface $config_factory,
StorageInterface $config_storage, ConfigManagerInterface $config_manager,
ModuleHandlerInterface $module_handler) {
ModuleHandlerInterface $module_handler, ConfigRevertInterface $config_reverter) {
$this->root = $root;
$this->entityManager = $entity_manager;
$this->entityTypeManager = $entity_type_manager;
$this->configStorage = $config_storage;
$this->configManager = $config_manager;
$this->moduleHandler = $module_handler;
$this->configFactory = $config_factory;
$this->configReverter = $config_reverter;
$this->settings = $config_factory->getEditable('features.settings');
$this->extensionStorages = new FeaturesExtensionStorages($this->configStorage);
$this->extensionStorages->addStorage(InstallStorage::CONFIG_INSTALL_DIRECTORY);
@@ -146,6 +156,15 @@ class FeaturesManager implements FeaturesManagerInterface {
$this->configCollection = [];
}
/**
* {@inheritdoc}
*/
public function setRoot($root) {
$this->root = $root;
// Clear cache.
$this->featureInfoCache = [];
}
/**
* {@inheritdoc}
*/
@@ -168,7 +187,7 @@ class FeaturesManager implements FeaturesManagerInterface {
return $name;
}
$definition = $this->entityManager->getDefinition($type);
$definition = $this->entityTypeManager->getDefinition($type);
$prefix = $definition->getConfigPrefix() . '.';
return $prefix . $name;
}
@@ -182,12 +201,12 @@ class FeaturesManager implements FeaturesManagerInterface {
'name_short' => '',
);
$prefix = FeaturesManagerInterface::SYSTEM_SIMPLE_CONFIG . '.';
if (strpos($fullname, $prefix)) {
if (strpos($fullname, $prefix) !== FALSE) {
$result['type'] = FeaturesManagerInterface::SYSTEM_SIMPLE_CONFIG;
$result['name_short'] = substr($fullname, strlen($prefix));
}
else {
foreach ($this->entityManager->getDefinitions() as $entity_type => $definition) {
foreach ($this->entityTypeManager->getDefinitions() as $entity_type => $definition) {
if ($definition->isSubclassOf('Drupal\Core\Config\Entity\ConfigEntityInterface')) {
$prefix = $definition->getConfigPrefix() . '.';
if (strpos($fullname, $prefix) === 0) {
@@ -277,6 +296,26 @@ class FeaturesManager implements FeaturesManagerInterface {
}
}
/**
* {@inheritdoc}
*/
public function loadPackage($module_name, $any = FALSE) {
$package = $this->getPackage($module_name);
// Load directly from module if packages are not loaded or
// if we want to include ANY module regardless of its a feature.
if ((empty($this->packages) || $any) && !isset($package)) {
$module_list = $this->moduleHandler->getModuleList();
if (!empty($module_list[$module_name])) {
$extension = $module_list[$module_name];
$package = $this->initPackageFromExtension($extension);
$config = $this->listExtensionConfig($extension);
$package->setConfigOrig($config);
$package->setStatus(FeaturesManagerInterface::STATUS_INSTALLED);
}
}
return $package;
}
/**
* {@inheritdoc}
*/
@@ -347,7 +386,7 @@ class FeaturesManager implements FeaturesManagerInterface {
* {@inheritdoc}
*/
public function getExtensionInfo(Extension $extension) {
return \Drupal::service('info_parser')->parse(\Drupal::root() . '/' . $extension->getPathname());
return \Drupal::service('info_parser')->parse($this->root . '/' . $extension->getPathname());
}
/**
@@ -385,11 +424,15 @@ class FeaturesManager implements FeaturesManagerInterface {
$machine_names[] = $bundle->getProfileName();
}
// If we are checking the default bundle, return all features.
if (isset($bundle) && $bundle->isDefault()) {
$bundle = NULL;
}
$modules = $this->getFeaturesModules($bundle);
// Filter to include only the requested packages.
$modules = array_filter($modules, function ($module) use ($bundle, $machine_names) {
$short_name = $bundle->getShortName($module->getName());
return in_array($short_name, $machine_names);
return in_array($module->getName(), $machine_names);
});
$directories = array();
@@ -411,7 +454,7 @@ class FeaturesManager implements FeaturesManagerInterface {
// modules. system_rebuild_module_data() includes only the site's install
// profile directory, while we may need to include a custom profile.
// @see _system_rebuild_module_data().
$listing = new ExtensionDiscovery(\Drupal::root());
$listing = new ExtensionDiscovery($this->root);
$profile_directories = $listing->setProfileDirectoriesFromSettings()->getProfileDirectories();
$installed_profile = $this->drupalGetProfile();
@@ -444,19 +487,10 @@ class FeaturesManager implements FeaturesManagerInterface {
$modules = $this->getAllModules();
// Filter by bundle.
if (isset($bundle)) {
$features_manager = $this;
$modules = array_filter($modules, function ($module) use ($features_manager, $bundle) {
return $features_manager->isFeatureModule($module, $bundle);
});
}
else {
// No bundle filter, but still only return "Feature" modules
$features_manager = $this;
$modules = array_filter($modules, function ($module) use ($features_manager) {
return $features_manager->isFeatureModule($module);
});
}
$features_manager = $this;
$modules = array_filter($modules, function ($module) use ($features_manager, $bundle) {
return $features_manager->isFeatureModule($module, $bundle);
});
// Filtered by installed status.
if ($installed) {
@@ -480,10 +514,14 @@ class FeaturesManager implements FeaturesManagerInterface {
* {@inheritdoc}
*/
public function initPackage($machine_name, $name = NULL, $description = '', $type = 'module', FeaturesBundleInterface $bundle = NULL, Extension $extension = NULL) {
if (!isset($this->packages[$machine_name])) {
return $this->packages[$machine_name] = $this->getPackageObject($machine_name, $name, $description, $type, $bundle, $extension);
if (isset($this->packages[$machine_name])) {
return $this->packages[$machine_name];
}
return $this->packages[$machine_name];
// Also look for existing package within the bundle
elseif (isset($bundle) && isset($this->packages[$bundle->getFullName($machine_name)])) {
return $this->packages[$bundle->getFullName($machine_name)];
}
return $this->packages[$machine_name] = $this->getPackageObject($machine_name, $name, $description, $type, $bundle, $extension);
}
/**
@@ -509,8 +547,7 @@ class FeaturesManager implements FeaturesManagerInterface {
$dependencies = [];
$type = $config->getType();
if ($type != FeaturesManagerInterface::SYSTEM_SIMPLE_CONFIG) {
$provider = $this->entityManager->getDefinition($type)
->getProvider();
$provider = $this->entityTypeManager->getDefinition($type)->getProvider();
// Ensure the provider is an installed module and not, for example, 'core'
if (isset($module_list[$provider])) {
$dependencies[] = $provider;
@@ -564,7 +601,7 @@ class FeaturesManager implements FeaturesManagerInterface {
// - it is not flagged as excluded.
$assignable = (!$item->isProviderExcluded() || $is_profile_package) && !$item->isExcluded();
// An item is assignable if it was provided by the current package
$assignable = $assignable || ($item->getProvider() == $package->getFullName());
$assignable = $assignable || ($item->getProvider() == $package->getMachineName());
$excluded_from_package = in_array($package_name, $item->getPackageExcluded());
$already_in_package = in_array($item_name, $package->getConfig());
if (($force || (!$already_assigned && $assignable && !$excluded_from_package)) && !$already_in_package) {
@@ -595,9 +632,13 @@ class FeaturesManager implements FeaturesManagerInterface {
'/block\.block\..*_page_title/',
];
$config_collection = $this->getConfigCollection();
// Reverse sort by key so that child package will claim items before parent
// package. E.g., event_registration will claim before event.
krsort($config_collection);
// Sort by key so that specific package will claim items before general
// package. E.g., event_registration and registration_event will claim
// before event.
uksort($patterns, function($a, $b) {
// Count underscores to determine specificity of the package.
return (int) (substr_count($a, '_') <= substr_count($b, '_'));
});
foreach ($patterns as $pattern => $machine_name) {
if (isset($this->packages[$machine_name])) {
foreach ($config_collection as $item_name => $item) {
@@ -608,7 +649,7 @@ class FeaturesManager implements FeaturesManagerInterface {
}
}
if (!$item->getPackage() && preg_match('/[_\-.]' . $pattern . '[_\-.]/', '.' . $item->getShortName() . '.')) {
if (!$item->getPackage() && preg_match('/(\.|-|_|^)' . $pattern . '(\.|-|_|$)/', $item->getShortName())) {
try {
$this->assignConfigPackage($machine_name, [$item_name]);
}
@@ -826,9 +867,9 @@ class FeaturesManager implements FeaturesManagerInterface {
// If no extension was passed in, look for a match.
if (!isset($extension)) {
$module_list = $this->getFeaturesModules($bundle);
$full_name = $bundle->getFullName($package->getMachineName());
if (isset($module_list[$full_name])) {
$extension = $module_list[$full_name];
$module_name = $package->getMachineName();
if (isset($module_list[$module_name])) {
$extension = $module_list[$module_name];
}
}
@@ -931,32 +972,14 @@ class FeaturesManager implements FeaturesManagerInterface {
*/
protected function addPackageFiles(Package $package) {
$config_collection = $this->getConfigCollection();
// Only add files if there is at least one piece of configuration
// present.
// Always add .info.yml and .features.yml files.
$this->addInfoFile($package);
// Only add files if there is at least one piece of configuration present.
if ($package->getConfig()) {
// Add .info.yml files.
$this->addInfoFile($package);
// Add configuration files.
foreach ($package->getConfig() as $name) {
$config = $config_collection[$name];
$data = $config->getData();
// The _core is site-specific, so don't export it.
unset($data['_core']);
// The UUID is site-specfic, so don't export it.
if ($entity_type_id = $this->configManager->getEntityTypeIdByName($name)) {
unset($data['uuid']);
}
$config->setData($data);
// User roles include all permissions currently assigned to them. To
// avoid extraneous additions, reset permissions.
if ($config->getType() == 'user_role') {
$data = $config->getData();
// Unset and not empty permissions data to prevent loss of configured
// role permissions in the event of a feature revert.
unset($data['permissions']);
$config->setData($data);
}
$package->appendFile([
'filename' => $config->getName() . '.yml',
'subdirectory' => $config->getSubdirectory(),
@@ -994,7 +1017,7 @@ class FeaturesManager implements FeaturesManagerInterface {
*/
public function listConfigTypes($bundles_only = FALSE) {
$definitions = [];
foreach ($this->entityManager->getDefinitions() as $entity_type => $definition) {
foreach ($this->entityTypeManager->getDefinitions() as $entity_type => $definition) {
if ($definition->isSubclassOf('Drupal\Core\Config\Entity\ConfigEntityInterface')) {
if (!$bundles_only || $definition->getBundleOf()) {
$definitions[$entity_type] = $definition;
@@ -1039,7 +1062,7 @@ class FeaturesManager implements FeaturesManagerInterface {
public function listConfigByType($config_type) {
// For a given entity type, load all entities.
if ($config_type && $config_type !== FeaturesManagerInterface::SYSTEM_SIMPLE_CONFIG) {
$entity_storage = $this->entityManager->getStorage($config_type);
$entity_storage = $this->entityTypeManager->getStorage($config_type);
$names = [];
foreach ($entity_storage->loadMultiple() as $entity) {
$entity_id = $entity->id();
@@ -1050,7 +1073,7 @@ class FeaturesManager implements FeaturesManagerInterface {
// Handle simple configuration.
else {
$definitions = [];
foreach ($this->entityManager->getDefinitions() as $entity_type => $definition) {
foreach ($this->entityTypeManager->getDefinitions() as $entity_type => $definition) {
if ($definition->isSubclassOf('Drupal\Core\Config\Entity\ConfigEntityInterface')) {
$definitions[$entity_type] = $definition;
}
@@ -1303,4 +1326,57 @@ class FeaturesManager implements FeaturesManagerInterface {
return $features_info;
}
/**
* {@inheritdoc}
*/
public function createConfiguration(array $config_to_create) {
$existing_config = $this->getConfigCollection();
// If config data is not specified, load it from the extension storage.
foreach ($config_to_create as $name => $item) {
if (empty($item)) {
$config = $this->configReverter->getFromExtension('', $name);
// For testing purposes, if it couldn't load from a module, get config
// from the cached Config Collection
if (empty($config) && isset($existing_config[$name])) {
$config = $existing_config[$name]->getData();
}
$config_to_create[$name] = $config;
}
}
// Determine which config is new vs existing.
$existing = array_intersect_key($config_to_create, $existing_config);
$new = array_diff_key($config_to_create, $existing);
// The FeaturesConfigInstaller exposes the normally protected createConfiguration
// function from Core ConfigInstaller than handles the creation of new
// config or the changing of existing config.
/** @var \Drupal\features\FeaturesConfigInstaller $config_installer */
$config_installer = \Drupal::service('features.config.installer');
$config_installer->createConfiguration(StorageInterface::DEFAULT_COLLECTION, $config_to_create);
// Collect results for new and updated config.
$new_config = $this->getConfigCollection(TRUE);
$result['updated'] = array_intersect_key($new_config, $existing);
$result['new'] = array_intersect_key($new_config, $new);
return $result;
}
/**
* {@inheritdoc}
*/
public function import($modules, $any = FALSE) {
$result = [];
foreach ($modules as $module_name) {
$package = $this->loadPackage($module_name, $any);
$components = isset($package) ? $package->getConfigOrig() : [];
if (empty($components)) {
continue;
}
$result[$module_name] = $this->createConfiguration(array_fill_keys($components, []));
}
return $result;
}
}
@@ -33,6 +33,14 @@ interface FeaturesManagerInterface {
const STATE_DEFAULT = 0;
const STATE_OVERRIDDEN = 1;
/**
* Set the app.root.
*
* Should only be used by tests.
* @param string $root
*/
public function setRoot($root);
/**
* Returns the active config store.
*
@@ -169,6 +177,21 @@ interface FeaturesManagerInterface {
*/
public function setPackage(Package $package);
/**
* Load a specific package.
*
* Similar to getPackage but can also load modules that are not Features.
*
* @param string $module_name
* Full machine name of module.
* @param bool $any
* If TRUE then check for any module, not just a Features module.
*
* @return \Drupal\features\Package
* Package data.
*/
public function loadPackage($module_name, $any = FALSE);
/**
* Filters the supplied package list by the given namespace.
*
@@ -268,7 +291,7 @@ interface FeaturesManagerInterface {
* (optional) Bundle to use to add profile directories to the scan.
* @param \Drupal\Core\Extension\Extension $extension
* (optional) An Extension object.
* @return array
* @return \Drupal\features\Package
* The created package array.
*/
public function initPackage($machine_name, $name = NULL, $description = '', $type = 'module', FeaturesBundleInterface $bundle = NULL, Extension $extension = NULL);
@@ -507,7 +530,7 @@ interface FeaturesManagerInterface {
public function getExportInfo(Package $package, FeaturesBundleInterface $bundle = NULL);
/**
* Determines if the module is a Features package, optinally testing by
* Determines if the module is a Features package, optionally testing by
* bundle.
*
* @param \Drupal\Core\Extension\Extension $module
@@ -598,4 +621,27 @@ interface FeaturesManagerInterface {
*/
public function getFeaturesInfo(Extension $extension);
/**
* Creates configuration in a collection based on the provided list.
*
* @param array $config_to_create
* An array of configuration data to create, keyed by name.
* @return array of config imported
* 'new': list of new config created keyed by name.
* 'updated': list of updated config keyed by name.
*/
public function createConfiguration(array $config_to_create);
/**
* @param array $modules
* An array of module names to import (revert)
* @param bool $any
* Set to TRUE to import config from non-Features modules
* @return array of config imported
* keyed by name of module, then:
* 'new': list of new config created keyed by name.
* 'updated': list of updated config keyed by name.
*/
public function import($modules, $any = FALSE);
}
@@ -1,24 +0,0 @@
<?php
namespace Drupal\features;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceProviderBase;
/**
* Service provider implementation for Features to override config.installer.
*
* @ingroup container
*/
class FeaturesServiceProvider extends ServiceProviderBase {
/**
* {@inheritdoc}
*/
public function alter(ContainerBuilder $container) {
// Override the config.installer class with a new class.
$definition = $container->getDefinition('config.installer');
$definition->setClass('Drupal\features\FeaturesConfigInstaller');
}
}
@@ -151,6 +151,11 @@ class Package {
}
/**
* Return the full name of the package by prefixing it with bundle as needed
*
* NOTE: When possible, use the Bundle::getFullName method since it can
* better handle cases where a bundle is a profile.
*
* @return string
*/
public function getFullName() {
@@ -0,0 +1,63 @@
<?php
namespace Drupal\features\Plugin\FeaturesAssignment;
use Drupal\features\FeaturesAssignmentMethodBase;
use Drupal\features\FeaturesManagerInterface;
/**
* Class for excluding configuration from packages.
*
* @Plugin(
* id = "alter",
* weight = 0,
* name = @Translation("Alter"),
* description = @Translation("Alter configuration items before they are exported. Altering includes options such as removing permissions from roles."),
* config_route_name = "features.assignment_alter",
* default_settings = {
* "core" = TRUE,
* "uuid" = TRUE,
* "user_permissions" = TRUE,
* }
* )
*/
class FeaturesAssignmentAlter extends FeaturesAssignmentMethodBase {
/**
* {@inheritdoc}
*/
public function assignPackages($force = FALSE) {
$current_bundle = $this->assigner->getBundle();
$settings = $current_bundle->getAssignmentSettings($this->getPluginId());
// Alter configuration items.
if ($settings['core'] || $settings['uuid'] || $settings['user_permissions']) {
$config_collection = $this->featuresManager->getConfigCollection();
foreach ($config_collection as &$config) {
$data = $config->getData();
if ($settings['core']) {
unset($data['_core']);
}
// Unset UUID for configuration entities.
if ($settings['uuid'] && $config->getType() !== FeaturesManagerInterface::SYSTEM_SIMPLE_CONFIG) {
unset($data['uuid']);
}
// Unset permissions for user roles. Doing so facilitates packaging
// roles that may have permissions that relate to multiple packages.
if ($settings['user_permissions'] && $config->getType() == 'user_role') {
// Unset and not empty permissions data to prevent loss of configured
// role permissions in the event of a feature revert.
unset($data['permissions']);
}
$config->setData($data);
}
// Clean up the $config pass by reference.
unset($config);
// Register the updated data.
$this->featuresManager->setConfigCollection($config_collection);
}
}
}
@@ -49,12 +49,11 @@ class FeaturesAssignmentBaseType extends FeaturesAssignmentMethodBase {
catch (\Exception $exception) {
\Drupal::logger('features')->error($exception->getMessage());
}
$this->featuresManager->assignConfigDependents([$item_name]);
}
}
}
$entity_types = $this->entityManager->getDefinitions();
$entity_types = $this->entityTypeManager->getDefinitions();
$content_base_types = $settings['types']['content'];
foreach ($content_base_types as $entity_type_id) {
@@ -29,8 +29,8 @@ class FeaturesAssignmentCoreType extends FeaturesAssignmentMethodBase {
$machine_name = 'core';
$name = $this->t('Core');
$description = $this->t('Provides core components required by other features.');
$this->featuresManager->initPackage($machine_name, $name, $description, 'module', $current_bundle);
$this->assignPackageByConfigTypes($machine_name, $force);
$package = $this->featuresManager->initPackage($machine_name, $name, $description, 'module', $current_bundle);
$this->assignPackageByConfigTypes($package->getMachineName(), $force);
}
@@ -11,7 +11,7 @@ use Drupal\features\FeaturesAssignmentMethodBase;
* id = "exclude",
* weight = -5,
* name = @Translation("Exclude"),
* description = @Translation("Exclude configuration items from packaging by various methods including by configuration type."),
* description = @Translation("Exclude configuration items from packaging by various methods including by configuration type. When configuration is excluded, it won't be automatically reassigned to other packages."),
* config_route_name = "features.assignment_exclude",
* default_settings = {
* "curated" = FALSE,
@@ -83,8 +83,9 @@ class FeaturesAssignmentExclude extends FeaturesAssignmentMethodBase {
if ($module_namespace) {
$modules = $this->featuresManager->getFeaturesModules($current_bundle);
foreach ($modules as $extension) {
// Only make exception for non-exported modules
if (!empty($exclude_module['namespace_any']) || !isset($all_modules[$extension->getName()])) {
// Only make exception for uninstalled modules or
// if namespace_any is set
if (!empty($exclude_module['namespace_any']) || !$this->featuresManager->extensionEnabled($extension)) {
$extension_list = array_merge($extension_list, $this->featuresManager->listExtensionConfig($extension));
}
}
@@ -11,7 +11,7 @@ use Drupal\features\FeaturesAssignmentMethodBase;
* id = "namespace",
* weight = 0,
* name = @Translation("Namespace"),
* description = @Translation("Add to packages configuration with a machine name containing that package's machine name."),
* description = @Translation("Add config to packages that contain that package's machine name."),
* )
*/
class FeaturesAssignmentNamespace extends FeaturesAssignmentMethodBase {
@@ -19,8 +19,20 @@ class FeaturesAssignmentNamespace extends FeaturesAssignmentMethodBase {
* {@inheritdoc}
*/
public function assignPackages($force = FALSE) {
$packages = array_keys($this->featuresManager->getPackages());
$this->featuresManager->assignConfigByPattern(array_combine($packages, $packages));
$packages = $this->featuresManager->getPackages();
$current_bundle = $this->assigner->getBundle();
// Build an array of patterns.
// Keys are short names while values are full machine names.
// We need full names because existing packages may receive machine names
// prefixed with a bundle name.
$patterns = [];
foreach ($packages as $package) {
$machine_name = $package->getMachineName();
$pattern = $current_bundle->getShortName($machine_name);
$patterns[$pattern] = $machine_name;
}
$this->featuresManager->assignConfigByPattern($patterns);
}
}
@@ -29,8 +29,8 @@ class FeaturesAssignmentSiteType extends FeaturesAssignmentMethodBase {
$machine_name = 'site';
$name = $this->t('Site');
$description = $this->t('Provides site components.');
$this->featuresManager->initPackage($machine_name, $name, $description, 'module', $current_bundle);
$this->assignPackageByConfigTypes($machine_name, $force);
$package = $this->featuresManager->initPackage($machine_name, $name, $description, 'module', $current_bundle);
$this->assignPackageByConfigTypes($package->getMachineName(), $force);
}
}
@@ -22,6 +22,13 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
*/
class FeaturesGenerationArchive extends FeaturesGenerationMethodBase implements ContainerFactoryPluginInterface {
/**
* The app root.
*
* @var string
*/
protected $root;
/**
* The CSRF token generator.
*
@@ -32,10 +39,13 @@ class FeaturesGenerationArchive extends FeaturesGenerationMethodBase implements
/**
* Creates a new FeaturesGenerationArchive instance.
*
* @param string $root
* The app root.
* @param \Drupal\Core\Access\CsrfTokenGenerator $csrf_token
* The CSRF token generator.
*/
public function __construct(\Drupal\Core\Access\CsrfTokenGenerator $csrf_token) {
public function __construct($root, \Drupal\Core\Access\CsrfTokenGenerator $csrf_token) {
$this->root = $root;
$this->csrfToken = $csrf_token;
}
@@ -44,6 +54,7 @@ class FeaturesGenerationArchive extends FeaturesGenerationMethodBase implements
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$container->get('app.root'),
$container->get('csrf_token')
);
}
@@ -66,8 +77,19 @@ class FeaturesGenerationArchive extends FeaturesGenerationMethodBase implements
protected function preparePackage(Package $package, array $existing_packages, FeaturesBundleInterface $bundle = NULL) {
if (isset($existing_packages[$package->getMachineName()])) {
$existing_directory = $existing_packages[$package->getMachineName()];
}
else {
$existing_directory = $package->getDirectory();
}
$existing_directory = $this->root . '/' . $existing_directory;
if (is_dir($existing_directory)) {
// Scan for all files.
$files = file_scan_directory($existing_directory, '/.*/');
// Skip any existing .features.yml as it will be replaced.
$exclude_files = [
$package->getMachineName() . '.features',
];
foreach ($files as $file) {
// Skip files in the any existing configuration directory, as these
// will be replaced.
@@ -83,7 +105,7 @@ class FeaturesGenerationArchive extends FeaturesGenerationMethodBase implements
$package->setFiles($files);
}
// Read in remaining files.
else {
elseif (!in_array($file->name, $exclude_files)) {
// Determine if the file is within a subdirectory of the
// extension's directory.
$file_directory = dirname($file->uri);
@@ -3,6 +3,7 @@
namespace Drupal\features\Plugin\FeaturesGeneration;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\features\FeaturesGenerationMethodBase;
use Drupal\features\FeaturesBundleInterface;
use Drupal\features\Package;
@@ -32,14 +33,21 @@ class FeaturesGenerationWrite extends FeaturesGenerationMethodBase implements Co
*/
protected $root;
/**
* The file_system service.
* @var \Drupal\Core\File\FileSystemInterface
*/
protected $fileSystem;
/**
* Creates a new FeaturesGenerationWrite instance.
*
* @param string $root
* The app root.
*/
public function __construct($root) {
public function __construct($root, FileSystemInterface $fileSystem) {
$this->root = $root;
$this->fileSystem = $fileSystem;
}
/**
@@ -47,7 +55,8 @@ class FeaturesGenerationWrite extends FeaturesGenerationMethodBase implements Co
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$container->get('app.root')
$container->get('app.root'),
$container->get('file_system')
);
}
@@ -65,19 +74,22 @@ class FeaturesGenerationWrite extends FeaturesGenerationMethodBase implements Co
// If this package is already present, prepare files.
if (isset($existing_packages[$package->getMachineName()])) {
$existing_directory = $existing_packages[$package->getMachineName()];
$package->setDirectory($existing_directory);
}
else {
$existing_directory = $package->getDirectory();
}
// Merge in the info file.
$info_file_uri = $this->root . '/' . $existing_directory . '/' . $package->getMachineName() . '.info.yml';
if (file_exists($info_file_uri)) {
$files = $package->getFiles();
$files['info']['string'] = $this->mergeInfoFile($package->getFiles()['info']['string'], $info_file_uri);
$package->setFiles($files);
}
// Merge in the info file.
$info_file_uri = $this->root . '/' . $existing_directory . '/' . $package->getMachineName() . '.info.yml';
if (file_exists($info_file_uri)) {
$files = $package->getFiles();
$files['info']['string'] = $this->mergeInfoFile($package->getFiles()['info']['string'], $info_file_uri);
$package->setFiles($files);
// Remove the config directories, as they will be replaced.
foreach (array_keys($this->featuresManager->getExtensionStorages()->getExtensionStorages()) as $directory) {
foreach (array_keys($this->featuresManager->getExtensionStorages()
->getExtensionStorages()) as $directory) {
$config_directory = $this->root . '/' . $existing_directory . '/' . $directory;
if (is_dir($config_directory)) {
file_unmanaged_delete_recursive($config_directory);
@@ -213,7 +225,7 @@ class FeaturesGenerationWrite extends FeaturesGenerationMethodBase implements Co
}
$directory = $this->root . '/' . $directory;
if (!is_dir($directory)) {
if (drupal_mkdir($directory, NULL, TRUE) === FALSE) {
if ($this->fileSystem->mkdir($directory, NULL, TRUE) === FALSE) {
throw new \Exception($this->t('Failed to create directory @directory.', ['@directory' => $directory]));
}
}
@@ -1,136 +0,0 @@
<?php
/**
* This file was generated via php core/scripts/generate-proxy-class.php 'Drupal\features\FeaturesConfigInstaller' "modules/contrib/features/src".
*/
namespace Drupal\features\ProxyClass {
/**
* Provides a proxy class for \Drupal\features\FeaturesConfigInstaller.
*
* @see \Drupal\Component\ProxyBuilder
*/
class FeaturesConfigInstaller implements \Drupal\Core\Config\ConfigInstallerInterface
{
use \Drupal\Core\DependencyInjection\DependencySerializationTrait;
/**
* The id of the original proxied service.
*
* @var string
*/
protected $drupalProxyOriginalServiceId;
/**
* The real proxied service, after it was lazy loaded.
*
* @var \Drupal\features\FeaturesConfigInstaller
*/
protected $service;
/**
* The service container.
*
* @var \Symfony\Component\DependencyInjection\ContainerInterface
*/
protected $container;
/**
* Constructs a ProxyClass Drupal proxy object.
*
* @param \Symfony\Component\DependencyInjection\ContainerInterface $container
* The container.
* @param string $drupal_proxy_original_service_id
* The service ID of the original service.
*/
public function __construct(\Symfony\Component\DependencyInjection\ContainerInterface $container, $drupal_proxy_original_service_id)
{
$this->container = $container;
$this->drupalProxyOriginalServiceId = $drupal_proxy_original_service_id;
}
/**
* Lazy loads the real service from the container.
*
* @return object
* Returns the constructed real service.
*/
protected function lazyLoadItself()
{
if (!isset($this->service)) {
$this->service = $this->container->get($this->drupalProxyOriginalServiceId);
}
return $this->service;
}
/**
* {@inheritdoc}
*/
public function installDefaultConfig($type, $name)
{
return $this->lazyLoadItself()->installDefaultConfig($type, $name);
}
/**
* {@inheritdoc}
*/
public function installOptionalConfig(\Drupal\Core\Config\StorageInterface $storage = NULL, $dependency = array (
))
{
return $this->lazyLoadItself()->installOptionalConfig($storage, $dependency);
}
/**
* {@inheritdoc}
*/
public function installCollectionDefaultConfig($collection)
{
return $this->lazyLoadItself()->installCollectionDefaultConfig($collection);
}
/**
* {@inheritdoc}
*/
public function setSourceStorage(\Drupal\Core\Config\StorageInterface $storage)
{
return $this->lazyLoadItself()->setSourceStorage($storage);
}
/**
* {@inheritdoc}
*/
public function getSourceStorage()
{
return $this->lazyLoadItself()->getSourceStorage();
}
/**
* {@inheritdoc}
*/
public function setSyncing($status)
{
return $this->lazyLoadItself()->setSyncing($status);
}
/**
* {@inheritdoc}
*/
public function isSyncing()
{
return $this->lazyLoadItself()->isSyncing();
}
/**
* {@inheritdoc}
*/
public function checkConfigurationToInstall($type, $name)
{
return $this->lazyLoadItself()->checkConfigurationToInstall($type, $name);
}
}
}