diff --git a/core/lib/Drupal/Core/Config/Schema/Mapping.php b/core/lib/Drupal/Core/Config/Schema/Mapping.php index c09d9ad..e958f07 100644 --- a/core/lib/Drupal/Core/Config/Schema/Mapping.php +++ b/core/lib/Drupal/Core/Config/Schema/Mapping.php @@ -9,6 +9,7 @@ use Drupal\Component\Utility\NestedArray; use Drupal\Core\TypedData\ComplexDataInterface; +use Drupal\Core\TypedData\TypedDataInterface; use \InvalidArgumentException; /** @@ -122,4 +123,14 @@ public function isEmpty() { return empty($this->value); } + /** + * Implements \Drupal\Core\TypedData\ComplexDataInterface::onChange(). + */ + public function onChange($property_name) { + // Notify the parent of changes. + if (isset($this->parent)) { + $this->parent->onChange($this->name); + } + } + } diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php index 49d2933..0b976c5 100644 --- a/core/lib/Drupal/Core/Entity/Entity.php +++ b/core/lib/Drupal/Core/Entity/Entity.php @@ -466,9 +466,9 @@ public function validate() { } /** - * Implements \Drupal\Core\TypedData\ComplexDataInterface::handleChanges(). + * Implements \Drupal\Core\TypedData\ComplexDataInterface::onChange(). */ - public function handleChanges($property_name, TypedDataInterface $property, $new_value) { + public function onChange($property_name) { // Nothing to do. } diff --git a/core/lib/Drupal/Core/Entity/EntityBCDecorator.php b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php index 3b8a069..497621e 100644 --- a/core/lib/Drupal/Core/Entity/EntityBCDecorator.php +++ b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php @@ -513,7 +513,7 @@ public function getExportProperties() { /** * Forwards the call to the decorated entity. */ - public function handleChanges($property_name, TypedDataInterface $property, $new_value) { - $this->decorated->handleChanges($property_name, $property, $new_value); + public function onChange($property_name) { + $this->decorated->onChange($property_name, $property, $new_value); } } diff --git a/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php b/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php index 701b461..ce1a98d 100644 --- a/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php +++ b/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php @@ -31,7 +31,7 @@ public function setValue($values, $notify = TRUE) { // Treat the values as property value of the first property, if no array is // given. if (!is_array($values)) { - $keys = array_keys($this->properties); + $keys = array_keys($this->getPropertyDefinitions()); $values = array($keys[0] => $values); } parent::setValue($values, $notify); @@ -52,11 +52,29 @@ public function __get($name) { } /** + * Overrides \Drupal\Core\TypedData\Type\Map::set(). + */ + public function set($property_name, $value) { + if (isset($this->properties[$property_name])) { + $this->properties[$property_name]->setValue($value); + } + else { + // Notify the parent of any changes to be made. + if (isset($this->parent)) { + $this->parent->onChange($this->name); + } + // Just set the plain value, which allows adding a new entry to the map. + $this->values[$property_name] = $value; + } + } + + /** * Implements \Drupal\Core\Entity\Field\FieldItemInterface::__set(). */ public function __set($name, $value) { - // Support setting values via property objects. - if ($value instanceof TypedDataInterface) { + // Support setting values via property objects, but take care in as the + // value of the 'entity' property is typed data also. + if ($value instanceof TypedDataInterface && !($value instanceof \Drupal\Core\Entity\EntityInterface)) { $value = $value->getValue(); } $this->set($name, $value); @@ -66,7 +84,7 @@ public function __set($name, $value) { * Implements \Drupal\Core\Entity\Field\FieldItemInterface::__isset(). */ public function __isset($name) { - return isset($this->values[$name]) || isset($this->properties[$name]); + return isset($this->values[$name]) || (isset($this->properties[$name]) && $this->properties[$name]->getValue() !== NULL); } /** @@ -77,12 +95,12 @@ public function __unset($name) { } /** - * Overrides \Drupal\Core\TypedData\Map::handleChanges(). + * Overrides \Drupal\Core\TypedData\Map::onChange(). */ - public function handleChanges($property_name, TypedDataInterface $property, $new_value) { + public function onChange($property_name) { // Notify the parent of changes. if (isset($this->parent)) { - $this->parent->handleChanges($this->name, $property, $new_value); + $this->parent->onChange($this->name); } // Remove the plain value, such that any further __get() calls go via the // updated property object. diff --git a/core/lib/Drupal/Core/Entity/Field/Type/EntityReferenceItem.php b/core/lib/Drupal/Core/Entity/Field/Type/EntityReferenceItem.php index 330eb99..6971e39 100644 --- a/core/lib/Drupal/Core/Entity/Field/Type/EntityReferenceItem.php +++ b/core/lib/Drupal/Core/Entity/Field/Type/EntityReferenceItem.php @@ -8,6 +8,7 @@ namespace Drupal\Core\Entity\Field\Type; use Drupal\Core\Entity\Field\FieldItemBase; +use Drupal\Core\TypedData\TypedDataInterface; /** * Defines the 'entity_reference' entity field item. @@ -69,37 +70,6 @@ public function getPropertyDefinitions() { } /** - * Overrides \Drupal\Core\Entity\Field\FieldItemBase::setValue(). - */ - public function setValue($values, $notify = TRUE) { - // Treat the values as property value of the entity field, if no array - // is given. That way we support setting the field by entity ID or object. - if (!is_array($values)) { - $values = array('entity' => $values); - } - // Notify the parent of any changes to be made. - if ($notify && isset($this->parent)) { - $this->parent->handleChanges($this->name, $this, $values); - } - - // Entity is computed out of the ID, so we only need to update the ID. Only - // set the entity field if no ID is given. - if (isset($values['target_id'])) { - $this->properties['target_id']->setValue($values['target_id'], FALSE); - } - elseif (isset($values['entity'])) { - $this->properties['entity']->setValue($values['entity'], FALSE); - } - else { - $this->properties['entity']->setValue(NULL, FALSE); - } - unset($values['entity'], $values['target_id']); - if ($values) { - throw new \InvalidArgumentException('Property ' . key($values) . ' is unknown.'); - } - } - - /** * Overrides \Drupal\Core\Entity\Field\FieldItemBase::__get(). */ public function __get($name) { @@ -116,22 +86,39 @@ public function get($property_name) { } /** - * Overrides \Drupal\Core\Entity\Field\FieldItemBase::__set(). - */ - public function __set($name, $value) { - // Support setting values via property objects, but take care in as the - // value of the 'entity' property is typed data also. - if ($value instanceof TypedDataInterface && !($value instanceof \Drupal\Core\Entity\EntityInterface)) { - $value = $value->getValue(); - } - $this->set($name, $value); - } - - /** * Implements \Drupal\Core\Entity\Field\FieldItemInterface::__isset(). */ public function __isset($property_name) { $property_name = ($property_name == 'value') ? 'target_id' : $property_name; return parent::__isset($property_name); } + + /** + * Overrides \Drupal\Core\Entity\Field\FieldItemBase::get(). + */ + public function setValue($values, $notify = TRUE) { + // Treat the values as property value of the first property, if no array is + // given. + if (!is_array($values)) { + $keys = array_keys($this->getPropertyDefinitions()); + $values = array($keys[0] => $values); + } + + // Notify the parent of any changes to be made. + if ($notify && isset($this->parent)) { + $this->parent->onChange($this->name); + } + $this->values = $values; + + // Update any existing property objects, except of 'entity'. + foreach ($this->properties as $name => $property) { + if ($name != 'entity') { + $value = NULL; + if (isset($values[$name])) { + $value = $values[$name]; + } + $property->setValue($value, FALSE); + } + } + } } diff --git a/core/lib/Drupal/Core/Entity/Field/Type/EntityTranslation.php b/core/lib/Drupal/Core/Entity/Field/Type/EntityTranslation.php index 134e91d..4765a54 100644 --- a/core/lib/Drupal/Core/Entity/Field/Type/EntityTranslation.php +++ b/core/lib/Drupal/Core/Entity/Field/Type/EntityTranslation.php @@ -11,6 +11,7 @@ use Drupal\Core\TypedData\ComplexDataInterface; use Drupal\Core\TypedData\TypedData; use ArrayIterator; +use Drupal\Core\TypedData\TypedDataInterface; use IteratorAggregate; use InvalidArgumentException; @@ -74,7 +75,7 @@ public function getValue() { public function setValue($values, $notify = TRUE) { // Notify the parent of any changes to be made. if ($notify && isset($this->parent)) { - $this->parent->handleChanges($this->name, $this, $values); + $this->parent->onChange($this->name); } $this->fields = $values; } @@ -197,6 +198,16 @@ public function isEmpty() { } /** + * Implements \Drupal\Core\TypedData\ComplexDataInterface::onChange(). + */ + public function onChange($property_name) { + // Notify the parent of changes. + if (isset($this->parent)) { + $this->parent->onChange($this->name); + } + } + + /** * Implements \Drupal\Core\TypedData\AccessibleInterface::access(). */ public function access($operation = 'view', \Drupal\user\Plugin\Core\Entity\User $account = NULL) { diff --git a/core/lib/Drupal/Core/Entity/Field/Type/EntityWrapper.php b/core/lib/Drupal/Core/Entity/Field/Type/EntityWrapper.php index 071ddb0..10492e6 100644 --- a/core/lib/Drupal/Core/Entity/Field/Type/EntityWrapper.php +++ b/core/lib/Drupal/Core/Entity/Field/Type/EntityWrapper.php @@ -8,7 +8,6 @@ namespace Drupal\Core\Entity\Field\Type; use Drupal\Core\Entity\EntityInterface; -use Drupal\Core\Entity\EntityNG; use Drupal\Core\TypedData\ComplexDataInterface; use Drupal\Core\TypedData\TypedData; use Drupal\Core\TypedData\TypedDataInterface; @@ -74,18 +73,10 @@ public function getValue() { if (isset($this->newEntity)) { return $this->newEntity; } - $source = $this->getIdSource(); - $id = $source ? $source->getValue() : $this->id; - return $id ? entity_load($this->entityType, $id) : NULL; - } - - /** - * Helper to get the typed data object holding the source entity ID. - * - * @return \Drupal\Core\TypedData\TypedDataInterface|FALSE - */ - protected function getIdSource() { - return !empty($this->definition['settings']['id source']) ? $this->parent->get($this->definition['settings']['id source']) : FALSE; + if (!empty($this->definition['settings']['id source'])) { + $this->id = $this->parent->__get($this->definition['settings']['id source']); + } + return $this->id ? entity_load($this->entityType, $this->id) : NULL; } /** @@ -109,12 +100,15 @@ public function setValue($value, $notify = TRUE) { elseif (isset($value) && !(is_scalar($value) && !empty($this->definition['constraints']['EntityType']))) { throw new InvalidArgumentException('Value is not a valid entity.'); } - // Now update the value in the source or the local id property. - $source = $this->getIdSource(); - if ($source) { - $source->setValue($value); + // Update the 'id source' property, if given. + if (!empty($this->definition['settings']['id source'])) { + $this->parent->__set($this->definition['settings']['id source'], $value); } else { + // Notify the parent of any changes to be made. + if ($notify && isset($this->parent)) { + $this->parent->onChange($this->name); + } $this->id = $value; } } @@ -214,12 +208,12 @@ public function isEmpty() { } /** - * Implements \Drupal\Core\TypedData\ComplexDataInterface::handleChanges(). + * Implements \Drupal\Core\TypedData\ComplexDataInterface::onChange(). */ - public function handleChanges($property_name, TypedDataInterface $property, $new_value) { + public function onChange($property_name) { // Notify the parent of changes. if (isset($this->parent)) { - $this->parent->handleChanges($this->name, $property, $new_value); + $this->parent->onChange($this->name); } } } diff --git a/core/lib/Drupal/Core/Entity/Field/Type/Field.php b/core/lib/Drupal/Core/Entity/Field/Type/Field.php index b39e9a5..8c5451a 100644 --- a/core/lib/Drupal/Core/Entity/Field/Type/Field.php +++ b/core/lib/Drupal/Core/Entity/Field/Type/Field.php @@ -66,7 +66,11 @@ public function getValue() { /** * Overrides \Drupal\Core\TypedData\ItemList::setValue(). */ - public function setValue($values) { + public function setValue($values, $notify = TRUE) { + // Notify the parent of any changes to be made. + if ($notify && isset($this->parent)) { + $this->parent->onChange($this->name); + } if (!isset($values) || $values === array()) { $this->list = $values; } @@ -114,7 +118,7 @@ public function getPropertyDefinitions() { * Implements \Drupal\Core\Entity\Field\FieldInterface::__get(). */ public function __get($property_name) { - return $this->offsetGet(0)->get($property_name)->getValue(); + return $this->offsetGet(0)->__get($property_name); } /** diff --git a/core/lib/Drupal/Core/Entity/Field/Type/LanguageItem.php b/core/lib/Drupal/Core/Entity/Field/Type/LanguageItem.php index b3765b1..4f16384 100644 --- a/core/lib/Drupal/Core/Entity/Field/Type/LanguageItem.php +++ b/core/lib/Drupal/Core/Entity/Field/Type/LanguageItem.php @@ -8,7 +8,7 @@ namespace Drupal\Core\Entity\Field\Type; use Drupal\Core\Entity\Field\FieldItemBase; -use InvalidArgumentException; +use Drupal\Core\TypedData\TypedDataInterface; /** * Defines the 'language_field' entity field item. @@ -25,6 +25,16 @@ class LanguageItem extends FieldItemBase { static $propertyDefinitions; /** + * Overrides \Drupal\Core\TypedData\TypedData::__construct(). + */ + public function __construct(array $definition, $name = NULL, TypedDataInterface $parent = NULL) { + $this->definition = $definition; + $this->setContext($name, $parent); + // Initialize the language property by default. + $this->properties['language'] = typed_data()->getPropertyInstance($this, 'language'); + } + + /** * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions(). */ public function getPropertyDefinitions() { @@ -47,30 +57,31 @@ public function getPropertyDefinitions() { } /** - * Overrides FieldItemBase::setValue(). + * Overrides \Drupal\Core\Entity\Field\FieldItemBase::get(). */ - public function setValue($values) { - // Treat the values as property value of the object property, if no array - // is given. That way we support setting the field by language code or - // object. + public function setValue($values, $notify = TRUE) { + // Treat the values as property value of the first property, if no array is + // given. if (!is_array($values)) { - $values = array('language' => $values); + $keys = array_keys($this->getPropertyDefinitions()); + $values = array($keys[0] => $values); } - // Language is computed out of the langcode, so we only need to update the - // langcode. Only set the language property if no langcode is given. - if (!empty($values['value'])) { - $this->properties['value']->setValue($values['value']); + // Notify the parent of any changes to be made. + if ($notify && isset($this->parent)) { + $this->parent->onChange($this->name); } - elseif (isset($values['language'])) { - $this->properties['language']->setValue($values['language']); - } - else { - $this->properties['language']->setValue(NULL); - } - unset($values['language'], $values['value']); - if ($values) { - throw new InvalidArgumentException('Property ' . key($values) . ' is unknown.'); + $this->values = $values; + + // Update any existing property objects, except of 'entity'. + foreach ($this->properties as $name => $property) { + if ($name != 'language') { + $value = NULL; + if (isset($values[$name])) { + $value = $values[$name]; + } + $property->setValue($value, FALSE); + } } } } diff --git a/core/lib/Drupal/Core/TypedData/ComplexDataInterface.php b/core/lib/Drupal/Core/TypedData/ComplexDataInterface.php index 132212a..e3a540b 100644 --- a/core/lib/Drupal/Core/TypedData/ComplexDataInterface.php +++ b/core/lib/Drupal/Core/TypedData/ComplexDataInterface.php @@ -122,19 +122,12 @@ public function getPropertyDefinitions(); public function isEmpty(); /** - * Handle changes to a child property or item, if any. + * React to changes to a child property. * - * For example, if the 'value' property of a child 'body' property is changed - * the body property would be passed along with property path 'body.value'. + * Note that this is invoked before any changes are applied. * * @param $property_name - * The name of the property which has been changed. - * @param \Drupal\Core\TypedData\TypedDataInterface $changed - * The typed data object being the source of the changes. This might be the - * direct child property notifying the parent of changes, or any other - * descendent item. - * @param mixed $new_value - * The new value being set on the changed object. + * The name of the property which is changed. */ - public function handleChanges($property_name, TypedDataInterface $changed, $new_value); + public function onChange($property_name); } diff --git a/core/lib/Drupal/Core/TypedData/ItemList.php b/core/lib/Drupal/Core/TypedData/ItemList.php index 24a7d72..88af366 100644 --- a/core/lib/Drupal/Core/TypedData/ItemList.php +++ b/core/lib/Drupal/Core/TypedData/ItemList.php @@ -41,7 +41,11 @@ public function getValue() { * @param array|null $values * An array of values of the field items, or NULL to unset the field. */ - public function setValue($values) { + public function setValue($values, $notify = TRUE) { + // Notify the parent of any changes to be made. + if ($notify && isset($this->parent)) { + $this->parent->onChange($this->name); + } if (!isset($values) || $values === array()) { $this->list = $values; } @@ -197,6 +201,16 @@ public function isEmpty() { } /** + * Implements \Drupal\Core\TypedData\ListInterface::onChange(). + */ + public function onChange($delta) { + // Notify the parent of changes. + if (isset($this->parent)) { + $this->parent->onChange($this->name); + } + } + + /** * Magic method: Implements a deep clone. */ public function __clone() { diff --git a/core/lib/Drupal/Core/TypedData/ListInterface.php b/core/lib/Drupal/Core/TypedData/ListInterface.php index 5bca254..2711cd4 100644 --- a/core/lib/Drupal/Core/TypedData/ListInterface.php +++ b/core/lib/Drupal/Core/TypedData/ListInterface.php @@ -20,7 +20,7 @@ * When implementing this interface which extends Traversable, make sure to list * IteratorAggregate or Iterator before this interface in the implements clause. */ -interface ListInterface extends ArrayAccess, Countable, Traversable, TypedDataInterface { +interface ListInterface extends TypedDataInterface, ArrayAccess, Countable, Traversable { /** * Determines whether the list contains any non-empty items. @@ -37,4 +37,14 @@ public function isEmpty(); * The data definition of contained items. */ public function getItemDefinition(); + + /** + * React to changes to a child item. + * + * Note that this is invoked before any changes are applied. + * + * @param $delta + * The delta of the item which is changed. + */ + public function onChange($delta); } diff --git a/core/lib/Drupal/Core/TypedData/Type/Binary.php b/core/lib/Drupal/Core/TypedData/Type/Binary.php index 3e4c312..f9c4985 100644 --- a/core/lib/Drupal/Core/TypedData/Type/Binary.php +++ b/core/lib/Drupal/Core/TypedData/Type/Binary.php @@ -53,7 +53,7 @@ public function getValue() { public function setValue($value, $notify = TRUE) { // Notify the parent of any changes to be made. if ($notify && isset($this->parent)) { - $this->parent->handleChanges($this->name, $this, $value); + $this->parent->onChange($this->name); } if (!isset($value)) { $this->handle = NULL; diff --git a/core/lib/Drupal/Core/TypedData/Type/Date.php b/core/lib/Drupal/Core/TypedData/Type/Date.php index dcf661a..c9b8c6b 100644 --- a/core/lib/Drupal/Core/TypedData/Type/Date.php +++ b/core/lib/Drupal/Core/TypedData/Type/Date.php @@ -34,7 +34,7 @@ class Date extends TypedData { public function setValue($value, $notify = TRUE) { // Notify the parent of any changes to be made. if ($notify && isset($this->parent)) { - $this->parent->handleChanges($this->name, $this, $value); + $this->parent->onChange($this->name); } // Don't try to create a date from an empty value. // It would default to the current time. diff --git a/core/lib/Drupal/Core/TypedData/Type/Duration.php b/core/lib/Drupal/Core/TypedData/Type/Duration.php index f91fcb9..52ba97d 100644 --- a/core/lib/Drupal/Core/TypedData/Type/Duration.php +++ b/core/lib/Drupal/Core/TypedData/Type/Duration.php @@ -34,7 +34,7 @@ class Duration extends TypedData { public function setValue($value, $notify = TRUE) { // Notify the parent of any changes to be made. if ($notify && isset($this->parent)) { - $this->parent->handleChanges($this->name, $this, $value); + $this->parent->onChange($this->name); } // Catch any exceptions thrown due to invalid values being passed. try { diff --git a/core/lib/Drupal/Core/TypedData/Type/Language.php b/core/lib/Drupal/Core/TypedData/Type/Language.php index c16fbc4..0127314 100644 --- a/core/lib/Drupal/Core/TypedData/Type/Language.php +++ b/core/lib/Drupal/Core/TypedData/Type/Language.php @@ -38,33 +38,21 @@ class Language extends TypedData { * Overrides TypedData::getValue(). */ public function getValue() { - $source = $this->getLanguageCodeSource(); - $langcode = $source ? $source->getValue() : $this->langcode; - if ($langcode) { - $language = language_load($langcode); + if (!empty($this->definition['settings']['langcode source'])) { + $this->langcode = $this->parent->__get($this->definition['settings']['langcode source']); + } + if ($this->langcode) { + $language = language_load($this->langcode); return $language ?: new LanguageObject(array('langcode' => $this->langcode)); } } /** - * Helper to get the typed data object holding the source language code. - * - * @return \Drupal\Core\TypedData\TypedDataInterface|FALSE - */ - protected function getLanguageCodeSource() { - return !empty($this->definition['settings']['langcode source']) ? $this->parent->get($this->definition['settings']['langcode source']) : FALSE; - } - - /** * Overrides TypedData::setValue(). * * Both the langcode and the language object may be passed as value. */ public function setValue($value, $notify = TRUE) { - // Notify the parent of any changes to be made. - if ($notify && isset($this->parent)) { - $this->parent->handleChanges($this->name, $this, $value); - } // Support passing language objects. if (is_object($value)) { $value = $value->langcode; @@ -72,12 +60,15 @@ public function setValue($value, $notify = TRUE) { elseif (isset($value) && !is_scalar($value)) { throw new InvalidArgumentException('Value is no valid langcode or language object.'); } - // Now update the value in the source or the local langcode property. - $source = $this->getLanguageCodeSource(); - if ($source) { - $source->setValue($value); + // Update the 'langcode source' property, if given. + if (!empty($this->definition['settings']['langcode source'])) { + $this->parent->__set($this->definition['settings']['langcode source'], $value); } else { + // Notify the parent of any changes to be made. + if ($notify && isset($this->parent)) { + $this->parent->onChange($this->name); + } $this->langcode = $value; } } diff --git a/core/lib/Drupal/Core/TypedData/Type/Map.php b/core/lib/Drupal/Core/TypedData/Type/Map.php index 2464c23..a05497d 100644 --- a/core/lib/Drupal/Core/TypedData/Type/Map.php +++ b/core/lib/Drupal/Core/TypedData/Type/Map.php @@ -58,7 +58,13 @@ public function getValue() { foreach ($this->properties as $name => $property) { $definition = $property->getDefinition(); if (empty($definition['computed'])) { - $this->values[$name] = $property->getValue(); + $value = $property->getValue(); + if (isset($value)) { + $this->values[$name] = $property->getValue(); + } + else { + unset($this->values[$name]); + } } } return $this->values; @@ -76,20 +82,17 @@ public function setValue($values, $notify = TRUE) { } // Notify the parent of any changes to be made. if ($notify && isset($this->parent)) { - $this->parent->handleChanges($this->name, $this, $value); + $this->parent->onChange($this->name); } $this->values = $values; // Update any existing property objects. foreach ($this->properties as $name => $property) { - $definition = $property->getDefinition(); - if (empty($definition['computed'])) { - $value = NULL; - if (isset($values[$name])) { - $value = $values[$name]; - } - $property->setValue($value, FALSE); + $value = NULL; + if (isset($values[$name])) { + $value = $values[$name]; } + $property->setValue($value, FALSE); } } @@ -110,8 +113,12 @@ public function getString() { */ public function get($property_name) { if (!isset($this->properties[$property_name])) { + $value = NULL; + if (isset($this->values[$property_name])) { + $value = $this->values[$property_name]; + } // If the property is unknown, this will throw an exception. - $this->properties[$property_name] = typed_data()->getPropertyInstance($this, $property_name); + $this->properties[$property_name] = typed_data()->getPropertyInstance($this, $property_name, $value); } return $this->properties[$property_name]; } @@ -198,19 +205,19 @@ public function isEmpty() { * Magic method: Implements a deep clone. */ public function __clone() { - foreach ($this->getProperties() as $name => $property) { + foreach ($this->properties as $name => $property) { $this->properties[$name] = clone $property; $this->properties[$name]->setContext($name, $this); } } /** - * Implements \Drupal\Core\TypedData\ComplexDataInterface::handleChanges(). + * Implements \Drupal\Core\TypedData\ComplexDataInterface::onChange(). */ - public function handleChanges($property_name, TypedDataInterface $property, $new_value) { + public function onChange($property_name) { // Notify the parent of changes. if (isset($this->parent)) { - $this->parent->handleChanges($this->name, $property, $new_value); + $this->parent->onChange($this->name); } } } diff --git a/core/lib/Drupal/Core/TypedData/TypedData.php b/core/lib/Drupal/Core/TypedData/TypedData.php index 1ea98c2..e9558f3 100644 --- a/core/lib/Drupal/Core/TypedData/TypedData.php +++ b/core/lib/Drupal/Core/TypedData/TypedData.php @@ -52,7 +52,8 @@ */ public function __construct(array $definition, $name = NULL, TypedDataInterface $parent = NULL) { $this->definition = $definition; - $this->setContext($name, $parent); + $this->parent = $parent; + $this->name = $name; } /** @@ -82,7 +83,7 @@ public function getValue() { public function setValue($value, $notify = TRUE) { // Notify the parent of any changes to be made. if ($notify && isset($this->parent)) { - $this->parent->handleChanges($this->name, $this, $value); + $this->parent->onChange($this->name); } $this->value = $value; } diff --git a/core/lib/Drupal/Core/TypedData/TypedDataManager.php b/core/lib/Drupal/Core/TypedData/TypedDataManager.php index 098be1f..195e32d 100644 --- a/core/lib/Drupal/Core/TypedData/TypedDataManager.php +++ b/core/lib/Drupal/Core/TypedData/TypedDataManager.php @@ -145,7 +145,7 @@ public function createInstance($plugin_id, array $configuration, $name = NULL, $ public function create(array $definition, $value = NULL, $name = NULL, $parent = NULL) { $wrapper = $this->factory->createInstance($definition['type'], $definition, $name, $parent); if (isset($value)) { - $wrapper->setValue($value); + $wrapper->setValue($value, FALSE); } return $wrapper; } @@ -249,7 +249,7 @@ public function getPropertyInstance($object, $property_name, $value = NULL) { $property = clone $this->prototypes[$key]; $property->setContext($property_name, $object); if (isset($value)) { - $property->setValue($value); + $property->setValue($value, FALSE); } return $property; } diff --git a/core/modules/file/lib/Drupal/file/Type/FileItem.php b/core/modules/file/lib/Drupal/file/Type/FileItem.php index e1c7d24..a4dd7e5 100644 --- a/core/modules/file/lib/Drupal/file/Type/FileItem.php +++ b/core/modules/file/lib/Drupal/file/Type/FileItem.php @@ -8,6 +8,7 @@ namespace Drupal\file\Type; use Drupal\Core\Entity\Field\FieldItemBase; +use Drupal\Core\TypedData\TypedDataInterface; /** * Defines the 'file_field' entity field item. @@ -24,6 +25,16 @@ class FileItem extends FieldItemBase { static $propertyDefinitions; /** + * Overrides \Drupal\Core\TypedData\TypedData::__construct(). + */ + public function __construct(array $definition, $name = NULL, TypedDataInterface $parent = NULL) { + $this->definition = $definition; + $this->setContext($name, $parent); + // Initialize the entity property by default. + $this->properties['entity'] = typed_data()->getPropertyInstance($this, 'entity'); + } + + /** * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions(). */ public function getPropertyDefinitions() { @@ -57,37 +68,31 @@ public function getPropertyDefinitions() { } /** - * Overrides \Drupal\Core\Entity\Field\FieldItemBase::setValue(). + * Overrides \Drupal\Core\Entity\Field\FieldItemBase::get(). */ - public function setValue($values) { - // Treat the values as property value of the entity field, if no array - // is given. + public function setValue($values, $notify = TRUE) { + // Treat the values as property value of the first property, if no array is + // given. if (!is_array($values)) { - $values = array('entity' => $values); + $keys = array_keys($this->getPropertyDefinitions()); + $values = array($keys[0] => $values); } - if (isset($values['display'])) { - $this->properties['display']->setValue($values['display']); - } - if (isset($values['description'])) { - $this->properties['description']->setValue($values['description']); + // Notify the parent of any changes to be made. + if ($notify && isset($this->parent)) { + $this->parent->onChange($this->name); } + $this->values = $values; - // Entity is computed out of the ID, so we only need to update the ID. Only - // set the entity field if no ID is given. - if (isset($values['fid'])) { - $this->properties['fid']->setValue($values['fid']); - } - elseif (isset($values['entity'])) { - $this->properties['entity']->setValue($values['entity']); - } - else { - $this->properties['entity']->setValue(NULL); - } - unset($values['entity'], $values['fid'], $values['display'], $values['description']); - if ($values) { - throw new \InvalidArgumentException('Property ' . key($values) . ' is unknown.'); + // Update any existing property objects, except of 'entity'. + foreach ($this->properties as $name => $property) { + if ($name != 'entity') { + $value = NULL; + if (isset($values[$name])) { + $value = $values[$name]; + } + $property->setValue($value, FALSE); + } } } - } diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Type/TaxonomyTermReferenceItem.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Type/TaxonomyTermReferenceItem.php index 7f7ab02..4029e90 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Type/TaxonomyTermReferenceItem.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Type/TaxonomyTermReferenceItem.php @@ -8,6 +8,7 @@ namespace Drupal\taxonomy\Type; use Drupal\Core\Entity\Field\FieldItemBase; +use Drupal\Core\TypedData\TypedDataInterface; /** * Defines the 'taxonomy_term_reference' entity field item. @@ -24,6 +25,16 @@ class TaxonomyTermReferenceItem extends FieldItemBase { static $propertyDefinitions; /** + * Overrides \Drupal\Core\TypedData\TypedData::__construct(). + */ + public function __construct(array $definition, $name = NULL, TypedDataInterface $parent = NULL) { + $this->definition = $definition; + $this->setContext($name, $parent); + // Initialize the entity property by default. + $this->properties['entity'] = typed_data()->getPropertyInstance($this, 'entity'); + } + + /** * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions(). */ public function getPropertyDefinitions() { @@ -49,30 +60,31 @@ public function getPropertyDefinitions() { } /** - * Overrides \Drupal\Core\Entity\Field\FieldItemBase::setValue(). + * Overrides \Drupal\Core\Entity\Field\FieldItemBase::get(). */ - public function setValue($values) { - // Treat the values as property value of the entity field, if no array - // is given. + public function setValue($values, $notify = TRUE) { + // Treat the values as property value of the first property, if no array is + // given. if (!is_array($values)) { - $values = array('entity' => $values); + $keys = array_keys($this->getPropertyDefinitions()); + $values = array($keys[0] => $values); } - // Entity is computed out of the ID, so we only need to update the ID. Only - // set the entity field if no ID is given. - if (isset($values['tid'])) { - $this->properties['tid']->setValue($values['tid']); + // Notify the parent of any changes to be made. + if ($notify && isset($this->parent)) { + $this->parent->onChange($this->name); } - elseif (isset($values['entity'])) { - $this->properties['entity']->setValue($values['entity']); - } - else { - $this->properties['entity']->setValue(NULL); - } - unset($values['entity'], $values['tid']); - if ($values) { - throw new \InvalidArgumentException('Property ' . key($values) . ' is unknown.'); + $this->values = $values; + + // Update any existing property objects, except of 'entity'. + foreach ($this->properties as $name => $property) { + if ($name != 'entity') { + $value = NULL; + if (isset($values[$name])) { + $value = $values[$name]; + } + $property->setValue($value, FALSE); + } } } - } diff --git a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewUI.php b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewUI.php index 83abb4b..9114a6a 100644 --- a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewUI.php +++ b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewUI.php @@ -1069,9 +1069,9 @@ public function setContext($name = NULL, TypedDataInterface $parent = NULL) { } /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::handleChanges(). + * Implements \Drupal\Core\TypedData\TypedDataInterface::onChange(). */ - public function handleChanges($property_name, TypedDataInterface $property, $new_value) { + public function onChange($property_name) { return $this->__call(__FUNCTION__, func_get_args()); } }