You are here

class TypedDataManager in Drupal 9

Same name and namespace in other branches
  1. 8 core/lib/Drupal/Core/TypedData/TypedDataManager.php \Drupal\Core\TypedData\TypedDataManager

Manages data type plugins.

Hierarchy

Expanded class hierarchy of TypedDataManager

6 files declare their use of TypedDataManager
ContextDefinitionIsSatisfiedTest.php in core/tests/Drupal/Tests/Core/Plugin/Context/ContextDefinitionIsSatisfiedTest.php
ContextHandlerTest.php in core/tests/Drupal/Tests/Core/Plugin/ContextHandlerTest.php
Contains \Drupal\Tests\Core\Plugin\ContextHandlerTest.
EntityContextDefinitionIsSatisfiedTest.php in core/tests/Drupal/Tests/Core/Plugin/Context/EntityContextDefinitionIsSatisfiedTest.php
FieldDefinitionTest.php in core/tests/Drupal/Tests/Core/Entity/FieldDefinitionTest.php
RecursiveContextualValidatorTest.php in core/tests/Drupal/Tests/Core/TypedData/RecursiveContextualValidatorTest.php
Contains \Drupal\Tests\Core\TypedData\RecursiveContextualValidatorTest.

... See full list

1 string reference to 'TypedDataManager'
core.services.yml in core/core.services.yml
core/core.services.yml
1 service uses TypedDataManager
typed_data_manager in core/core.services.yml
Drupal\Core\TypedData\TypedDataManager

File

core/lib/Drupal/Core/TypedData/TypedDataManager.php, line 21

Namespace

Drupal\Core\TypedData
View source
class TypedDataManager extends DefaultPluginManager implements TypedDataManagerInterface {
  use DependencySerializationTrait;

  /**
   * The validator used for validating typed data.
   *
   * @var \Symfony\Component\Validator\Validator\ValidatorInterface
   */
  protected $validator;

  /**
   * The validation constraint manager to use for instantiating constraints.
   *
   * @var \Drupal\Core\Validation\ConstraintManager
   */
  protected $constraintManager;

  /**
   * An array of typed data property prototypes.
   *
   * @var array
   */
  protected $prototypes = [];

  /**
   * The class resolver.
   *
   * @var \Drupal\Core\DependencyInjection\ClassResolverInterface
   */
  protected $classResolver;

