You are here

public function TypedDataManager::getPropertyInstance in Drupal 9

Same name and namespace in other branches
  1. 8 core/lib/Drupal/Core/TypedData/TypedDataManager.php \Drupal\Core\TypedData\TypedDataManager::getPropertyInstance()
  2. 10 core/lib/Drupal/Core/TypedData/TypedDataManager.php \Drupal\Core\TypedData\TypedDataManager::getPropertyInstance()

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; for example, 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.

Parameters

\Drupal\Core\TypedData\TypedDataInterface $object: The parent typed data object, implementing the TypedDataInterface and either the ListInterface or the ComplexDataInterface.

string $property_name: The name of the property to instantiate, or the delta of a list item.

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.

Return value

\Drupal\Core\TypedData\TypedDataInterface The new property instance.

Throws

\InvalidArgumentException If the given property is not known, or the passed object does not implement the ListInterface or the ComplexDataInterface.

Overrides TypedDataManagerInterface::getPropertyInstance

See also

\Drupal\Core\TypedData\TypedDataManager::create()

1 call to TypedDataManager::getPropertyInstance()
TypedDataManager::getInstance in core/lib/Drupal/Core/TypedData/TypedDataManager.php
Gets a preconfigured instance of a plugin.

File

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

Class

TypedDataManager
Manages data type plugins.

Namespace

Drupal\Core\TypedData

Code

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;
}