Esempio n. 1
0
 /**
  * {@inheritdoc}
  */
 public function getRoot()
 {
     if (isset($this->parent)) {
         return $this->parent->getRoot();
     }
     // If no parent is set, this is the root of the data tree.
     return $this;
 }
Esempio n. 2
0
 /**
  * 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)
 {
     $definition = $object->getRoot()->getDataDefinition();
     // If the definition is a list, we need to look at the data type and the
     // settings of its item definition.
     if ($definition instanceof ListDataDefinition) {
         $definition = $definition->getItemDefinition();
     }
     $key = $definition->getDataType();
     if ($settings = $definition->getSettings()) {
         $key .= ':' . Crypt::hashBase64(serialize($settings));
     }
     $key .= ':' . $object->getPropertyPath() . '.';
     // If we are creating list items, we always use 0 in the key as all list
     // items look the same.
     $key .= is_numeric($property_name) ? 0 : $property_name;
     // Make sure we have a prototype. Then, clone the prototype and set object
     // specific values, i.e. the value and the context.
     if (!isset($this->prototypes[$key]) || !$key) {
         // Create the initial prototype. For that we need to fetch the definition
         // of the to be created property instance 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.");
         }
         // Make sure we have got a valid definition.
         if (!$definition) {
             throw new \InvalidArgumentException('Property ' . String::checkPlain($property_name) . ' is unknown.');
         }
         // Now create the prototype using the definition, but do not pass the
         // given value as it will serve as prototype for any further instance.
         $this->prototypes[$key] = $this->create($definition, NULL, $property_name, $object);
     }
     // Clone from the prototype, then update the parent relationship and set the
     // data value if necessary.
     $property = clone $this->prototypes[$key];
     $property->setContext($property_name, $object);
     if (isset($value)) {
         $property->setValue($value, FALSE);
     }
     return $property;
 }
Esempio n. 3
0
 /**
  * {@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()) {
         // Hash the settings into a string. crc32 is the fastest way to hash
         // something for non-cryptographic purposes.
         $parts[] = hash('crc32b', serialize($settings));
     }
     // Property path for the requested data object. When creating a list item,
     // use 0 in the key as all items look the same.
     $parts[] = $object->getPropertyPath() . '.' . (is_numeric($property_name) ? 0 : $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 correclty.
         $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;
 }