  /**
   * Constructs a new TypedDataManager.
   *
   * @param \Traversable $namespaces
   *   An object that implements \Traversable which contains the root paths
   *   keyed by the corresponding namespace to look for plugin implementations.
   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
   *   Cache backend instance to use.
   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
   *   The module handler.
   * @param \Drupal\Core\DependencyInjection\ClassResolverInterface $class_resolver
   *   The class resolver.
   */
  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, ClassResolverInterface $class_resolver) {
    $this
      ->alterInfo('data_type_info');
    $this
      ->setCacheBackend($cache_backend, 'typed_data_types_plugins');
    $this->classResolver = $class_resolver;
    parent::__construct('Plugin/DataType', $namespaces, $module_handler, NULL, 'Drupal\\Core\\TypedData\\Annotation\\DataType');
  }

  /**
   * {@inheritdoc}
   */
  public function createInstance($data_type, array $configuration = []) {
    $data_definition = $configuration['data_definition'];
    $type_definition = $this
      ->getDefinition($data_type);
    if (!isset($type_definition)) {
      throw new \InvalidArgumentException("Invalid data type '{$data_type}' has been given");
    }

    // Allow per-data definition overrides of the used classes, i.e. take over
    // classes specified in the type definition.
    $class = $data_definition
      ->getClass();
    if (!isset($class)) {
      throw new PluginException(sprintf('The plugin (%s) did not specify an instance class.', $data_type));
    }
    $typed_data = $class::createInstance($data_definition, $configuration['name'], $configuration['parent']);
    $typed_data
      ->setTypedDataManager($this);
    return $typed_data;
  }

  /**
   * {@inheritdoc}
   */
  public function create(DataDefinitionInterface $definition, $value = NULL, $name = NULL, $parent = NULL) {
    $typed_data = $this
      ->createInstance($definition
      ->getDataType(), [
      'data_definition' => $definition,
      'name' => $name,
      'parent' => $parent,
    ]);
    if (isset($value)) {
      $typed_data
        ->setValue($value, FALSE);
    }
    return $typed_data;
  }

  /**
   * {@inheritdoc}
   */
  public function createDataDefinition($data_type) {
    $type_definition = $this
      ->getDefinition($data_type);
    if (!isset($type_definition)) {
      throw new \InvalidArgumentException("Invalid data type '{$data_type}' has been given");
    }
    $class = $type_definition['definition_class'];
    $data_definition = $class::createFromDataType($data_type);
    if (method_exists($data_definition, 'setTypedDataManager')) {
      $data_definition
        ->setTypedDataManager($this);
    }
    return $data_definition;
  }

  /**
   * {@inheritdoc}
   */
  public function createListDataDefinition($item_type) {
    $type_definition = $this
      ->getDefinition($item_type);
    if (!isset($type_definition)) {
      throw new \InvalidArgumentException("Invalid data type '{$item_type}' has been given");
    }
    $class = $type_definition['list_definition_class'];
    return $class::createFromItemType($item_type);
  }

  /**
   * {@inheritdoc}
   */
  public function getInstance(array $options) {
    return $this
      ->getPropertyInstance($options['object'], $options['property'], $options['value']);
  }

  /**
   * {@inheritdoc}
   */
  public function getPropertyInstance(TypedDataInterface $object, $property_name, $value = NULL) {

    // For performance, try to reuse existing prototypes instead of
    // constructing new objects when possible. A prototype is reused when
    // creating a data object:
    // - for a similar root object (same data type and settings),
    // - at the same property path under that root object.
    $root_definition = $object
      ->getRoot()
      ->getDataDefinition();

    // If the root object is a list, we want to look at the data type and the
    // settings of its item definition.
    if ($root_definition instanceof ListDataDefinition) {
      $root_definition = $root_definition
        ->getItemDefinition();
    }

    // Root data type and settings.
    $parts[] = $root_definition
      ->getDataType();
    if ($settings = $root_definition
      ->getSettings()) {

      // Include the settings serialized as JSON as part of the key. The JSON is
      // a shorter string than the serialized form, so array access is faster.
      $parts[] = json_encode($settings);
    }

    // Property path for the requested data object.
    $parts[] = $object
      ->getPropertyPath();

    // Only property instances of complex data types should be cached by the
    // property name, as they represent different properties. Properties of list
    // data types are the items of the list and the property name represents
    // only the delta in that list and not an unique property, which is why all
    // items should use the same prototype.
    if ($object instanceof ComplexDataInterface) {
      $parts[] = $property_name;
    }
    $key = implode(':', $parts);

    // Create the prototype if needed.
    if (!isset($this->prototypes[$key])) {

      // Fetch the data definition for the child object from the parent.
      if ($object instanceof ComplexDataInterface) {
        $definition = $object
          ->getDataDefinition()
          ->getPropertyDefinition($property_name);
      }
      elseif ($object instanceof ListInterface) {
        $definition = $object
          ->getItemDefinition();
      }
      else {
        throw new \InvalidArgumentException("The passed object has to either implement the ComplexDataInterface or the ListInterface.");
      }
      if (!$definition) {
        throw new \InvalidArgumentException("Property {$property_name} is unknown.");
      }

      // Create the prototype without any value, but with initial parenting
      // so that constructors can set up the objects correctly.
      $this->prototypes[$key] = $this
        ->create($definition, NULL, $property_name, $object);
    }

    // Clone the prototype, update its parenting information, and assign the
    // value.
    $property = clone $this->prototypes[$key];
    $property
      ->setContext($property_name, $object);
    if (isset($value)) {
      $property
        ->setValue($value, FALSE);
    }
    return $property;
  }

  /**
   * Sets the validator for validating typed data.
   *
   * @param \Symfony\Component\Validator\Validator\ValidatorInterface $validator
   *   The validator object to set.
   */
  public function setValidator(ValidatorInterface $validator) {
    $this->validator = $validator;
  }

  /**
   * {@inheritdoc}
   */
  public function getValidator() {
    if (!isset($this->validator)) {
      $this->validator = new RecursiveValidator(new ExecutionContextFactory(new DrupalTranslator()), new ConstraintValidatorFactory($this->classResolver), $this);
    }
    return $this->validator;
  }

  /**
   * {@inheritdoc}
   */
  public function setValidationConstraintManager(ConstraintManager $constraintManager) {
    $this->constraintManager = $constraintManager;
  }

  /**
   * {@inheritdoc}
   */
  public function getValidationConstraintManager() {
    return $this->constraintManager;
  }

  /**
   * {@inheritdoc}
   */
  public function getDefaultConstraints(DataDefinitionInterface $definition) {
    $constraints = [];
    $type_definition = $this
      ->getDefinition($definition
      ->getDataType());

    // Auto-generate a constraint for data types implementing a primitive
    // interface.
    if (is_subclass_of($type_definition['class'], '\\Drupal\\Core\\TypedData\\PrimitiveInterface')) {
      $constraints['PrimitiveType'] = [];
    }

    // Add in constraints specified by the data type.
    if (isset($type_definition['constraints'])) {
      $constraints += $type_definition['constraints'];
    }

    // Add the NotNull constraint for required data.
    if ($definition
      ->isRequired()) {
      $constraints['NotNull'] = [];
    }

    // Check if the class provides allowed values.
    if (is_subclass_of($definition
      ->getClass(), 'Drupal\\Core\\TypedData\\OptionsProviderInterface')) {
      $constraints['AllowedValues'] = [];
    }
    return $constraints;
  }

  /**
   * {@inheritdoc}
   */
  public function clearCachedDefinitions() {
    parent::clearCachedDefinitions();
    $this->prototypes = [];
  }

  /**
   * {@inheritdoc}
   */
  public function getCanonicalRepresentation(TypedDataInterface $data) {
    $data_definition = $data
      ->getDataDefinition();

    // In case a list is passed, respect the 'wrapped' key of its data type.
    if ($data_definition instanceof ListDataDefinitionInterface) {
      $data_definition = $data_definition
        ->getItemDefinition();
    }

    // Get the plugin definition of the used data type.
    $type_definition = $this
      ->getDefinition($data_definition
      ->getDataType());
    if (!empty($type_definition['unwrap_for_canonical_representation'])) {
      return $data
        ->getValue();
    }
    return $data;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
DefaultPluginManager::$additionalAnnotationNamespaces protected property Additional namespaces the annotation discovery mechanism should scan for annotation definitions.
DefaultPluginManager::$alterHook protected property Name of the alter hook if one should be invoked.
DefaultPluginManager::$cacheKey protected property The cache key.
DefaultPluginManager::$cacheTags protected property An array of cache tags to use for the cached definitions.
DefaultPluginManager::$defaults protected property A set of defaults to be referenced by $this->processDefinition() if additional processing of plugins is necessary or helpful for development purposes. 9
DefaultPluginManager::$moduleHandler protected property The module handler to invoke the alter hook. 1
DefaultPluginManager::$namespaces protected property An object that implements \Traversable which contains the root paths keyed by the corresponding namespace to look for plugin implementations.
DefaultPluginManager::$pluginDefinitionAnnotationName protected property The name of the annotation that contains the plugin definition.
DefaultPluginManager::$pluginInterface protected property The interface each plugin should implement. 1
DefaultPluginManager::$subdir protected property The subdirectory within a namespace to look for plugins, or FALSE if the plugins are in the top level of the namespace.
DefaultPluginManager::alterDefinitions protected function Invokes the hook to alter the definitions if the alter hook is set. 1
DefaultPluginManager::alterInfo protected function Sets the alter hook name.
DefaultPluginManager::extractProviderFromDefinition protected function Extracts the provider from a plugin definition.
DefaultPluginManager::findDefinitions protected function Finds plugin definitions. 7
DefaultPluginManager::getCacheContexts public function The cache contexts associated with this object. Overrides CacheableDependencyInterface::getCacheContexts
DefaultPluginManager::getCachedDefinitions protected function Returns the cached plugin definitions of the decorated discovery class.
DefaultPluginManager::getCacheMaxAge public function The maximum age for which this object may be cached. Overrides CacheableDependencyInterface::getCacheMaxAge
DefaultPluginManager::getCacheTags public function The cache tags associated with this object. Overrides CacheableDependencyInterface::getCacheTags
DefaultPluginManager::getDefinitions public function Gets the definition of all plugins for this type. Overrides DiscoveryTrait::getDefinitions 2
DefaultPluginManager::getDiscovery protected function Gets the plugin discovery. Overrides PluginManagerBase::getDiscovery 12
DefaultPluginManager::getFactory protected function Gets the plugin factory. Overrides PluginManagerBase::getFactory
DefaultPluginManager::processDefinition public function Performs extra processing on plugin definitions. 13
DefaultPluginManager::providerExists protected function Determines if the provider of a definition exists. 3
DefaultPluginManager::setCacheBackend public function Initialize the cache backend.
DefaultPluginManager::setCachedDefinitions protected function Sets a cache of plugin definitions for the decorated discovery class.
DefaultPluginManager::useCaches public function Disable the use of caches. Overrides CachedDiscoveryInterface::useCaches 1
DependencySerializationTrait::$_entityStorages protected property
DependencySerializationTrait::$_serviceIds protected property
DependencySerializationTrait::__sleep public function 2
DependencySerializationTrait::__wakeup public function 2
DiscoveryCachedTrait::$definitions protected property Cached definitions array. 1
DiscoveryCachedTrait::getDefinition public function Overrides DiscoveryTrait::getDefinition 3
DiscoveryTrait::doGetDefinition protected function Gets a specific plugin definition.
DiscoveryTrait::hasDefinition public function
PluginManagerBase::$discovery protected property The object that discovers plugins managed by this manager.
PluginManagerBase::$factory protected property The object that instantiates plugins managed by this manager.
PluginManagerBase::$mapper protected property The object that returns the preconfigured plugin instance appropriate for a particular runtime condition.
PluginManagerBase::handlePluginNotFound protected function Allows plugin managers to specify custom behavior if a plugin is not found. 1
TypedDataManager::$classResolver protected property The class resolver.
TypedDataManager::$constraintManager protected property The validation constraint manager to use for instantiating constraints.
TypedDataManager::$prototypes protected property An array of typed data property prototypes.
TypedDataManager::$validator protected property The validator used for validating typed data.
TypedDataManager::clearCachedDefinitions public function Clears static and persistent plugin definition caches. Overrides DefaultPluginManager::clearCachedDefinitions 1
TypedDataManager::create public function Creates a new typed data object instance. Overrides TypedDataManagerInterface::create
TypedDataManager::createDataDefinition public function Creates a new data definition object. Overrides TypedDataManagerInterface::createDataDefinition
TypedDataManager::createInstance public function Instantiates a typed data object. Overrides PluginManagerBase::createInstance
TypedDataManager::createListDataDefinition public function Creates a new list data definition for items of the given data type. Overrides TypedDataManagerInterface::createListDataDefinition
TypedDataManager::getCanonicalRepresentation public function Gets the canonical representation of a TypedData object. Overrides TypedDataManagerInterface::getCanonicalRepresentation
TypedDataManager::getDefaultConstraints public function Gets default constraints for the given data definition. Overrides TypedDataManagerInterface::getDefaultConstraints
TypedDataManager::getInstance public function Gets a preconfigured instance of a plugin. Overrides PluginManagerBase::getInstance
TypedDataManager::getPropertyInstance public function Get a typed data instance for a property of a given typed data object. Overrides TypedDataManagerInterface::getPropertyInstance
TypedDataManager::getValidationConstraintManager public function Gets the validation constraint manager. Overrides TypedDataManagerInterface::getValidationConstraintManager
TypedDataManager::getValidator public function Gets the validator for validating typed data. Overrides TypedDataManagerInterface::getValidator
TypedDataManager::setValidationConstraintManager public function Sets the validation constraint manager. Overrides TypedDataManagerInterface::setValidationConstraintManager
TypedDataManager::setValidator public function Sets the validator for validating typed data. Overrides TypedDataManagerInterface::setValidator
TypedDataManager::__construct public function Constructs a new TypedDataManager. Overrides DefaultPluginManager::__construct 1
UseCacheBackendTrait::$cacheBackend protected property Cache backend instance.
UseCacheBackendTrait::$useCaches protected property Flag whether caches should be used or skipped.
UseCacheBackendTrait::cacheGet protected function Fetches from the cache backend, respecting the use caches flag.
UseCacheBackendTrait::cacheSet protected function Stores data in the persistent cache, respecting the use caches flag.