From 1efaefb15c30f24fd727c98512e760e967bd15cd Mon Sep 17 00:00:00 2001 From: webchick <drupal@webchick.net> Date: Mon, 13 Oct 2014 21:21:27 -0700 Subject: [PATCH] =?UTF-8?q?Issue=20#2235363=20by=20jhodgdon,=20jessebeach,?= =?UTF-8?q?=20alexpott,=20G=C3=A1bor=20Hojtsy:=20Document=20config=20depen?= =?UTF-8?q?dencies.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Config/Entity/ConfigDependencyManager.php | 76 +++++++++++++------ .../Core/Config/Entity/ConfigEntityBase.php | 9 ++- .../Config/Entity/ConfigEntityInterface.php | 12 ++- .../Drupal/Core/Entity/DependencyTrait.php | 29 ++++--- .../Core/Plugin/PluginDependencyTrait.php | 7 +- 5 files changed, 90 insertions(+), 43 deletions(-) diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigDependencyManager.php b/core/lib/Drupal/Core/Config/Entity/ConfigDependencyManager.php index f52aad063490..84a04627ed74 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigDependencyManager.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigDependencyManager.php @@ -14,37 +14,69 @@ * Provides a class to discover configuration entity dependencies. * * Configuration entities can depend on modules, themes and other configuration - * entities. The dependency system is used during configuration installation to - * ensure that configuration entities are imported in the correct order. For - * example, node types are created before their field storages and the field - * storages are created before their fields. + * entities. The dependency system is used during configuration installation, + * uninstallation, and synchronization to ensure that configuration entities are + * handled in the correct order. For example, node types are created before + * their fields, and both are created before the view display configuration. * - * Dependencies are stored to the configuration entity's configuration object so - * that they can be checked without the module that provides the configuration - * entity class being installed. This is important for configuration - * synchronization which needs to be able to validate configuration in the - * staging directory before the synchronization has occurred. + * If a configuration entity is provided as default configuration by an + * extension (module, theme, or profile), the extension has to depend on any + * modules or themes that the configuration depends on. For example, if a view + * configuration entity is provided by an installation profile and the view will + * not work without a certain module, the profile must declare a dependency on + * this module in its info.yml file. If you do not want your extension to always + * depend on a particular module that one of its default configuration entities + * depends on, you can use a sub-module: move the configuration entity to the + * sub-module instead of including it in the main extension, and declare the + * module dependency in the sub-module only. * - * Configuration entities determine their dependencies by implementing - * \Drupal\Core\Config\Entity\ConfigEntityInterface::calculateDependencies(). - * This method should be called from the configuration entity's implementation - * of \Drupal\Core\Entity\EntityInterface::preSave(). Implementations should use - * the helper method + * Classes for configuration entities with dependencies normally extend + * \Drupal\Core\Config\Entity\ConfigEntityBase or at least use + * \Drupal\Core\Plugin\PluginDependencyTrait to manage dependencies. The class + * must implement + * \Drupal\Core\Config\Entity\ConfigEntityInterface::calculateDependencies(), + * which should calculate (and return) the dependencies. In this method, use * \Drupal\Core\Config\Entity\ConfigEntityBase::addDependency() to add - * dependencies. All the implementations in core call the parent method - * \Drupal\Core\Config\Entity\ConfigEntityBase::calculateDependencies() which - * resets the dependencies and provides an implementation to determine the - * plugin providers for configuration entities that implement - * \Drupal\Core\Entity\EntityWithPluginBagsInterface. + * dependencies. Most implementations call + * \Drupal\Core\Config\Entity\ConfigEntityBase::calculateDependencies() since it + * provides a generic implementation that will discover dependencies due to + * plugins and third party settings. To get a configuration entity's current + * dependencies without forcing a recalculation use + * \Drupal\Core\Config\Entity\ConfigEntityInterface::getDependencies(). * - * The configuration manager service provides methods to find dependencies for - * a specified module, theme or configuration entity. + * Classes for configurable plugins are a special case. They can either declare + * their configuration dependencies using the calculateDependencies() method + * described in the paragraph above, or if they have only static dependencies, + * these can be declared using the 'config_dependencies' annotation key. + * + * Once declared properly, dependencies are saved to the configuration entity's + * configuration object so that they can be checked without the module that + * provides the configuration entity class being installed. This is important + * for configuration synchronization, which needs to be able to validate + * configuration in the staging directory before the synchronization has + * occurred. + * + * When uninstalling a module or a theme, configuration entities that are + * dependent will also be removed. This default behavior can lead to undesirable + * side effects, such as a node view mode being entirely removed when the module + * defining a field or formatter it uses is uninstalled. To prevent this, + * configuration entity classes can implement + * \Drupal\Core\Config\Entity\ConfigEntityInterface::onDependencyRemoval(), + * which allows the entity class to remove dependencies instead of being deleted + * themselves. Implementations should save the entity if dependencies have been + * successfully removed, in order to register the newly cleaned-out dependency + * list. So, in the above example, the node view mode configuration entity class + * should implement this method to remove references to formatters if the plugin + * that supplies them depends on a module that is being uninstalled. * * @see \Drupal\Core\Config\Entity\ConfigEntityInterface::calculateDependencies() * @see \Drupal\Core\Config\Entity\ConfigEntityInterface::getConfigDependencyName() + * @see \Drupal\Core\Config\Entity\ConfigEntityInterface::onDependencyRemoval() * @see \Drupal\Core\Config\Entity\ConfigEntityBase::addDependency() - * @see \Drupal\Core\Config\ConfigInstaller::installDefaultConfig() + * @see \Drupal\Core\Config\ConfigInstallerInterface::installDefaultConfig() + * @see \Drupal\Core\Config\ConfigManagerInterface::uninstall() * @see \Drupal\Core\Config\Entity\ConfigEntityDependency + * @see \Drupal\Core\Plugin\PluginDependencyTrait */ class ConfigDependencyManager { diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php index d226243a7e84..96e877b124ca 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php @@ -365,13 +365,18 @@ public function link($text = NULL, $rel = 'edit-form', array $options = []) { } /** - * {@inheritdoc} + * Overrides \Drupal\Core\Entity\DependencyTrait:addDependency(). + * + * Note that this function should only be called from implementations of + * \Drupal\Core\Config\Entity\ConfigEntityInterface::calculateDependencies(), + * as dependencies are recalculated during every entity save. + * + * @see \Drupal\Core\Config\Entity\ConfigEntityDependency::hasDependency() */ protected function addDependency($type, $name) { // A config entity is always dependent on its provider. There is no need to // explicitly declare the dependency. An explicit dependency on Core, which // provides some plugins, is also not needed. - // @see \Drupal\Core\Config\Entity\ConfigEntityDependency::hasDependency() if ($type == 'module' && ($name == $this->getEntityType()->getProvider() || $name == 'core')) { return $this; } diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityInterface.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityInterface.php index b15498e9e03c..b83df5dbf95f 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityInterface.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityInterface.php @@ -10,7 +10,7 @@ use Drupal\Core\Entity\EntityInterface; /** - * Defines the interface common for all configuration entities. + * Defines a common interface for configuration entities. * * @ingroup config_api * @ingroup entity_api @@ -146,6 +146,8 @@ public function set($property_name, $value); * * @return array * An array of dependencies grouped by type (module, theme, entity). + * + * @see \Drupal\Core\Config\Entity\ConfigDependencyManager */ public function calculateDependencies(); @@ -154,6 +156,8 @@ public function calculateDependencies(); * * @return string * The configuration dependency name. + * + * @see \Drupal\Core\Config\Entity\ConfigDependencyManager */ public function getConfigDependencyName(); @@ -176,6 +180,7 @@ public function getConfigDependencyName(); * An array of dependencies that will be deleted keyed by dependency type. * Dependency types are, for example, entity, module and theme. * + * @see \Drupal\Core\Config\Entity\ConfigDependencyManager * @see \Drupal\Core\Config\ConfigManager::uninstall() * @see \Drupal\Core\Entity\EntityDisplayBase::onDependencyRemoval() */ @@ -185,8 +190,9 @@ public function onDependencyRemoval(array $dependencies); * Gets the configuration dependencies. * * @return array - * An array of dependencies. If $type not set all dependencies will be - * returned keyed by $type. + * An array of dependencies, keyed by $type. + * + * @see \Drupal\Core\Config\Entity\ConfigDependencyManager */ public function getDependencies(); diff --git a/core/lib/Drupal/Core/Entity/DependencyTrait.php b/core/lib/Drupal/Core/Entity/DependencyTrait.php index 2c77834a494d..5815ab1b8087 100644 --- a/core/lib/Drupal/Core/Entity/DependencyTrait.php +++ b/core/lib/Drupal/Core/Entity/DependencyTrait.php @@ -20,14 +20,13 @@ trait DependencyTrait { protected $dependencies = array(); /** - * Creates a dependency. + * Adds a dependency. * * @param string $type - * The type of dependency being checked. Either 'module', 'theme', 'entity'. + * The type of dependency being added: 'module', 'theme', or 'entity'. * @param string $name - * If $type equals 'module' or 'theme' then it should be the name of the - * module or theme. In the case of entity it should be the full - * configuration object name. + * If $type is 'module' or 'theme', the name of the module or theme. If + * $type is 'entity', the full configuration object name. * * @see \Drupal\Core\Config\Entity\ConfigEntityInterface::getConfigDependencyName() * @@ -54,17 +53,17 @@ protected function addDependency($type, $name) { * * @param array $dependencies. * An array of dependencies keyed by the type of dependency. One example: - * @code - * array( - * 'module' => array( - * 'node', - * 'field', - * 'image' - * ), - * ); - * @endcode + * @code + * array( + * 'module' => array( + * 'node', + * 'field', + * 'image', + * ), + * ); + * @endcode * - * @see ::addDependency + * @see \Drupal\Core\Entity\DependencyTrait::addDependency */ protected function addDependencies(array $dependencies) { foreach ($dependencies as $dependency_type => $list) { diff --git a/core/lib/Drupal/Core/Plugin/PluginDependencyTrait.php b/core/lib/Drupal/Core/Plugin/PluginDependencyTrait.php index 21ec3ba6c957..2114d38c300a 100644 --- a/core/lib/Drupal/Core/Plugin/PluginDependencyTrait.php +++ b/core/lib/Drupal/Core/Plugin/PluginDependencyTrait.php @@ -19,7 +19,12 @@ trait PluginDependencyTrait { use DependencyTrait; /** - * Calculates the dependencies of a specific plugin instance. + * Calculates and adds dependencies of a specific plugin instance. + * + * Dependencies are added for the module that provides the plugin, as well + * as any dependencies declared by the instance's calculateDependencies() + * method, if it implements + * \Drupal\Component\Plugin\ConfigurablePluginInterface. * * @param \Drupal\Component\Plugin\PluginInspectionInterface $instance * The plugin instance. -- GitLab