From b6707fca2eeb91bf96c3c652bef0ec39b21fec6e Mon Sep 17 00:00:00 2001
From: effulgentsia <alex.bronstein@acquia.com>
Date: Mon, 5 Oct 2015 14:31:21 -0700
Subject: [PATCH] =?UTF-8?q?Issue=20#2488568=20by=20Jose=20Reyero,=20alexpo?=
 =?UTF-8?q?tt,=20G=C3=A1bor=20Hojtsy,=20tstoeckler:=20Add=20a=20TypedDataM?=
 =?UTF-8?q?anagerInterface=20and=20use=20it=20for=20typed=20parameters?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 core/lib/Drupal.php                           |   2 +-
 .../Core/Config/Schema/ArrayElement.php       |  36 +--
 .../lib/Drupal/Core/Config/Schema/Element.php |  39 +++
 .../Drupal/Core/Config/TypedConfigManager.php |  21 +-
 .../Config/TypedConfigManagerInterface.php    |  48 +---
 core/lib/Drupal/Core/Entity/EntityManager.php |   8 +-
 core/lib/Drupal/Core/Field/FieldItemList.php  |   2 +-
 .../Core/Field/FieldTypePluginManager.php     |   8 +-
 .../Core/TypedData/DataReferenceBase.php      |   2 +-
 .../TypedData/Plugin/DataType/ItemList.php    |   2 +-
 .../Core/TypedData/Plugin/DataType/Map.php    |   2 +-
 core/lib/Drupal/Core/TypedData/TypedData.php  |   9 +-
 .../Core/TypedData/TypedDataManager.php       | 194 ++------------
 .../TypedData/TypedDataManagerInterface.php   | 248 ++++++++++++++++++
 .../Drupal/Core/TypedData/TypedDataTrait.php  |   8 +-
 .../RecursiveContextualValidator.php          |   6 +-
 .../Validation/RecursiveValidator.php         |   6 +-
 17 files changed, 335 insertions(+), 306 deletions(-)
 create mode 100644 core/lib/Drupal/Core/TypedData/TypedDataManagerInterface.php

