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