diff --git a/core/lib/Drupal.php b/core/lib/Drupal.php
index 711028be445a..8b90d3e66859 100644
--- a/core/lib/Drupal.php
+++ b/core/lib/Drupal.php
@@ -459,7 +459,7 @@ public static function moduleHandler() {
    *
    * Use the typed data manager service for creating typed data objects.
    *
-   * @return \Drupal\Core\TypedData\TypedDataManager
+   * @return \Drupal\Core\TypedData\TypedDataManagerInterface
    *   The typed data manager.
    *
    * @see \Drupal\Core\TypedData\TypedDataManager::create()
diff --git a/core/lib/Drupal/Core/Config/Schema/ArrayElement.php b/core/lib/Drupal/Core/Config/Schema/ArrayElement.php
index fb89063117b7..c4641cf0288f 100644
--- a/core/lib/Drupal/Core/Config/Schema/ArrayElement.php
+++ b/core/lib/Drupal/Core/Config/Schema/ArrayElement.php
@@ -7,27 +7,10 @@
 
 namespace Drupal\Core\Config\Schema;
 
-use Drupal\Core\Config\TypedConfigManagerInterface;
-use Drupal\Core\TypedData\TypedData;
-
 /**
  * Defines a generic configuration element that contains multiple properties.
  */
-abstract class ArrayElement extends TypedData implements \IteratorAggregate, TypedConfigInterface {
-
-  /**
-   * The typed config manager.
-   *
-   * @var \Drupal\Core\Config\TypedConfigManagerInterface
-   */
-  protected $typedConfig;
-
-  /**
-   * The configuration value.
-   *
-   * @var mixed
-   */
-  protected $value;
+abstract class ArrayElement extends Element implements \IteratorAggregate, TypedConfigInterface {
 
   /**
    * Parsed elements.
@@ -152,7 +135,7 @@ public function getIterator() {
    * @return \Drupal\Core\TypedData\TypedDataInterface
    */
   protected function createElement($definition, $value, $key) {
-    return $this->typedConfig->create($definition, $value, $key, $this);
+    return $this->getTypedDataManager()->create($definition, $value, $key, $this);
   }
 
   /**
@@ -170,20 +153,7 @@ protected function createElement($definition, $value, $key) {
    * @return \Drupal\Core\TypedData\DataDefinitionInterface
    */
   protected function buildDataDefinition($definition, $value, $key) {
-    return $this->typedConfig->buildDataDefinition($definition, $value, $key, $this);
-  }
-
-
-  /**
-   * Sets the typed config manager on the instance.
-   *
-   * This must be called immediately after construction to enable
-   * self::parseElement() and self::buildDataDefinition() to work.
-   *
-   * @param \Drupal\Core\Config\TypedConfigManagerInterface $typed_config
-   */
-  public function setTypedConfig(TypedConfigManagerInterface $typed_config) {
-    $this->typedConfig = $typed_config;
+    return $this->getTypedDataManager()->buildDataDefinition($definition, $value, $key, $this);
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Config/Schema/Element.php b/core/lib/Drupal/Core/Config/Schema/Element.php
index 2993f8c7a48f..86cf4de3bcf3 100644
--- a/core/lib/Drupal/Core/Config/Schema/Element.php
+++ b/core/lib/Drupal/Core/Config/Schema/Element.php
@@ -7,7 +7,9 @@
 
 namespace Drupal\Core\Config\Schema;
 
+use Drupal\Core\Config\TypedConfigManagerInterface;
 use Drupal\Core\TypedData\TypedData;
+use Drupal\Core\TypedData\TypedDataManagerInterface;
 
 /**
  * Defines a generic configuration element.
@@ -21,4 +23,41 @@ abstract class Element extends TypedData {
    */
   protected $value;
 
+  /**
+   * Gets the typed configuration manager.
+   *
+   * Overrides \Drupal\Core\TypedData\TypedDataTrait::getTypedDataManager() to
+   * ensure the typed configuration manager is returned.
+   *
+   * @return \Drupal\Core\Config\TypedConfigManagerInterface
+   *   The typed configuration manager.
+   */
+  public function getTypedDataManager() {
+    if (empty($this->typedDataManager)) {
+      $this->setTypedDataManager(\Drupal::service('config.typed'));
+    }
+
+    return $this->typedDataManager;
+  }
+
+  /**
+   * Sets the typed config manager.
+   *
+   * Overrides \Drupal\Core\TypedData\TypedDataTrait::setTypedDataManager() to
+   * ensure that only typed configuration manager can be used.
+   *
+   * @param \Drupal\Core\TypedData\TypedDataManagerInterface $typed_data_manager
+   *   The typed config manager. This must be an instance of
+   *   \Drupal\Core\Config\TypedConfigManagerInterface. If it is not, then this
+   *   method will error when assertions are enabled. We can not narrow the
+   *   typehint as this will cause PHP errors.
+   *
+   * @return $this
+   */
+  public function setTypedDataManager(TypedDataManagerInterface $typed_data_manager) {
+    assert($typed_data_manager instanceof TypedConfigManagerInterface, '$typed_data_manager should be an instance of \Drupal\Core\Config\TypedConfigManagerInterface.');
+    $this->typedDataManager = $typed_data_manager;
+    return $this;
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Config/TypedConfigManager.php b/core/lib/Drupal/Core/Config/TypedConfigManager.php
index 5c7aeeb29f85..625e1eabaa3f 100644
--- a/core/lib/Drupal/Core/Config/TypedConfigManager.php
+++ b/core/lib/Drupal/Core/Config/TypedConfigManager.php
@@ -71,13 +71,7 @@ protected function getDiscovery() {
 
 
   /**
-   * Gets typed configuration data.
-   *
-   * @param string $name
-   *   Configuration object name.
-   *
-   * @return \Drupal\Core\Config\Schema\TypedConfigInterface
-   *   Typed configuration data.
+   * {@inheritdoc}
    */
   public function get($name) {
     $data = $this->configStorage->read($name);
@@ -342,17 +336,4 @@ protected function alterDefinitions(&$definitions) {
     }
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function createInstance($data_type, array $configuration = array()) {
-    $instance = parent::createInstance($data_type, $configuration);
-    // Enable elements to construct their own definitions using the typed config
-    // manager.
-    if ($instance instanceof ArrayElement) {
-      $instance->setTypedConfig($this);
-    }
-    return $instance;
-  }
-
 }
diff --git a/core/lib/Drupal/Core/Config/TypedConfigManagerInterface.php b/core/lib/Drupal/Core/Config/TypedConfigManagerInterface.php
index 11c375109f77..dcd858492a9e 100644
--- a/core/lib/Drupal/Core/Config/TypedConfigManagerInterface.php
+++ b/core/lib/Drupal/Core/Config/TypedConfigManagerInterface.php
@@ -7,9 +7,7 @@
 
 namespace Drupal\Core\Config;
 
-use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface;
-use Drupal\Component\Plugin\PluginManagerInterface;
-use Drupal\Core\TypedData\DataDefinitionInterface;
+use Drupal\Core\TypedData\TypedDataManagerInterface;
 
 /**
  * Defines an interface for managing config schema type plugins.
@@ -19,7 +17,7 @@
  * @see hook_config_schema_info_alter()
  * @see https://www.drupal.org/node/1905070
  */
-Interface TypedConfigManagerInterface extends PluginManagerInterface, CachedDiscoveryInterface {
+Interface TypedConfigManagerInterface extends TypedDataManagerInterface {
 
   /**
    * Gets typed configuration data.
@@ -32,48 +30,6 @@
    */
   public function get($name);
 
-  /**
-   * Instantiates a typed configuration object.
-   *
-   * @param string $data_type
-   *   The data type, for which a typed configuration object should be
-   *   instantiated.
-   * @param array $configuration
-   *   The plugin configuration array, i.e. an array with the following keys:
-   *   - data definition: The data definition object, i.e. an instance of
-   *     \Drupal\Core\TypedData\DataDefinitionInterface.
-   *   - name: (optional) If a property or list item is to be created, the name
-   *     of the property or the delta of the list item.
-   *   - parent: (optional) If a property or list item is to be created, the
-   *     parent typed data object implementing either the ListInterface or the
-   *     ComplexDataInterface.
-   *
-   * @return \Drupal\Core\Config\Schema\Element
-   *   The instantiated typed configuration object.
-   */
-  public function createInstance($data_type, array $configuration = array());
-
-  /**
-   * Creates a new typed configuration object instance.
-   *
-   * @param \Drupal\Core\TypedData\DataDefinitionInterface $definition
-   *   The data definition of the typed data object.
-   * @param mixed $value
-   *   The data value. If set, it has to match one of the supported
-   *   data type format as documented for the data type classes.
-   * @param string $name
-   *   (optional) If a property or list item is to be created, the name of the
-   *   property or the delta of the list item.
-   * @param mixed $parent
-   *   (optional) If a property or list item is to be created, the parent typed
-   *   data object implementing either the ListInterface or the
-   *   ComplexDataInterface.
-   *
-   * @return \Drupal\Core\Config\Schema\Element
-   *   The instantiated typed data object.
-   */
-  public function create(DataDefinitionInterface $definition, $value, $name = NULL, $parent = NULL);
-
   /**
    * Creates a new data definition object from a type definition array and
    * actual configuration data. Since type definitions may contain variables
diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php
index f00fd2cf956e..da4fec06a6d8 100644
--- a/core/lib/Drupal/Core/Entity/EntityManager.php
+++ b/core/lib/Drupal/Core/Entity/EntityManager.php
@@ -32,7 +32,7 @@
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\Core\StringTranslation\TranslationInterface;
 use Drupal\Core\TypedData\TranslatableInterface;
-use Drupal\Core\TypedData\TypedDataManager;
+use Drupal\Core\TypedData\TypedDataManagerInterface;
 use Symfony\Component\DependencyInjection\ContainerAwareInterface;
 use Symfony\Component\DependencyInjection\ContainerAwareTrait;
 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
@@ -111,7 +111,7 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa
   /**
    * The typed data manager.
    *
-   * @var \Drupal\Core\TypedData\TypedDataManager
+   * @var \Drupal\Core\TypedData\TypedDataManagerInterface
    */
   protected $typedDataManager;
 
@@ -193,14 +193,14 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa
    *   The string translationManager.
    * @param \Drupal\Core\DependencyInjection\ClassResolverInterface $class_resolver
    *   The class resolver.
-   * @param \Drupal\Core\TypedData\TypedDataManager $typed_data_manager
+   * @param \Drupal\Core\TypedData\TypedDataManagerInterface $typed_data_manager
    *   The typed data manager.
    * @param \Drupal\Core\KeyValueStore\KeyValueFactoryInterface $key_value_factory
    *   The keyvalue factory.
    * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
    *   The event dispatcher.
    */
-  public function __construct(\Traversable $namespaces, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache, LanguageManagerInterface $language_manager, TranslationInterface $translation_manager, ClassResolverInterface $class_resolver, TypedDataManager $typed_data_manager, KeyValueFactoryInterface $key_value_factory, EventDispatcherInterface $event_dispatcher) {
+  public function __construct(\Traversable $namespaces, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache, LanguageManagerInterface $language_manager, TranslationInterface $translation_manager, ClassResolverInterface $class_resolver, TypedDataManagerInterface $typed_data_manager, KeyValueFactoryInterface $key_value_factory, EventDispatcherInterface $event_dispatcher) {
     parent::__construct('Entity', $namespaces, $module_handler, 'Drupal\Core\Entity\EntityInterface');
 
     $this->setCacheBackend($cache, 'entity_type', array('entity_types'));
diff --git a/core/lib/Drupal/Core/Field/FieldItemList.php b/core/lib/Drupal/Core/Field/FieldItemList.php
index 9d108ff2d214..2121334a7e60 100644
--- a/core/lib/Drupal/Core/Field/FieldItemList.php
+++ b/core/lib/Drupal/Core/Field/FieldItemList.php
@@ -281,7 +281,7 @@ public function getConstraints() {
     // widgets.
     $cardinality = $this->getFieldDefinition()->getFieldStorageDefinition()->getCardinality();
     if ($cardinality != FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) {
-      $constraints[] = \Drupal::typedDataManager()
+      $constraints[] = $this->getTypedDataManager()
         ->getValidationConstraintManager()
         ->create('Count', array(
           'max' => $cardinality,
diff --git a/core/lib/Drupal/Core/Field/FieldTypePluginManager.php b/core/lib/Drupal/Core/Field/FieldTypePluginManager.php
index 000e3fe7e8d5..3d896b2752a9 100644
--- a/core/lib/Drupal/Core/Field/FieldTypePluginManager.php
+++ b/core/lib/Drupal/Core/Field/FieldTypePluginManager.php
@@ -13,7 +13,7 @@
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\CategorizingPluginManagerTrait;
 use Drupal\Core\Plugin\DefaultPluginManager;
-use Drupal\Core\TypedData\TypedDataManager;
+use Drupal\Core\TypedData\TypedDataManagerInterface;
 
 /**
  * Plugin manager for 'field type' plugins.
@@ -27,7 +27,7 @@ class FieldTypePluginManager extends DefaultPluginManager implements FieldTypePl
   /**
    * The typed data manager.
    *
-   * @var \Drupal\Core\TypedData\TypedDataManager
+   * @var \Drupal\Core\TypedData\TypedDataManagerInterface
    */
   protected $typedDataManager;
 
@@ -41,10 +41,10 @@ class FieldTypePluginManager extends DefaultPluginManager implements FieldTypePl
    *   Cache backend instance to use.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface
    *   The module handler.
-   * @param \Drupal\Core\TypedData\TypedDataManager $typed_data_manager
+   * @param \Drupal\Core\TypedData\TypedDataManagerInterface $typed_data_manager
    *   The typed data manager.
    */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, TypedDataManager $typed_data_manager) {
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, TypedDataManagerInterface $typed_data_manager) {
     parent::__construct('Plugin/Field/FieldType', $namespaces, $module_handler, 'Drupal\Core\Field\FieldItemInterface', 'Drupal\Core\Field\Annotation\FieldType');
     $this->alterInfo('field_info');
     $this->setCacheBackend($cache_backend, 'field_types_plugins');
diff --git a/core/lib/Drupal/Core/TypedData/DataReferenceBase.php b/core/lib/Drupal/Core/TypedData/DataReferenceBase.php
index 1b9aaa5c20eb..4ad77bdf527d 100644
--- a/core/lib/Drupal/Core/TypedData/DataReferenceBase.php
+++ b/core/lib/Drupal/Core/TypedData/DataReferenceBase.php
@@ -48,7 +48,7 @@ public function getValue() {
    * {@inheritdoc}
    */
   public function setValue($value, $notify = TRUE) {
-    $this->target = \Drupal::typedDataManager()->create($this->definition->getTargetDefinition(), $value);
+    $this->target = $this->getTypedDataManager()->create($this->definition->getTargetDefinition(), $value);
     // Notify the parent of any changes.
     if ($notify && isset($this->parent)) {
       $this->parent->onChange($this->name);
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/ItemList.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/ItemList.php
index 2a868dbdacf9..577bfb4c0c0f 100644
--- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/ItemList.php
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/ItemList.php
@@ -222,7 +222,7 @@ public function appendItem($value = NULL) {
    * @return \Drupal\Core\TypedData\TypedDataInterface
    */
   protected function createItem($offset = 0, $value = NULL) {
-    return \Drupal::typedDataManager()->getPropertyInstance($this, $offset, $value);
+    return $this->getTypedDataManager()->getPropertyInstance($this, $offset, $value);
   }
 
   /**
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php
index a06b9e3e2ed4..4ab0aba8d887 100644
--- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php
@@ -118,7 +118,7 @@ public function get($property_name) {
         $value = $this->values[$property_name];
       }
       // If the property is unknown, this will throw an exception.
-      $this->properties[$property_name] = \Drupal::typedDataManager()->getPropertyInstance($this, $property_name, $value);
+      $this->properties[$property_name] = $this->getTypedDataManager()->getPropertyInstance($this, $property_name, $value);
     }
     return $this->properties[$property_name];
   }
diff --git a/core/lib/Drupal/Core/TypedData/TypedData.php b/core/lib/Drupal/Core/TypedData/TypedData.php
index 92c8a89e9592..a266daa56342 100644
--- a/core/lib/Drupal/Core/TypedData/TypedData.php
+++ b/core/lib/Drupal/Core/TypedData/TypedData.php
@@ -21,6 +21,7 @@
 abstract class TypedData implements TypedDataInterface, PluginInspectionInterface {
 
   use StringTranslationTrait;
+  use TypedDataTrait;
 
   /**
    * The data definition.
@@ -85,7 +86,7 @@ public function getPluginId() {
    * {@inheritdoc}
    */
   public function getPluginDefinition() {
-    return \Drupal::typedDataManager()->getDefinition($this->definition->getDataType());
+    return $this->getTypedDataManager()->getDefinition($this->definition->getDataType());
   }
 
   /**
@@ -124,8 +125,7 @@ public function getString() {
    * {@inheritdoc}
    */
   public function getConstraints() {
-    // @todo: Add the typed data manager as proper dependency.
-    $constraint_manager = \Drupal::typedDataManager()->getValidationConstraintManager();
+    $constraint_manager = $this->getTypedDataManager()->getValidationConstraintManager();
     $constraints = array();
     foreach ($this->definition->getConstraints() as $name => $options) {
       $constraints[] = $constraint_manager->create($name, $options);
@@ -137,8 +137,7 @@ public function getConstraints() {
    * {@inheritdoc}
    */
   public function validate() {
-    // @todo: Add the typed data manager as proper dependency.
-    return \Drupal::typedDataManager()->getValidator()->validate($this);
+    return $this->getTypedDataManager()->getValidator()->validate($this);
   }
 
   /**
diff --git a/core/lib/Drupal/Core/TypedData/TypedDataManager.php b/core/lib/Drupal/Core/TypedData/TypedDataManager.php
index 20910f6242c5..be5bcd4e5578 100644
--- a/core/lib/Drupal/Core/TypedData/TypedDataManager.php
+++ b/core/lib/Drupal/Core/TypedData/TypedDataManager.php
@@ -23,7 +23,7 @@
 /**
  * Manages data type plugins.
  */
-class TypedDataManager extends DefaultPluginManager {
+class TypedDataManager extends DefaultPluginManager implements TypedDataManagerInterface {
   use DependencySerializationTrait;
 
   /**
@@ -76,24 +76,7 @@ public function __construct(\Traversable $namespaces, CacheBackendInterface $cac
   }
 
   /**
-   * Instantiates a typed data object.
-   *
-   * @param string $data_type
-   *   The data type, for which a typed object should be instantiated.
-   * @param array $configuration
-   *   The plugin configuration array, i.e. an array with the following keys:
-   *   - data_definition: The data definition object, i.e. an instance of
-   *     \Drupal\Core\TypedData\DataDefinitionInterface.
-   *   - name: (optional) If a property or list item is to be created, the name
-   *     of the property or the delta of the list item.
-   *   - parent: (optional) If a property or list item is to be created, the
-   *     parent typed data object implementing either the ListInterface or the
-   *     ComplexDataInterface.
-   *
-   * @return \Drupal\Core\TypedData\TypedDataInterface
-   *   The instantiated typed data object.
-   *
-   * @see \Drupal\Core\TypedData\TypedDataManager::create()
+   * {@inheritdoc}
    */
   public function createInstance($data_type, array $configuration = array()) {
     $data_definition = $configuration['data_definition'];
@@ -110,39 +93,13 @@ public function createInstance($data_type, array $configuration = array()) {
     if (!isset($class)) {
       throw new PluginException(sprintf('The plugin (%s) did not specify an instance class.', $data_type));
     }
-    return $class::createInstance($data_definition, $configuration['name'], $configuration['parent']);
+    $typed_data = $class::createInstance($data_definition, $configuration['name'], $configuration['parent']);
+    $typed_data->setTypedDataManager($this);
+    return $typed_data;
   }
 
   /**
-   * Creates a new typed data object instance.
-   *
-   * @param \Drupal\Core\TypedData\DataDefinitionInterface $definition
-   *   The data definition of the typed data object. For backwards-compatibility
-   *   an array representation of the data definition may be passed also.
-   * @param mixed $value
-   *   (optional) The data value. If set, it has to match one of the supported
-   *   data type format as documented for the data type classes.
-   * @param string $name
-   *   (optional) If a property or list item is to be created, the name of the
-   *   property or the delta of the list item.
-   * @param mixed $parent
-   *   (optional) If a property or list item is to be created, the parent typed
-   *   data object implementing either the ListInterface or the
-   *   ComplexDataInterface.
-   *
-   * @return \Drupal\Core\TypedData\TypedDataInterface
-   *   The instantiated typed data object.
-   *
-   * @see \Drupal::typedDataManager()
-   * @see \Drupal\Core\TypedData\TypedDataManager::getPropertyInstance()
-   * @see \Drupal\Core\TypedData\Plugin\DataType\BinaryData
-   * @see \Drupal\Core\TypedData\Plugin\DataType\BooleanData
-   * @see \Drupal\Core\TypedData\Plugin\DataType\Date
-   * @see \Drupal\Core\TypedData\Plugin\DataType\Duration
-   * @see \Drupal\Core\TypedData\Plugin\DataType\FloatData
-   * @see \Drupal\Core\TypedData\Plugin\DataType\IntegerData
-   * @see \Drupal\Core\TypedData\Plugin\DataType\StringData
-   * @see \Drupal\Core\TypedData\Plugin\DataType\Uri
+   * {@inheritdoc}
    */
   public function create(DataDefinitionInterface $definition, $value = NULL, $name = NULL, $parent = NULL) {
     $typed_data = $this->createInstance($definition->getDataType(), array(
@@ -157,27 +114,7 @@ public function create(DataDefinitionInterface $definition, $value = NULL, $name
   }
 
   /**
-   * Creates a new data definition object.
-   *
-   * While data definitions objects may be created directly if the definition
-   * class used by a data type is known, this method allows the creation of data
-   * definitions for any given data type.
-   *
-   * E.g., if a definition for a map is to be created, the following code
-   * could be used instead of calling this method with the argument 'map':
-   * @code
-   *   $map_definition = \Drupal\Core\TypedData\MapDataDefinition::create();
-   * @endcode
-   *
-   * @param string $data_type
-   *   The data type plugin ID, for which a data definition object should be
-   *   created.
-   *
-   * @return \Drupal\Core\TypedData\DataDefinitionInterface
-   *   A data definition object for the given data type. The class of this
-   *   object is provided by the definition_class in the plugin annotation.
-   *
-   * @see \Drupal\Core\TypedData\TypedDataManager::createListDataDefinition()
+   * {@inheritdoc}
    */
   public function createDataDefinition($data_type) {
     $type_definition = $this->getDefinition($data_type);
@@ -189,15 +126,7 @@ public function createDataDefinition($data_type) {
   }
 
   /**
-   * Creates a new list data definition for items of the given data type.
-   *
-   * @param string $item_type
-   *   The item type, for which a list data definition should be created.
-   *
-   * @return \Drupal\Core\TypedData\ListDataDefinitionInterface
-   *   A list definition for items of the given data type.
-   *
-   * @see \Drupal\Core\TypedData\TypedDataManager::createDataDefinition()
+   * {@inheritdoc}
    */
   public function createListDataDefinition($item_type) {
     $type_definition = $this->getDefinition($item_type);
@@ -209,59 +138,14 @@ public function createListDataDefinition($item_type) {
   }
 
   /**
-   * Implements \Drupal\Component\Plugin\PluginManagerInterface::getInstance().
-   *
-   * @param array $options
-   *   An array of options with the following keys:
-   *   - object: The parent typed data object, implementing the
-   *     TypedDataInterface and either the ListInterface or the
-   *     ComplexDataInterface.
-   *   - property: The name of the property to instantiate, or the delta of the
-   *     the list item to instantiate.
-   *   - value: The value to set. If set, it has to match one of the supported
-   *     data type formats as documented by the data type classes.
-   *
-   * @throws \InvalidArgumentException
-   *   If the given property is not known, or the passed object does not
-   *   implement the ListInterface or the ComplexDataInterface.
-   *
-   * @return \Drupal\Core\TypedData\TypedDataInterface
-   *   The new property instance.
-   *
-   * @see \Drupal\Core\TypedData\TypedDataManager::getPropertyInstance()
+   * {@inheritdoc}
    */
   public function getInstance(array $options) {
     return $this->getPropertyInstance($options['object'], $options['property'], $options['value']);
   }
 
   /**
-   * Get a typed data instance for a property of a given typed data object.
-   *
-   * This method will use prototyping for fast and efficient instantiation of
-   * many property objects with the same property path; e.g.,
-   * when multiple comments are used comment_body.0.value needs to be
-   * instantiated very often.
-   * Prototyping is done by the root object's data type and the given
-   * property path, i.e. all property instances having the same property path
-   * and inheriting from the same data type are prototyped.
-   *
-   * @param \Drupal\Core\TypedData\TypedDataInterface $object
-   *   The parent typed data object, implementing the TypedDataInterface and
-   *   either the ListInterface or the ComplexDataInterface.
-   * @param string $property_name
-   *   The name of the property to instantiate, or the delta of an list item.
-   * @param mixed $value
-   *   (optional) The data value. If set, it has to match one of the supported
-   *   data type formats as documented by the data type classes.
-   *
-   * @throws \InvalidArgumentException
-   *   If the given property is not known, or the passed object does not
-   *   implement the ListInterface or the ComplexDataInterface.
-   *
-   * @return \Drupal\Core\TypedData\TypedDataInterface
-   *   The new property instance.
-   *
-   * @see \Drupal\Core\TypedData\TypedDataManager::create()
+   * {@inheritdoc}
    */
   public function getPropertyInstance(TypedDataInterface $object, $property_name, $value = NULL) {
     // For performance, try to reuse existing prototypes instead of
@@ -329,10 +213,7 @@ public function setValidator(ValidatorInterface $validator) {
   }
 
   /**
-   * Gets the validator for validating typed data.
-   *
-   * @return \Symfony\Component\Validator\Validator\ValidatorInterface
-   *   The validator object.
+   * {@inheritdoc}
    */
   public function getValidator() {
     if (!isset($this->validator)) {
@@ -346,43 +227,21 @@ public function getValidator() {
   }
 
   /**
-   * Sets the validation constraint manager.
-   *
-   * The validation constraint manager is used to instantiate validation
-   * constraint plugins.
-   *
-   * @param \Drupal\Core\Validation\ConstraintManager
-   *   The constraint manager to set.
+   * {@inheritdoc}
    */
   public function setValidationConstraintManager(ConstraintManager $constraintManager) {
     $this->constraintManager = $constraintManager;
   }
 
   /**
-   * Gets the validation constraint manager.
-   *
-   * @return \Drupal\Core\Validation\ConstraintManager
-   *   The constraint manager.
+   * {@inheritdoc}
    */
   public function getValidationConstraintManager() {
     return $this->constraintManager;
   }
 
   /**
-   * Gets default constraints for the given data definition.
-   *
-   * This generates default constraint definitions based on the data definition;
-   * e.g. a NotNull constraint is generated if the data is defined as required.
-   * Besides that any constraints defined for the data type, i.e. below the
-   * 'constraint' key of the type's plugin definition, are taken into account.
-   *
-   * @param \Drupal\Core\TypedData\DataDefinitionInterface $definition
-   *   A data definition.
-   *
-   * @return array
-   *   An array of validation constraint definitions, keyed by constraint name.
-   *   Each constraint definition can be used for instantiating
-   *   \Symfony\Component\Validator\Constraint objects.
+   * {@inheritdoc}
    */
   public function getDefaultConstraints(DataDefinitionInterface $definition) {
     $constraints = array();
@@ -416,30 +275,7 @@ public function clearCachedDefinitions() {
   }
 
   /**
-   * Gets the canonical representation of a TypedData object.
-   *
-   * The canonical representation is typically used when data is passed on to
-   * other code components. In many use cases, the TypedData object is mostly
-   * unified adapter wrapping a primary value (e.g. a string, an entity...)
-   * which is the canonical representation that consuming code like constraint
-   * validators are really interested in. For some APIs, though, the domain
-   * object (e.g. Field API's FieldItem and FieldItemList) directly implements
-   * TypedDataInterface, and the canonical representation is thus the data
-   * object itself.
-   *
-   * When a TypedData object gets validated, for example, its canonical
-   * representation is passed on to constraint validators, which thus receive
-   * an Entity unwrapped, but a FieldItem as is.
-   *
-   * Data types specify whether their data objects need unwrapping by using the
-   * 'unwrap_for_canonical_representation' property in the data definition
-   * (defaults to TRUE).
-   *
-   * @param \Drupal\Core\TypedData\TypedDataInterface $data
-   *   The data.
-   *
-   * @return mixed
-   *   The canonical representation of the passed data.
+   * {@inheritdoc}
    */
   public function getCanonicalRepresentation(TypedDataInterface $data) {
     $data_definition = $data->getDataDefinition();
diff --git a/core/lib/Drupal/Core/TypedData/TypedDataManagerInterface.php b/core/lib/Drupal/Core/TypedData/TypedDataManagerInterface.php
new file mode 100644
index 000000000000..cdfe96248cf7
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/TypedDataManagerInterface.php
@@ -0,0 +1,248 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\TypedDataManagerInterface.
+ */
+
+namespace Drupal\Core\TypedData;
+
+use Drupal\Component\Plugin\PluginManagerInterface;
+use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface;
+use Drupal\Core\Validation\ConstraintManager;
+use Symfony\Component\Validator\Validator\ValidatorInterface;
+
+/**
+ * Defines an interface for typed data manager.
+ */
+interface TypedDataManagerInterface extends PluginManagerInterface, CachedDiscoveryInterface {
+
+  /**
+   * Instantiates a typed data object.
+   *
+   * @param string $data_type
+   *   The data type, for which a typed object should be instantiated.
+   * @param array $configuration
+   *   The plugin configuration array, i.e. an array with the following keys:
+   *   - data_definition: The data definition object, i.e. an instance of
+   *     \Drupal\Core\TypedData\DataDefinitionInterface.
+   *   - name: (optional) If a property or list item is to be created, the name
+   *     of the property or the delta of the list item.
+   *   - parent: (optional) If a property or list item is to be created, the
+   *     parent typed data object implementing either the ListInterface or the
+   *     ComplexDataInterface.
+   *
+   * @return \Drupal\Core\TypedData\TypedDataInterface
+   *   The instantiated typed data object.
+   *
+   * @see \Drupal\Core\TypedData\TypedDataManager::create()
+   */
+  public function createInstance($data_type, array $configuration = array());
+
+  /**
+   * Creates a new typed data object instance.
+   *
+   * @param \Drupal\Core\TypedData\DataDefinitionInterface $definition
+   *   The data definition of the typed data object. For backwards-compatibility
+   *   an array representation of the data definition may be passed also.
+   * @param mixed $value
+   *   (optional) The data value. If set, it has to match one of the supported
+   *   data type format as documented for the data type classes.
+   * @param string $name
+   *   (optional) If a property or list item is to be created, the name of the
+   *   property or the delta of the list item.
+   * @param mixed $parent
+   *   (optional) If a property or list item is to be created, the parent typed
+   *   data object implementing either the ListInterface or the
+   *   ComplexDataInterface.
+   *
+   * @return \Drupal\Core\TypedData\TypedDataInterface
+   *   The instantiated typed data object.
+   *
+   * @see \Drupal\Core\TypedData\TypedDataManager::getPropertyInstance()
+   * @see \Drupal\Core\TypedData\Plugin\DataType\BinaryData
+   * @see \Drupal\Core\TypedData\Plugin\DataType\BooleanData
+   * @see \Drupal\Core\TypedData\Plugin\DataType\Date
+   * @see \Drupal\Core\TypedData\Plugin\DataType\Duration
+   * @see \Drupal\Core\TypedData\Plugin\DataType\FloatData
+   * @see \Drupal\Core\TypedData\Plugin\DataType\IntegerData
+   * @see \Drupal\Core\TypedData\Plugin\DataType\StringData
+   * @see \Drupal\Core\TypedData\Plugin\DataType\Uri
+   */
+  public function create(DataDefinitionInterface $definition, $value = NULL, $name = NULL, $parent = NULL);
+
+  /**
+   * Creates a new data definition object.
+   *
+   * While data definitions objects may be created directly if the definition
+   * class used by a data type is known, this method allows the creation of data
+   * definitions for any given data type.
+   *
+   * E.g., if a definition for a map is to be created, the following code
+   * could be used instead of calling this method with the argument 'map':
+   * @code
+   *   $map_definition = \Drupal\Core\TypedData\MapDataDefinition::create();
+   * @endcode
+   *
+   * @param string $data_type
+   *   The data type plugin ID, for which a data definition object should be
+   *   created.
+   *
+   * @return \Drupal\Core\TypedData\DataDefinitionInterface
+   *   A data definition object for the given data type. The class of this
+   *   object is provided by the definition_class in the plugin annotation.
+   *
+   * @see \Drupal\Core\TypedData\TypedDataManager::createListDataDefinition()
+   */
+  public function createDataDefinition($data_type);
+
+  /**
+   * Creates a new list data definition for items of the given data type.
+   *
+   * @param string $item_type
+   *   The item type, for which a list data definition should be created.
+   *
+   * @return \Drupal\Core\TypedData\ListDataDefinitionInterface
+   *   A list definition for items of the given data type.
+   *
+   * @see \Drupal\Core\TypedData\TypedDataManager::createDataDefinition()
+   */
+  public function createListDataDefinition($item_type);
+
+  /**
+   * {@inheritdoc}
+   *
+   * @param array $options
+   *   An array of options with the following keys:
+   *   - object: The parent typed data object, implementing the
+   *     TypedDataInterface and either the ListInterface or the
+   *     ComplexDataInterface.
+   *   - property: The name of the property to instantiate, or the delta of the
+   *     the list item to instantiate.
+   *   - value: The value to set. If set, it has to match one of the supported
+   *     data type formats as documented by the data type classes.
+   *
+   * @throws \InvalidArgumentException
+   *   If the given property is not known, or the passed object does not
+   *   implement the ListInterface or the ComplexDataInterface.
+   *
+   * @return \Drupal\Core\TypedData\TypedDataInterface
+   *   The new property instance.
+   *
+   * @see \Drupal\Core\TypedData\TypedDataManager::getPropertyInstance()
+   */
+  public function getInstance(array $options);
+
+  /**
+   * Get a typed data instance for a property of a given typed data object.
+   *
+   * This method will use prototyping for fast and efficient instantiation of
+   * many property objects with the same property path; e.g.,
+   * when multiple comments are used comment_body.0.value needs to be
+   * instantiated very often.
+   * Prototyping is done by the root object's data type and the given
+   * property path, i.e. all property instances having the same property path
+   * and inheriting from the same data type are prototyped.
+   *
+   * @param \Drupal\Core\TypedData\TypedDataInterface $object
+   *   The parent typed data object, implementing the TypedDataInterface and
+   *   either the ListInterface or the ComplexDataInterface.
+   * @param string $property_name
+   *   The name of the property to instantiate, or the delta of an list item.
+   * @param mixed $value
+   *   (optional) The data value. If set, it has to match one of the supported
+   *   data type formats as documented by the data type classes.
+   *
+   * @throws \InvalidArgumentException
+   *   If the given property is not known, or the passed object does not
+   *   implement the ListInterface or the ComplexDataInterface.
+   *
+   * @return \Drupal\Core\TypedData\TypedDataInterface
+   *   The new property instance.
+   *
+   * @see \Drupal\Core\TypedData\TypedDataManager::create()
+   */
+  public function getPropertyInstance(TypedDataInterface $object, $property_name, $value = NULL);
+
+  /**
+   * Gets the validator for validating typed data.
+   *
+   * @return \Symfony\Component\Validator\Validator\ValidatorInterface
+   *   The validator object.
+   */
+  public function getValidator();
+
+  /**
+   * Sets the validator for validating typed data.
+   *
+   * @param \Symfony\Component\Validator\Validator\ValidatorInterface $validator
+   *   The validator object to set.
+   */
+  public function setValidator(ValidatorInterface $validator);
+
+  /**
+   * Gets the validation constraint manager.
+   *
+   * @return \Drupal\Core\Validation\ConstraintManager
+   *   The constraint manager.
+   */
+  public function getValidationConstraintManager();
+
+  /**
+   * Sets the validation constraint manager.
+   *
+   * The validation constraint manager is used to instantiate validation
+   * constraint plugins.
+   *
+   * @param \Drupal\Core\Validation\ConstraintManager
+   *   The constraint manager to set.
+   */
+  public function setValidationConstraintManager(ConstraintManager $constraintManager);
+
+  /**
+   * Gets default constraints for the given data definition.
+   *
+   * This generates default constraint definitions based on the data definition;
+   * e.g. a NotNull constraint is generated if the data is defined as required.
+   * Besides that any constraints defined for the data type, i.e. below the
+   * 'constraint' key of the type's plugin definition, are taken into account.
+   *
+   * @param \Drupal\Core\TypedData\DataDefinitionInterface $definition
+   *   A data definition.
+   *
+   * @return array
+   *   An array of validation constraint definitions, keyed by constraint name.
+   *   Each constraint definition can be used for instantiating
+   *   \Symfony\Component\Validator\Constraint objects.
+   */
+  public function getDefaultConstraints(DataDefinitionInterface $definition);
+
+  /**
+   * Gets the canonical representation of a TypedData object.
+   *
+   * The canonical representation is typically used when data is passed on to
+   * other code components. In many use cases, the TypedData object is mostly
+   * unified adapter wrapping a primary value (e.g. a string, an entity...)
+   * which is the canonical representation that consuming code like constraint
+   * validators are really interested in. For some APIs, though, the domain
+   * object (e.g. Field API's FieldItem and FieldItemList) directly implements
+   * TypedDataInterface, and the canonical representation is thus the data
+   * object itself.
+   *
+   * When a TypedData object gets validated, for example, its canonical
+   * representation is passed on to constraint validators, which thus receive
+   * an Entity unwrapped, but a FieldItem as is.
+   *
+   * Data types specify whether their data objects need unwrapping by using the
+   * 'unwrap_for_canonical_representation' property in the data definition
+   * (defaults to TRUE).
+   *
+   * @param \Drupal\Core\TypedData\TypedDataInterface $data
+   *   The data.
+   *
+   * @return mixed
+   *   The canonical representation of the passed data.
+   */
+  public function getCanonicalRepresentation(TypedDataInterface $data);
+
+}
diff --git a/core/lib/Drupal/Core/TypedData/TypedDataTrait.php b/core/lib/Drupal/Core/TypedData/TypedDataTrait.php
index 737a86a25e44..b2cde549fef9 100644
--- a/core/lib/Drupal/Core/TypedData/TypedDataTrait.php
+++ b/core/lib/Drupal/Core/TypedData/TypedDataTrait.php
@@ -15,19 +15,19 @@ trait TypedDataTrait {
   /**
    * The typed data manager used for creating the data types.
    *
-   * @var \Drupal\Core\TypedData\TypedDataManager
+   * @var \Drupal\Core\TypedData\TypedDataManagerInterface
    */
   protected $typedDataManager;
 
   /**
    * Sets the typed data manager.
    *
-   * @param \Drupal\Core\TypedData\TypedDataManager $typed_data_manager
+   * @param \Drupal\Core\TypedData\TypedDataManagerInterface $typed_data_manager
    *   The typed data manager.
    *
    * @return $this
    */
-  public function setTypedDataManager(TypedDataManager $typed_data_manager) {
+  public function setTypedDataManager(TypedDataManagerInterface $typed_data_manager) {
     $this->typedDataManager = $typed_data_manager;
     return $this;
   }
@@ -35,7 +35,7 @@ public function setTypedDataManager(TypedDataManager $typed_data_manager) {
   /**
    * Gets the typed data manager.
    *
-   * @return \Drupal\Core\TypedData\TypedDataManager
+   * @return \Drupal\Core\TypedData\TypedDataManagerInterface
    *   The typed data manager.
    */
   public function getTypedDataManager() {
diff --git a/core/lib/Drupal/Core/TypedData/Validation/RecursiveContextualValidator.php b/core/lib/Drupal/Core/TypedData/Validation/RecursiveContextualValidator.php
index 81b8eeba8560..05fe0a04be43 100644
--- a/core/lib/Drupal/Core/TypedData/Validation/RecursiveContextualValidator.php
+++ b/core/lib/Drupal/Core/TypedData/Validation/RecursiveContextualValidator.php
@@ -10,7 +10,7 @@
 use Drupal\Core\TypedData\ComplexDataInterface;
 use Drupal\Core\TypedData\ListInterface;
 use Drupal\Core\TypedData\TypedDataInterface;
-use Drupal\Core\TypedData\TypedDataManager;
+use Drupal\Core\TypedData\TypedDataManagerInterface;
 use Symfony\Component\Validator\Constraint;
 use Symfony\Component\Validator\ConstraintValidatorFactoryInterface;
 use Symfony\Component\Validator\Context\ExecutionContextInterface;
@@ -64,10 +64,10 @@ class RecursiveContextualValidator implements ContextualValidatorInterface {
    *   The metadata factory.
    * @param \Symfony\Component\Validator\ConstraintValidatorFactoryInterface $validator_factory
    *   The constraint validator factory.
-   * @param \Drupal\Core\TypedData\TypedDataManager $typed_data_manager
+   * @param \Drupal\Core\TypedData\TypedDataManagerInterface $typed_data_manager
    *   The typed data manager.
    */
-  public function __construct(ExecutionContextInterface $context, MetadataFactoryInterface $metadata_factory, ConstraintValidatorFactoryInterface $validator_factory, TypedDataManager $typed_data_manager) {
+  public function __construct(ExecutionContextInterface $context, MetadataFactoryInterface $metadata_factory, ConstraintValidatorFactoryInterface $validator_factory, TypedDataManagerInterface $typed_data_manager) {
     $this->context = $context;
     $this->metadataFactory = $metadata_factory;
     $this->constraintValidatorFactory = $validator_factory;
diff --git a/core/lib/Drupal/Core/TypedData/Validation/RecursiveValidator.php b/core/lib/Drupal/Core/TypedData/Validation/RecursiveValidator.php
index c828cba51abf..e5260f750a93 100644
--- a/core/lib/Drupal/Core/TypedData/Validation/RecursiveValidator.php
+++ b/core/lib/Drupal/Core/TypedData/Validation/RecursiveValidator.php
@@ -8,7 +8,7 @@
 namespace Drupal\Core\TypedData\Validation;
 
 use Drupal\Core\TypedData\TypedDataInterface;
-use Drupal\Core\TypedData\TypedDataManager;
+use Drupal\Core\TypedData\TypedDataManagerInterface;
 use Symfony\Component\Validator\ConstraintValidatorFactoryInterface;
 use Symfony\Component\Validator\Context\ExecutionContextFactoryInterface;
 use Symfony\Component\Validator\Context\ExecutionContextInterface;
@@ -44,10 +44,10 @@ class RecursiveValidator implements ValidatorInterface {
    *   The factory for creating new contexts.
    * @param \Symfony\Component\Validator\ConstraintValidatorFactoryInterface $validator_factory
    *   The constraint validator factory.
-   * @param \Drupal\Core\TypedData\TypedDataManager $typed_data_manager
+   * @param \Drupal\Core\TypedData\TypedDataManagerInterface $typed_data_manager
    *   The typed data manager.
    */
-  public function __construct(ExecutionContextFactoryInterface $context_factory, ConstraintValidatorFactoryInterface $validator_factory, TypedDataManager $typed_data_manager) {
+  public function __construct(ExecutionContextFactoryInterface $context_factory, ConstraintValidatorFactoryInterface $validator_factory, TypedDataManagerInterface $typed_data_manager) {
     $this->contextFactory = $context_factory;
     $this->constraintValidatorFactory = $validator_factory;
     $this->typedDataManager = $typed_data_manager;
-- 
GitLab