diff --git a/core/lib/Drupal/Core/Config/Schema/ArrayElement.php b/core/lib/Drupal/Core/Config/Schema/ArrayElement.php index f801c28..4d9711e 100644 --- a/core/lib/Drupal/Core/Config/Schema/ArrayElement.php +++ b/core/lib/Drupal/Core/Config/Schema/ArrayElement.php @@ -12,6 +12,7 @@ use \Countable; use \IteratorAggregate; use \Traversable; +use Drupal\Core\TypedData\PrimitiveInterface; /** * Defines a generic configuration element that contains multiple properties. @@ -55,7 +56,7 @@ protected function getAllKeys() { protected abstract function parse(); /** - * Implements TypedDataInterface::validate(). + * {@inheritdoc} */ public function validate() { foreach ($this->getElements() as $element) { @@ -85,7 +86,7 @@ public function offsetGet($offset) { * Implements ArrayAccess::offsetSet(). */ public function offsetSet($offset, $value) { - if ($value instanceof TypedDataInterface) { + if ($value instanceof PrimitiveInterface) { $value = $value->getValue(); } $this->value[$offset] = $value; diff --git a/core/lib/Drupal/Core/Config/Schema/Element.php b/core/lib/Drupal/Core/Config/Schema/Element.php index d4e29db..bb748cf 100644 --- a/core/lib/Drupal/Core/Config/Schema/Element.php +++ b/core/lib/Drupal/Core/Config/Schema/Element.php @@ -28,4 +28,27 @@ protected function parseElement($key, $data, $definition) { return config_typed()->create($definition, $data, $key, $this); } + /** + * @todo + * Temporarily copied this method from TypedData where it's been removed + * because TypedDataInterface is removed. This will be fixed with + * https://drupal.org/node/1928868 + */ + public function getValue() { + return $this->value; + } + + /** + * @todo + * Temporarily copied this method from TypedData where it's been removed + * because TypedDataInterface is removed. This will be fixed with + * https://drupal.org/node/1928868 + */ + public function setValue($value, $notify = TRUE) { + $this->value = $value; + // Notify the parent of any changes. + if ($notify && isset($this->parent)) { + $this->parent->onChange($this->name); + } + } } diff --git a/core/lib/Drupal/Core/Config/Schema/Mapping.php b/core/lib/Drupal/Core/Config/Schema/Mapping.php index b7bddb3..1509421 100644 --- a/core/lib/Drupal/Core/Config/Schema/Mapping.php +++ b/core/lib/Drupal/Core/Config/Schema/Mapping.php @@ -9,7 +9,6 @@ use Drupal\Component\Utility\NestedArray; use Drupal\Core\TypedData\ComplexDataInterface; -use Drupal\Core\TypedData\TypedDataInterface; use \InvalidArgumentException; /** @@ -53,15 +52,11 @@ public function get($property_name) { * Implements Drupal\Core\TypedData\ComplexDataInterface::set(). */ public function set($property_name, $value, $notify = TRUE) { - // Notify the parent of any changes to be made. - if ($notify && isset($this->parent)) { - $this->parent->onChange($this->name); - } // Set the data into the configuration array but behave according to the // interface specification when we've got a null value. if (isset($value)) { $this->value[$property_name] = $value; - return $this->get($property_name); + $property = $this->get($property_name); } else { // In these objects, when clearing the value, the property is gone. @@ -69,8 +64,12 @@ public function set($property_name, $value, $notify = TRUE) { $property = $this->get($property_name); unset($this->value[$property_name]); $property->setValue($value); - return $property; } + // Notify the parent of any changes. + if ($notify && isset($this->parent)) { + $this->parent->onChange($this->name); + } + return $property; } /** diff --git a/core/lib/Drupal/Core/Config/Schema/Property.php b/core/lib/Drupal/Core/Config/Schema/Property.php index d7e4b60..d9ceacd 100644 --- a/core/lib/Drupal/Core/Config/Schema/Property.php +++ b/core/lib/Drupal/Core/Config/Schema/Property.php @@ -13,7 +13,7 @@ class Property extends Element { /** - * Implements TypedDataInterface::validate(). + * {@inheritdoc} */ public function validate() { return isset($this->value); diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php index 7712bf1..5741209 100644 --- a/core/lib/Drupal/Core/Entity/Entity.php +++ b/core/lib/Drupal/Core/Entity/Entity.php @@ -10,8 +10,6 @@ use Drupal\Component\Uuid\Uuid; use Drupal\Core\Language\Language; use Drupal\Core\TypedData\TranslatableInterface; -use Drupal\Core\TypedData\TypedDataInterface; -use Drupal\user\UserInterface; use IteratorAggregate; use Drupal\Core\Session\AccountInterface; @@ -425,62 +423,41 @@ public function getNGEntity() { } /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::getType(). + * {@inheritdoc} */ public function getType() { - // @todo: Incorporate the entity type here by making entities proper - // typed data. See http://drupal.org/node/1868004. - return 'entity'; + // @todo: This does not make much sense, so remove once TypedDataInterface + // is removed. See https://drupal.org/node/2002138. + if ($this->bundle() != $this->entityType()) { + return 'entity:' . $this->entityType() . ':' . $this->bundle(); + } + return 'entity:' . $this->entityType(); } /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::getDefinition(). + * {@inheritdoc} */ public function getDefinition() { + // @todo: This does not make much sense, so remove once TypedDataInterface + // is removed. See https://drupal.org/node/2002138. return array( 'type' => $this->getType() ); } /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::getValue(). - */ - public function getValue() { - // @todo: Implement by making entities proper typed data. See - // http://drupal.org/node/1868004. - } - - /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::setValue(). - */ - public function setValue($value, $notify = TRUE) { - // @todo: Implement by making entities proper typed data. See - // http://drupal.org/node/1868004. - } - - /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::getString(). - */ - public function getString() { - // @todo: Implement by making entities proper typed data. See - // http://drupal.org/node/1868004. - } - - /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::getConstraints(). + * {@inheritdoc} */ public function getConstraints() { - // @todo: Implement by making entities proper typed data. See - // http://drupal.org/node/1868004. return array(); } /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::validate(). + * {@inheritdoc} */ public function validate() { - // @todo: Implement by making entities proper typed data. See - // http://drupal.org/node/1868004. + // @todo: Add the typed data manager as proper dependency. + return \Drupal::typedData()->getValidator()->validate($this); } /** @@ -500,37 +477,37 @@ public function onChange($property_name) { } /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::getName(). + * {@inheritdoc} */ public function getName() { return NULL; } /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::getRoot(). + * {@inheritdoc} */ public function getRoot() { return $this; } /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::getPropertyPath(). + * {@inheritdoc} */ public function getPropertyPath() { return ''; } /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::getParent(). + * {@inheritdoc} */ public function getParent() { return NULL; } /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::setContext(). + * {@inheritdoc} */ - public function setContext($name = NULL, TypedDataInterface $parent = NULL) { + public function setContext($name = NULL, $parent = NULL) { // As entities are always the root of the tree of typed data, we do not need // to set any parent or name. } diff --git a/core/lib/Drupal/Core/Entity/EntityBCDecorator.php b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php index 52d3f6f..7af4a98 100644 --- a/core/lib/Drupal/Core/Entity/EntityBCDecorator.php +++ b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php @@ -10,7 +10,6 @@ use Drupal\Core\Language\Language; use IteratorAggregate; use Drupal\Core\Entity\EntityInterface; -use Drupal\Core\TypedData\TypedDataInterface; use Drupal\Core\Session\AccountInterface; /** @@ -184,6 +183,7 @@ public function __set($name, $value) { // out of sync. That way, the next field object instantiated by EntityNG // will hold the updated value. unset($this->decorated->fields[$name]); + $this->decorated->onChange($name); } /** @@ -508,7 +508,7 @@ public function getParent() { /** * Forwards the call to the decorated entity. */ - public function setContext($name = NULL, TypedDataInterface $parent = NULL) { + public function setContext($name = NULL, $parent = NULL) { $this->decorated->setContext($name, $parent); } diff --git a/core/lib/Drupal/Core/Entity/EntityInterface.php b/core/lib/Drupal/Core/Entity/EntityInterface.php index cdb4cd3..e965b8e 100644 --- a/core/lib/Drupal/Core/Entity/EntityInterface.php +++ b/core/lib/Drupal/Core/Entity/EntityInterface.php @@ -9,6 +9,7 @@ use Drupal\Core\TypedData\AccessibleInterface; use Drupal\Core\TypedData\ComplexDataInterface; +use Drupal\Core\TypedData\IdentifiableInterface; use Drupal\Core\TypedData\TranslatableInterface; /** @@ -27,16 +28,7 @@ * @see \Drupal\Core\TypedData\TypedDataManager * @see \Drupal\Core\Field\FieldInterface */ -interface EntityInterface extends ComplexDataInterface, AccessibleInterface, TranslatableInterface { - - /** - * Returns the entity identifier (the entity's machine name or numeric ID). - * - * @return - * The identifier of the entity, or NULL if the entity does not yet have - * an identifier. - */ - public function id(); +interface EntityInterface extends IdentifiableInterface, ComplexDataInterface, AccessibleInterface, TranslatableInterface { /** * Returns the entity UUID (Universally Unique Identifier). diff --git a/core/lib/Drupal/Core/Entity/EntityNG.php b/core/lib/Drupal/Core/Entity/EntityNG.php index 3d0c5c6..5d15d17 100644 --- a/core/lib/Drupal/Core/Entity/EntityNG.php +++ b/core/lib/Drupal/Core/Entity/EntityNG.php @@ -9,7 +9,7 @@ use Drupal\Core\Language\Language; use Drupal\Core\Session\AccountInterface; -use Drupal\Core\TypedData\TypedDataInterface; +use Drupal\Core\Entity\Field\FieldInterface; use ArrayIterator; use InvalidArgumentException; @@ -458,7 +458,7 @@ protected function getDefaultLanguage() { } if (empty($this->language)) { // Make sure we return a proper language object. - $this->language = new Language(array('id' => Language::LANGCODE_NOT_SPECIFIED)); + $this->language = new Language(array('id' => Language::LANGCODE_NOT_SPECIFIED, 'locked' => TRUE)); } } return $this->language; @@ -736,7 +736,7 @@ public function &__get($name) { */ public function __set($name, $value) { // Support setting values via property objects. - if ($value instanceof TypedDataInterface && !$value instanceof EntityInterface) { + if ($value instanceof FieldInterface && !$value instanceof EntityInterface) { $value = $value->getValue(); } // If this is an entity field, handle it accordingly. We first check whether @@ -841,12 +841,4 @@ public function label($langcode = NULL) { return $label; } - /** - * {@inheritdoc} - */ - public function validate() { - // @todo: Add the typed data manager as proper dependency. - return \Drupal::typedData()->getValidator()->validate($this); - } - } diff --git a/core/lib/Drupal/Core/Entity/Field/Field.php b/core/lib/Drupal/Core/Entity/Field/Field.php index 3948ddf..ed0d93d 100644 --- a/core/lib/Drupal/Core/Entity/Field/Field.php +++ b/core/lib/Drupal/Core/Entity/Field/Field.php @@ -9,7 +9,6 @@ use Drupal\Core\Entity\Field\FieldInterface; use Drupal\Core\Session\AccountInterface; -use Drupal\Core\TypedData\TypedDataInterface; use Drupal\Core\TypedData\ItemList; /** @@ -39,7 +38,7 @@ class Field extends ItemList implements FieldInterface { /** * Overrides TypedData::__construct(). */ - public function __construct(array $definition, $name = NULL, TypedDataInterface $parent = NULL) { + public function __construct(array $definition, $name = NULL, $parent = NULL) { parent::__construct($definition, $name, $parent); // Always initialize one empty item as most times a value for at least one // item will be present. That way prototypes created by @@ -77,10 +76,6 @@ public function getValue($include_computed = FALSE) { * Overrides \Drupal\Core\TypedData\ItemList::setValue(). */ 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; } @@ -108,6 +103,10 @@ public function setValue($values, $notify = TRUE) { } } } + // Notify the parent of any changes. + if ($notify && isset($this->parent)) { + $this->parent->onChange($this->name); + } } /** diff --git a/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php b/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php index cb243d5..96e996e 100644 --- a/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php +++ b/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php @@ -9,7 +9,7 @@ use Drupal\Core\Entity\EntityInterface; use Drupal\Core\TypedData\Plugin\DataType\Map; -use Drupal\Core\TypedData\TypedDataInterface; +use Drupal\Core\TypedData\PrimitiveInterface; use Drupal\user; /** @@ -25,7 +25,7 @@ /** * Overrides \Drupal\Core\TypedData\TypedData::__construct(). */ - public function __construct(array $definition, $name = NULL, TypedDataInterface $parent = NULL) { + public function __construct(array $definition, $name = NULL, $parent = NULL) { parent::__construct($definition, $name, $parent); // Initialize computed properties by default, such that they get cloned // with the whole item. @@ -49,10 +49,6 @@ public function setValue($values, $notify = TRUE) { $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. foreach ($this->properties as $name => $property) { @@ -63,6 +59,10 @@ public function setValue($values, $notify = TRUE) { $property->setValue($value, FALSE); unset($this->values[$name]); } + // Notify the parent of any changes. + if ($notify && isset($this->parent)) { + $this->parent->onChange($this->name); + } } /** @@ -83,10 +83,6 @@ public function __get($name) { * {@inheritdoc} */ public function set($property_name, $value, $notify = TRUE) { - // Notify the parent of any changes to be made. - if ($notify && isset($this->parent)) { - $this->parent->onChange($this->name); - } // For defined properties there is either a property object or a plain // value that needs to be updated. if (isset($this->properties[$property_name])) { @@ -97,6 +93,10 @@ public function set($property_name, $value, $notify = TRUE) { else { $this->values[$property_name] = $value; } + // Directly notify ourselves. + if ($notify) { + $this->onChange($property_name); + } } /** @@ -105,7 +105,7 @@ public function set($property_name, $value, $notify = TRUE) { 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 EntityInterface)) { + if ($value instanceof PrimitiveInterface && !($value instanceof EntityInterface)) { $value = $value->getValue(); } $this->set($name, $value); @@ -135,7 +135,9 @@ public function onChange($property_name) { } // Remove the plain value, such that any further __get() calls go via the // updated property object. - unset($this->values[$property_name]); + if (isset($this->properties[$property_name])) { + unset($this->values[$property_name]); + } } /** diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/EntityDeriver.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/EntityDeriver.php new file mode 100644 index 0000000..67ebea6 --- /dev/null +++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/EntityDeriver.php @@ -0,0 +1,67 @@ +derivatives) && !empty($this->derivatives[$derivative_id])) { + return $this->derivatives[$derivative_id]; + } + $this->getDerivativeDefinitions($base_plugin_definition); + if (isset($this->derivatives[$derivative_id])) { + return $this->derivatives[$derivative_id]; + } + } + + /** + * {@inheritdoc} + */ + public function getDerivativeDefinitions(array $base_plugin_definition) { + // Also keep the 'entity' defined as is. + $this->derivatives[''] = $base_plugin_definition; + // Add definitions for each entity type and bundle. + foreach (entity_get_info() as $entity_type => $info) { + $this->derivatives[$entity_type] = array( + 'label' => $info['label'], + 'class' => $info['class'], + 'constraints' => array('EntityType' => $entity_type), + ) + $base_plugin_definition; + + // Incorporate the bundles as entity:$entity_type:$bundle, if any. + foreach (entity_get_bundles($entity_type) as $bundle => $bundle_info) { + if ($bundle !== $entity_type) { + $this->derivatives[$entity_type . ':' . $bundle] = array( + 'label' => $bundle_info['label'], + 'class' => $info['class'], + 'constraints' => array( + 'EntityType' => $entity_type, + 'Bundle' => $bundle, + ), + ) + $base_plugin_definition; + } + } + } + return $this->derivatives; + } +} diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/FieldItemDeriver.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/FieldItemDeriver.php new file mode 100644 index 0000000..2a304df --- /dev/null +++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/FieldItemDeriver.php @@ -0,0 +1,46 @@ +derivatives)) { + $this->getDerivativeDefinitions($base_plugin_definition); + } + if (isset($this->derivatives[$derivative_id])) { + return $this->derivatives[$derivative_id]; + } + } + + /** + * {@inheritdoc} + */ + public function getDerivativeDefinitions(array $base_plugin_definition) { + foreach (\Drupal::service('plugin.manager.entity.field.field_type')->getDefinitions() as $plugin_id => $definition) { + $this->derivatives[$plugin_id] = $definition; + } + return $this->derivatives; + } + +} diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/Entity.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/Entity.php new file mode 100644 index 0000000..f1a61b0 --- /dev/null +++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/Entity.php @@ -0,0 +1,28 @@ + 'entity', + ); + if (isset($this->definition['constraints']['EntityType'])) { + $definition['type'] .= ':' . $this->definition['constraints']['EntityType']; + } + if (isset($this->definition['constraints']['Bundle']) && is_string($this->definition['constraints']['Bundle'])) { + $definition['type'] .= ':' . $this->definition['constraints']['Bundle']; + } + return $definition; + } + + /** + * {@inheritdoc} + */ + public function getTarget() { + if (!isset($this->target) && isset($this->id)) { + // If we have a valid reference, return the entity object which is typed + // data itself. + $this->target = entity_load($this->definition['constraints']['EntityType'], $this->id); + } + return $this->target; + } + + /** + * {@inheritdoc} + */ + public function getTargetIdentifier() { + if (isset($this->id)) { + return $this->id; + } + elseif ($entity = $this->getValue()) { + return $entity->id(); + } + } + + /** + * {@inheritdoc} + */ + public function getValue() { + // Entities are already typed data, so just return that. + return $this->getTarget(); + } + + /** + * {@inheritdoc} + */ + public function setValue($value, $notify = TRUE) { + unset($this->target); + unset($this->id); + + // Both the entity ID and the entity object may be passed as value. + if (!isset($value) || $value instanceof EntityInterface) { + // Enusre we set no BCEntity. + if (isset($value)) { + $value = $value->getNGEntity(); + } + $this->target = $value; + } + elseif (!is_scalar($value) || empty($this->definition['constraints']['EntityType'])) { + throw new \InvalidArgumentException('Value is not a valid entity.'); + } + else { + $this->id = $value; + } + // Notify the parent of any changes. + if ($notify && isset($this->parent)) { + $this->parent->onChange($this->name); + } + } + + /** + * {@inheritdoc} + */ + public function getString() { + if ($entity = $this->getValue()) { + return $entity->label(); + } + return ''; + } +} diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReferenceItem.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReferenceItem.php index 7f756ad..ae84ceb 100644 --- a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReferenceItem.php +++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReferenceItem.php @@ -10,13 +10,15 @@ use Drupal\Core\TypedData\Annotation\DataType; use Drupal\Core\Annotation\Translation; use Drupal\Core\Entity\Field\FieldItemBase; -use Drupal\Core\TypedData\TypedDataInterface; /** - * Defines the 'entity_reference' entity field item. + * Defines the 'entity_reference_item' entity field item. * - * Required settings (below the definition's 'settings' key) are: - * - target_type: The entity type to reference. + * Supported settings (below the definition's 'settings' key) are: + * - target_type: The entity type to reference. Required. + * - target_bundle: (optional): If set, restricts the entity bundles which may + * may be referenced. May be set to an single bundle, or to an array of + * allowed bundles. * * @DataType( * id = "entity_reference_field", @@ -40,11 +42,12 @@ class EntityReferenceItem extends FieldItemBase { * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions(). */ public function getPropertyDefinitions() { - // Definitions vary by entity type, so key them by entity type. - $target_type = $this->definition['settings']['target_type']; + // Definitions vary by entity type and bundle, so key them accordingly. + $key = $this->definition['settings']['target_type'] . ':'; + $key .= isset($this->definition['settings']['target_bundle']) ? $this->definition['settings']['target_bundle'] : ''; - if (!isset(self::$propertyDefinitions[$target_type])) { - static::$propertyDefinitions[$target_type]['target_id'] = array( + if (!isset(static::$propertyDefinitions[$key])) { + static::$propertyDefinitions[$key]['target_id'] = array( // @todo: Lookup the entity type's ID data type and use it here. 'type' => 'integer', 'label' => t('Entity ID'), @@ -52,20 +55,22 @@ public function getPropertyDefinitions() { 'Range' => array('min' => 0), ), ); - static::$propertyDefinitions[$target_type]['entity'] = array( - 'type' => 'entity', + static::$propertyDefinitions[$key]['entity'] = array( + 'type' => 'entity_reference', 'constraints' => array( - 'EntityType' => $target_type, + 'EntityType' => $this->definition['settings']['target_type'], ), 'label' => t('Entity'), 'description' => t('The referenced entity'), // The entity object is computed out of the entity ID. 'computed' => TRUE, 'read-only' => FALSE, - 'settings' => array('id source' => 'target_id'), ); + if (isset($this->definition['settings']['target_bundle'])) { + static::$propertyDefinitions[$key]['entity']['constraints']['Bundle'] = $this->definition['settings']['target_bundle']; + } } - return static::$propertyDefinitions[$target_type]; + return static::$propertyDefinitions[$key]; } /** @@ -96,12 +101,14 @@ public function __isset($property_name) { * Overrides \Drupal\Core\Entity\Field\FieldItemBase::get(). */ public function setValue($values, $notify = TRUE) { - // Treat the values as value of the entity property, if no array is - // given as this handles entity IDs and objects. if (isset($values) && !is_array($values)) { - // Directly update the property instead of invoking the parent, so that - // the entity property can take care of updating the ID property. + // Directly update the property instead of invoking the parent, so it can + // handle objects and IDs. $this->properties['entity']->setValue($values, $notify); + // If notify was FALSE, ensure the target_id property gets synched. + if (!$notify) { + $this->set('target_id', $this->properties['entity']->getTargetIdentifier(), FALSE); + } } else { // Make sure that the 'entity' property gets set as 'target_id'. @@ -111,4 +118,18 @@ public function setValue($values, $notify = TRUE) { parent::setValue($values, $notify); } } + + /** + * {@inheritdoc} + */ + public function onChange($property_name) { + // Make sure that the target ID and the target property stay in sync. + if ($property_name == 'target_id') { + $this->properties['entity']->setValue($this->target_id, FALSE); + } + elseif ($property_name == 'entity') { + $this->set('target_id', $this->properties['entity']->getTargetIdentifier(), FALSE); + } + parent::onChange($property_name); + } } diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityWrapper.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityWrapper.php deleted file mode 100644 index e2561a9..0000000 --- a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityWrapper.php +++ /dev/null @@ -1,227 +0,0 @@ -entityType = isset($this->definition['constraints']['EntityType']) ? $this->definition['constraints']['EntityType'] : NULL; - } - - /** - * Overrides \Drupal\Core\TypedData\TypedData::getValue(). - */ - public function getValue() { - if (isset($this->newEntity)) { - return $this->newEntity; - } - 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; - } - - /** - * Overrides \Drupal\Core\TypedData\TypedData::setValue(). - * - * Both the entity ID and the entity object may be passed as value. - */ - public function setValue($value, $notify = TRUE) { - // Support passing in the entity object. If it's not yet saved we have - // to store the whole entity such that it could be saved later on. - if ($value instanceof EntityInterface && $value->isNew()) { - $this->newEntity = $value; - $this->entityType = $value->entityType(); - $value = 0; - } - elseif ($value instanceof EntityInterface) { - $this->entityType = $value->entityType(); - $value = $value->id(); - unset($this->newEntity); - } - elseif (isset($value) && !(is_scalar($value) && !empty($this->definition['constraints']['EntityType']))) { - throw new InvalidArgumentException('Value is not a valid entity.'); - } - // Update the 'id source' property, if given. - if (!empty($this->definition['settings']['id source'])) { - $this->parent->__set($this->definition['settings']['id source'], $value, $notify); - } - else { - // Notify the parent of any changes to be made. - if ($notify && isset($this->parent)) { - $this->parent->onChange($this->name); - } - $this->id = $value; - } - } - - /** - * Overrides \Drupal\Core\TypedData\TypedData::getString(). - */ - public function getString() { - if ($entity = $this->getValue()) { - return $entity->label(); - } - return ''; - } - - /** - * Implements \IteratorAggregate::getIterator(). - */ - public function getIterator() { - if ($entity = $this->getValue()) { - return $entity->getIterator(); - } - return new ArrayIterator(array()); - } - - /** - * Implements \Drupal\Core\TypedData\ComplexDataInterface::get(). - */ - public function get($property_name) { - // @todo: Allow navigating through the tree without data as well. - if ($entity = $this->getValue()) { - return $entity->get($property_name); - } - } - - /** - * Implements \Drupal\Core\TypedData\ComplexDataInterface::set(). - */ - public function set($property_name, $value, $notify = TRUE) { - $this->get($property_name)->setValue($value, FALSE); - } - - /** - * Implements \Drupal\Core\TypedData\ComplexDataInterface::getProperties(). - */ - public function getProperties($include_computed = FALSE) { - if ($entity = $this->getValue()) { - return $entity->getProperties($include_computed); - } - return array(); - } - - /** - * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinition(). - */ - public function getPropertyDefinition($name) { - $definitions = $this->getPropertyDefinitions(); - if (isset($definitions[$name])) { - return $definitions[$name]; - } - else { - return FALSE; - } - } - - /** - * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions(). - */ - public function getPropertyDefinitions() { - // @todo: Support getting definitions if multiple bundles are specified. - return \Drupal::entityManager()->getFieldDefinitionsByConstraints($this->entityType, $this->definition['constraints']); - } - - /** - * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyValues(). - */ - public function getPropertyValues() { - if ($entity = $this->getValue()) { - return $entity->getPropertyValues(); - } - return array(); - } - - /** - * Implements \Drupal\Core\TypedData\ComplexDataInterface::setPropertyValues(). - */ - public function setPropertyValues($values) { - if ($entity = $this->getValue()) { - $entity->setPropertyValues($values); - } - } - - /** - * Implements \Drupal\Core\TypedData\ComplexDataInterface::isEmpty(). - */ - public function isEmpty() { - return !$this->getValue(); - } - - /** - * 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/Plugin/DataType/FieldDataTypeDerivative.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/FieldDataTypeDerivative.php deleted file mode 100644 index 346b656..0000000 --- a/core/lib/Drupal/Core/Entity/Plugin/DataType/FieldDataTypeDerivative.php +++ /dev/null @@ -1,46 +0,0 @@ -derivatives)) { - $this->getDerivativeDefinitions($base_plugin_definition); - } - if (isset($this->derivatives[$derivative_id])) { - return $this->derivatives[$derivative_id]; - } - } - - /** - * {@inheritdoc} - */ - public function getDerivativeDefinitions(array $base_plugin_definition) { - foreach (\Drupal::service('plugin.manager.entity.field.field_type')->getDefinitions() as $plugin_id => $definition) { - $this->derivatives[$plugin_id] = $definition; - } - return $this->derivatives; - } - -} diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/FieldItem.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/FieldItem.php index 73309d9..71fa264 100644 --- a/core/lib/Drupal/Core/Entity/Plugin/DataType/FieldItem.php +++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/FieldItem.php @@ -9,18 +9,20 @@ use Drupal\Core\TypedData\Annotation\DataType; use Drupal\Core\Annotation\Translation; -use Drupal\Component\Plugin\PluginBase; /** - * Defines the base plugin definition for field type typed data types. + * Defines the base plugin for deriving data types for field types. + * + * Note that the class only register the plugin, and is actually never used. + * \Drupal\Core\Entity\Field\FieldItemBase is available for use as base class. * * @DataType( * id = "field_item", * label = @Translation("Field item"), * list_class = "\Drupal\Core\Entity\Field\Field", - * derivative = "Drupal\Core\Entity\Plugin\DataType\FieldDataTypeDerivative" + * derivative = "Drupal\Core\Entity\Plugin\DataType\Deriver\FieldItemDeriver" * ) */ -class FieldItem extends PluginBase { +abstract class FieldItem { } diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageItem.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageItem.php index 5338556..68526f5 100644 --- a/core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageItem.php +++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageItem.php @@ -42,19 +42,18 @@ class LanguageItem extends FieldItemBase { * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions(). */ public function getPropertyDefinitions() { - if (!isset(static::$propertyDefinitions)) { static::$propertyDefinitions['value'] = array( 'type' => 'string', 'label' => t('Language code'), ); static::$propertyDefinitions['language'] = array( - 'type' => 'language', + 'type' => 'language_reference', 'label' => t('Language object'), + 'description' => t('The referenced language'), // The language object is retrieved via the language code. 'computed' => TRUE, 'read-only' => FALSE, - 'settings' => array('langcode source' => 'value'), ); } return static::$propertyDefinitions; @@ -71,6 +70,10 @@ public function setValue($values, $notify = TRUE) { // the language property can take care of updating the language code // property. $this->properties['language']->setValue($values, $notify); + // If notify was FALSE, ensure the value property gets synched. + if (!$notify) { + $this->set('value', $this->properties['language']->getTargetIdentifier(), FALSE); + } } else { // Make sure that the 'language' property gets set as 'value'. @@ -89,4 +92,18 @@ public function applyDefaultValue($notify = TRUE) { $this->setValue(array('value' => Language::LANGCODE_NOT_SPECIFIED), $notify); return $this; } + + /** + * {@inheritdoc} + */ + public function onChange($property_name) { + // Make sure that the value and the language property stay in sync. + if ($property_name == 'value') { + $this->properties['language']->setValue($this->value, FALSE); + } + elseif ($property_name == 'language') { + $this->set('value', $this->properties['language']->getTargetIdentifier(), FALSE); + } + parent::onChange($property_name); + } } diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageReference.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageReference.php new file mode 100644 index 0000000..8d143a7 --- /dev/null +++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageReference.php @@ -0,0 +1,39 @@ + 'language', + ); + } +} diff --git a/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php b/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php index f346129..2f7156a 100644 --- a/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php +++ b/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php @@ -8,6 +8,7 @@ namespace Drupal\Core\Entity\Query\Sql; use Drupal\Core\Database\Query\SelectInterface; +use Drupal\Core\Entity\Plugin\DataType\EntityReference; use Drupal\Core\Entity\Query\QueryException; use Drupal\field\Plugin\Core\Entity\Field; @@ -140,13 +141,12 @@ function addField($field, $type, $langcode) { $propertyDefinitions = $entity->{$field['field_name']}->getPropertyDefinitions(); // If the column is not yet known, ie. the - // $node->field_image->entity case then use the id source as the - // column. - if (!$column && isset($propertyDefinitions[$relationship_specifier]['settings']['id source'])) { - // If this is a valid relationship, use the id source. - // Otherwise, the code executing the relationship will throw an - // exception anyways so no need to do it here. - $column = $propertyDefinitions[$relationship_specifier]['settings']['id source']; + // $node->field_image->entity case then use first property as + // column, i.e. target_id or fid. + // Otherwise, the code executing the relationship will throw an + // exception anyways so no need to do it here. + if (!$column && isset($propertyDefinitions[$relationship_specifier]) && $entity->{$field['field_name']}->get('entity') instanceof EntityReference) { + $column = current(array_keys($propertyDefinitions)); } // Prepare the next index prefix. $next_index_prefix = "$relationship_specifier.$column"; @@ -193,7 +193,7 @@ function addField($field, $type, $langcode) { $next_index_prefix = $relationship_specifier; } // Check for a valid relationship. - if (isset($propertyDefinitions[$relationship_specifier]['constraints']['EntityType']) && isset($propertyDefinitions[$relationship_specifier]['settings']['id source'])) { + if (isset($propertyDefinitions[$relationship_specifier]) && $entity->{$specifier}->get('entity') instanceof EntityReference) { // If it is, use the entity type. $entity_type = $propertyDefinitions[$relationship_specifier]['constraints']['EntityType']; $entity_info = entity_get_info($entity_type); diff --git a/core/lib/Drupal/Core/Plugin/Context/Context.php b/core/lib/Drupal/Core/Plugin/Context/Context.php index fbdf658..8d67080 100644 --- a/core/lib/Drupal/Core/Plugin/Context/Context.php +++ b/core/lib/Drupal/Core/Plugin/Context/Context.php @@ -11,7 +11,7 @@ use Drupal\Core\Entity\Plugin\DataType\EntityWrapper; use Drupal\Core\TypedData\ComplexDataInterface; use Drupal\Core\TypedData\ListInterface; -use Drupal\Core\TypedData\TypedDataInterface; +use Drupal\Core\TypedData\PrimitiveInterface; use Drupal\Core\Validation\DrupalTranslator; use Symfony\Component\Validator\Validation; @@ -37,7 +37,7 @@ public function getContextValue() { $is_complex = $typed_value[0] instanceof ComplexDataInterface; } // @todo We won't need the getType == entity check once #1868004 lands. - if ($typed_value instanceof TypedDataInterface && (!$is_complex || $typed_value instanceof EntityWrapper)) { + if ($typed_value instanceof PrimitiveInterface && (!$is_complex || $typed_value instanceof EntityWrapper)) { return $typed_value->getValue(); } return $typed_value; @@ -48,7 +48,7 @@ public function getContextValue() { */ public function setContextValue($value) { // Make sure the value set is a typed data object. - if (!empty($this->contextDefinition['type']) && !$value instanceof TypedDataInterface) { + if (!empty($this->contextDefinition['type']) && !\Drupal::typedData()->isTypedData($value)) { $value = \Drupal::typedData()->create($this->contextDefinition, $value); } parent::setContextValue($value); diff --git a/core/lib/Drupal/Core/TypedData/AnyInterface.php b/core/lib/Drupal/Core/TypedData/AnyInterface.php new file mode 100644 index 0000000..ea94811 --- /dev/null +++ b/core/lib/Drupal/Core/TypedData/AnyInterface.php @@ -0,0 +1,31 @@ +target; + } + + /** + * {@inheritdoc} + */ + public function getValue() { + if ($target = $this->getTarget()) { + return $target->getValue(); + } + } + + /** + * {@inheritdoc} + */ + public function setValue($value, $notify = TRUE) { + $this->target = \Drupal::typedData()->create($this->getTargetDefinition(), $value); + // Notify the parent of any changes. + if ($notify && isset($this->parent)) { + $this->parent->onChange($this->name); + } + } + + /** + * {@inheritdoc} + */ + public function getString() { + return (string) $this->getType() . ':' . $this->getTargetIdentifier(); + } + + /** + * {@inheritdoc} + */ + public function getTargetIdentifier() { + $target = $this->getTarget(); + return isset($target) ? $target->id() : NULL; + } +} diff --git a/core/lib/Drupal/Core/TypedData/DataReferenceInterface.php b/core/lib/Drupal/Core/TypedData/DataReferenceInterface.php new file mode 100644 index 0000000..93c1d14 --- /dev/null +++ b/core/lib/Drupal/Core/TypedData/DataReferenceInterface.php @@ -0,0 +1,38 @@ +parent)) { - $this->parent->onChange($this->name); - } if (!isset($values) || $values === array()) { $this->list = $values; } @@ -72,6 +68,10 @@ public function setValue($values, $notify = TRUE) { } } } + // Notify the parent of any changes. + if ($notify && isset($this->parent)) { + $this->parent->onChange($this->name); + } } /** @@ -153,7 +153,7 @@ public function offsetSet($offset, $value) { } if (is_numeric($offset)) { // Support setting values via typed data objects. - if ($value instanceof TypedDataInterface) { + if ($value instanceof PrimitiveInterface) { $value = $value->getValue(); } $this->offsetGet($offset)->setValue($value); diff --git a/core/lib/Drupal/Core/TypedData/ListInterface.php b/core/lib/Drupal/Core/TypedData/ListInterface.php index 2711cd4..451e1af 100644 --- a/core/lib/Drupal/Core/TypedData/ListInterface.php +++ b/core/lib/Drupal/Core/TypedData/ListInterface.php @@ -41,7 +41,7 @@ public function getItemDefinition(); /** * React to changes to a child item. * - * Note that this is invoked before any changes are applied. + * Note that this is invoked after any changes have been applied. * * @param $delta * The delta of the item which is changed. diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Any.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Any.php index 9236b22..e16715f 100644 --- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Any.php +++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Any.php @@ -10,6 +10,7 @@ use Drupal\Core\TypedData\Annotation\DataType; use Drupal\Core\Annotation\Translation; use Drupal\Core\TypedData\TypedData; +use Drupal\Core\TypedData\AnyInterface; /** * The "any" data type. @@ -23,7 +24,7 @@ * label = @Translation("Any data") * ) */ -class Any extends TypedData { +class Any extends TypedData implements AnyInterface { /** * The data value. @@ -31,4 +32,22 @@ class Any extends TypedData { * @var mixed */ protected $value; + + /** + * {@inheritdoc} + */ + public function getValue() { + return $this->value; + } + + /** + * {@inheritdoc} + */ + public function setValue($value, $notify = TRUE) { + $this->value = $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/Binary.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Binary.php index 908f040..16ac5d6 100644 --- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Binary.php +++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Binary.php @@ -59,10 +59,6 @@ public function getValue() { * Supports a PHP file resource or a (absolute) stream resource URI as value. */ public function setValue($value, $notify = TRUE) { - // Notify the parent of any changes to be made. - if ($notify && isset($this->parent)) { - $this->parent->onChange($this->name); - } if (!isset($value)) { $this->handle = NULL; $this->uri = NULL; @@ -76,6 +72,10 @@ public function setValue($value, $notify = TRUE) { else { $this->handle = $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/DateTimeIso8601.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/DateTimeIso8601.php index 59bbe8a..906b4eb 100644 --- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/DateTimeIso8601.php +++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/DateTimeIso8601.php @@ -36,8 +36,12 @@ public function getDateTime() { /** * {@inheritdoc} */ - public function setDateTime(DrupalDateTime $dateTime) { + public function setDateTime(DrupalDateTime $dateTime, $notify = TRUE) { $this->value = $dateTime->format('c'); + // 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/DurationIso8601.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/DurationIso8601.php index d83261f..9e67026 100644 --- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/DurationIso8601.php +++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/DurationIso8601.php @@ -37,10 +37,14 @@ public function getDuration() { /** * {@inheritdoc} */ - public function setDuration(\DateInterval $duration) { + public function setDuration(\DateInterval $duration, $notify = TRUE) { // Generate an ISO 8601 formatted string as supported by // DateInterval::__construct() and setValue(). $this->value = $duration->format('%rP%yY%mM%dDT%hH%mM%sS'); + // 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/Language.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Language.php index fdb7e59..7aab65a 100644 --- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Language.php +++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Language.php @@ -11,6 +11,8 @@ use Drupal\Core\Annotation\Translation; use InvalidArgumentException; use Drupal\Core\Language\Language as LanguageObject; +use Drupal\Core\TypedData\IdentifiableInterface; +use Drupal\Core\TypedData\PrimitiveInterface; use Drupal\Core\TypedData\TypedData; /** @@ -20,39 +22,36 @@ * \Drupal\Core\Language\Language. For setting the value the language object or * the language code as string may be passed. * - * Optionally, this class may be used as computed property, see the supported - * settings below. E.g., it is used as 'language' property of language items. - * - * Supported settings (below the definition's 'settings' key) are: - * - langcode source: If used as computed property, the langcode property used - * to load the language object. - * * @DataType( * id = "language", * label = @Translation("Language"), * description = @Translation("A language object.") * ) */ -class Language extends TypedData { +class Language extends TypedData implements PrimitiveInterface, IdentifiableInterface { /** - * The language code of the language if no 'langcode source' is used. + * The id of the language. * * @var string */ - protected $langcode; + protected $id; + + /** + * @var \Drupal\Core\Language + */ + protected $language; /** * Overrides TypedData::getValue(). + * + * @return \Drupal\Core\Language\Language|null */ public function getValue() { - if (!empty($this->definition['settings']['langcode source'])) { - $this->id = $this->parent->__get($this->definition['settings']['langcode source']); - } - if ($this->id) { - $language = language_load($this->id); - return $language ?: new LanguageObject(array('id' => $this->id)); + if (!isset($this->language) && $this->id) { + $this->language = language_load($this->id); } + return $this->language; } /** @@ -63,21 +62,19 @@ public function getValue() { public function setValue($value, $notify = TRUE) { // Support passing language objects. if (is_object($value)) { - $value = $value->id; + $this->id = $value->id; + $this->language = $value; } elseif (isset($value) && !is_scalar($value)) { throw new InvalidArgumentException('Value is no valid langcode or language object.'); } - // Update the 'langcode source' property, if given. - if (!empty($this->definition['settings']['langcode source'])) { - $this->parent->__set($this->definition['settings']['langcode source'], $value, $notify); - } else { - // Notify the parent of any changes to be made. - if ($notify && isset($this->parent)) { - $this->parent->onChange($this->name); - } $this->id = $value; + $this->language = NULL; + } + // Notify the parent of any changes. + if ($notify && isset($this->parent)) { + $this->parent->onChange($this->name); } } @@ -88,4 +85,17 @@ public function getString() { $language = $this->getValue(); return $language ? $language->name : ''; } + + /** + * {@inheritdoc} + */ + public function id() { + if (isset($this->id)) { + return $this->id; + } + elseif (isset($this->language)) { + return $this->language->id; + } + } + } diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php index a033322..6a7ea4f 100644 --- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php +++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php @@ -26,6 +26,10 @@ * id = "map", * label = @Translation("Map") * ) + * + * @todo Map should not implement get/setValue() to instead stick tighter to the + * contract of ComplexDataInterface. Or, it should implement its own interface + * where get/setValue() is defined. */ class Map extends TypedData implements \IteratorAggregate, ComplexDataInterface { @@ -84,10 +88,6 @@ public function setValue($values, $notify = TRUE) { if (isset($values) && !is_array($values)) { throw new \InvalidArgumentException("Invalid values given. Values must be represented as an associative array."); } - // 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. @@ -98,18 +98,10 @@ public function setValue($values, $notify = TRUE) { } $property->setValue($value, FALSE); } - } - - /** - * Overrides \Drupal\Core\TypedData\TypedData::getString(). - */ - public function getString() { - $strings = array(); - foreach ($this->getProperties() as $property) { - $strings[] = $property->getString(); + // Notify the parent of any changes. + if ($notify && isset($this->parent)) { + $this->parent->onChange($this->name); } - // Remove any empty strings resulting from empty items. - return implode(', ', array_filter($strings, 'drupal_strlen')); } /** @@ -131,16 +123,16 @@ public function get($property_name) { * Implements \Drupal\Core\TypedData\ComplexDataInterface::set(). */ public function set($property_name, $value, $notify = TRUE) { - // Notify the parent of any changes to be made. - if ($notify && isset($this->parent)) { - $this->parent->onChange($this->name); - } if ($this->getPropertyDefinition($property_name)) { - $this->get($property_name)->setValue($value); + $this->get($property_name)->setValue($value, $notify); } else { // Just set the plain value, which allows adding a new entry to the map. $this->values[$property_name] = $value; + // Directly notify ourselves. + if ($notify) { + $this->onChange($property_name, $value); + } } } diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/TimeSpan.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/TimeSpan.php index b0ec72a..c91fcd2 100644 --- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/TimeSpan.php +++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/TimeSpan.php @@ -43,7 +43,7 @@ public function getDuration() { /** * {@inheritdoc} */ - public function setDuration(\DateInterval $duration) { + public function setDuration(\DateInterval $duration, $notify = TRUE) { // Note that this applies the assumption of 12 month's a 30 days and // each year having 365 days. There is no accurate conversion for time spans // exceeding a day. @@ -53,6 +53,11 @@ public function setDuration(\DateInterval $duration) { ($duration->h * 60 * 60) + ($duration->i * 60) + $duration->s; + + // 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/Timestamp.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Timestamp.php index 18c99dc..c0cad02 100644 --- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Timestamp.php +++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Timestamp.php @@ -41,7 +41,11 @@ public function getDateTime() { /** * {@inheritdoc} */ - public function setDateTime(DrupalDateTime $dateTime) { + public function setDateTime(DrupalDateTime $dateTime, $notify = TRUE) { $this->value = $dateTime->getTimestamp(); + // Notify the parent of any changes. + if ($notify && isset($this->parent)) { + $this->parent->onChange($this->name); + } } } diff --git a/core/lib/Drupal/Core/TypedData/PrimitiveBase.php b/core/lib/Drupal/Core/TypedData/PrimitiveBase.php index 1ba9319..7b0201e 100644 --- a/core/lib/Drupal/Core/TypedData/PrimitiveBase.php +++ b/core/lib/Drupal/Core/TypedData/PrimitiveBase.php @@ -30,10 +30,17 @@ public function getValue() { * {@inheritdoc} */ public function setValue($value, $notify = TRUE) { - // Notify the parent of any changes to be made. + $this->value = $value; + // Notify the parent of any changes. if ($notify && isset($this->parent)) { $this->parent->onChange($this->name); } - $this->value = $value; + } + + /** + * {@inheritdoc} + */ + public function getString() { + return (string) $this->getValue(); } } diff --git a/core/lib/Drupal/Core/TypedData/PrimitiveInterface.php b/core/lib/Drupal/Core/TypedData/PrimitiveInterface.php index b2293e2..35f16bd 100644 --- a/core/lib/Drupal/Core/TypedData/PrimitiveInterface.php +++ b/core/lib/Drupal/Core/TypedData/PrimitiveInterface.php @@ -10,7 +10,7 @@ /** * Interface for primitive data. */ -interface PrimitiveInterface { +interface PrimitiveInterface extends StringableInterface { /** * Gets the primitive data value. diff --git a/core/lib/Drupal/Core/TypedData/StringableInterface.php b/core/lib/Drupal/Core/TypedData/StringableInterface.php new file mode 100644 index 0000000..06b9064 --- /dev/null +++ b/core/lib/Drupal/Core/TypedData/StringableInterface.php @@ -0,0 +1,22 @@ +definition = $definition; $this->parent = $parent; $this->name = $name; } /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::getType(). - */ - public function getType() { - return $this->definition['type']; - } - - /** * {@inheritdoc} */ public function getPluginId() { @@ -87,32 +80,7 @@ public function getDefinition() { } /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::getValue(). - */ - public function getValue() { - return $this->value; - } - - /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::setValue(). - */ - public function setValue($value, $notify = TRUE) { - // Notify the parent of any changes to be made. - if ($notify && isset($this->parent)) { - $this->parent->onChange($this->name); - } - $this->value = $value; - } - - /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::getString(). - */ - public function getString() { - return (string) $this->getValue(); - } - - /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::getConstraints(). + * {@inheritdoc} */ public function getConstraints() { // @todo: Add the typed data manager as proper dependency. @@ -120,7 +88,7 @@ public function getConstraints() { } /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::validate(). + * {@inheritdoc} */ public function validate() { // @todo: Add the typed data manager as proper dependency. @@ -137,22 +105,22 @@ public function applyDefaultValue($notify = TRUE) { } /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::setContext(). + * {@inheritdoc} */ - public function setContext($name = NULL, TypedDataInterface $parent = NULL) { + public function setContext($name = NULL, $parent = NULL) { $this->parent = $parent; $this->name = $name; } /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::getName(). + * {@inheritdoc} */ public function getName() { return $this->name; } /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::getRoot(). + * {@inheritdoc} */ public function getRoot() { if (isset($this->parent)) { @@ -163,7 +131,7 @@ public function getRoot() { } /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::getPropertyPath(). + * {@inheritdoc} */ public function getPropertyPath() { if (isset($this->parent)) { @@ -181,9 +149,7 @@ public function getPropertyPath() { } /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::getParent(). - * - * @return \Drupal\Core\Entity\Field\FieldInterface + * {@inheritdoc} */ public function getParent() { return $this->parent; diff --git a/core/lib/Drupal/Core/TypedData/TypedDataInterface.php b/core/lib/Drupal/Core/TypedData/TypedDataInterface.php index 96229b6..66ac1a5 100644 --- a/core/lib/Drupal/Core/TypedData/TypedDataInterface.php +++ b/core/lib/Drupal/Core/TypedData/TypedDataInterface.php @@ -7,143 +7,16 @@ namespace Drupal\Core\TypedData; -use Drupal\user; - /** * Interface for typed data objects. */ interface TypedDataInterface { /** - * Gets the data type. - * - * @return string - * The data type of the wrapped data. - */ - public function getType(); - - /** * Gets the data definition. * * @return array * The data definition array. */ public function getDefinition(); - - /** - * Gets the data value. - * - * @return mixed - */ - public function getValue(); - - /** - * Sets the data value. - * - * @param mixed|null $value - * The value to set in the format as documented for the data type or NULL to - * unset the data value. - * @param bool $notify - * (optional) Whether to notify the parent object of the change. Defaults to - * TRUE. If a property is updated from a parent object, set it to FALSE to - * avoid being notified again. - * - * @throws \Drupal\Core\TypedData\ReadOnlyException - * If the data is read-only. - */ - public function setValue($value, $notify = TRUE); - - /** - * Returns a string representation of the data. - * - * @return string - */ - public function getString(); - - /** - * Gets a list of validation constraints. - * - * @return array - * Array of constraints, each being an instance of - * \Symfony\Component\Validator\Constraint. - */ - public function getConstraints(); - - /** - * Validates the currently set data value. - * - * @return \Symfony\Component\Validator\ConstraintViolationListInterface - * A list of constraint violations. If the list is empty, validation - * succeeded. - */ - public function validate(); - - /** - * Applies the default value. - * - * @param bool $notify - * (optional) Whether to notify the parent object of the change. Defaults to - * TRUE. If a property is updated from a parent object, set it to FALSE to - * avoid being notified again. - * - * @return \Drupal\Core\TypedData\TypedDataInterface - * Returns itself to allow for chaining. - */ - public function applyDefaultValue($notify = TRUE); - - /** - * Returns the name of a property or item. - * - * @return string - * If the data is a property of some complex data, the name of the property. - * If the data is an item of a list, the name is the numeric position of the - * item in the list, starting with 0. Otherwise, NULL is returned. - */ - public function getName(); - - /** - * Returns the parent data structure; i.e. either complex data or a list. - * - * @return \Drupal\Core\TypedData\ComplexDataInterface|\Drupal\Core\TypedData\ListInterface - * The parent data structure, either complex data or a list; or NULL if this - * is the root of the typed data tree. - */ - public function getParent(); - - /** - * Returns the root of the typed data tree. - * - * Returns the root data for a tree of typed data objects; e.g. for an entity - * field item the root of the tree is its parent entity object. - * - * @return \Drupal\Core\TypedData\ComplexDataInterface|\Drupal\Core\TypedData\ListInterface - * The root data structure, either complex data or a list. - */ - public function getRoot(); - - /** - * Returns the property path of the data. - * - * The trail of property names relative to the root of the typed data tree, - * separated by dots; e.g. 'field_text.0.format'. - * - * @return string - * The property path relative to the root of the typed tree, or an empty - * string if this is the root. - */ - public function getPropertyPath(); - - /** - * Sets the context of a property or item via a context aware parent. - * - * This method is supposed to be called by the factory only. - * - * @param string $name - * (optional) The name of the property or the delta of the list item, - * or NULL if it is the root of a typed data tree. Defaults to NULL. - * @param \Drupal\Core\TypedData\TypedDataInterface $parent - * (optional) The parent object of the data property, or NULL if it is the - * root of a typed data tree. Defaults to NULL. - */ - public function setContext($name = NULL, TypedDataInterface $parent = NULL); } diff --git a/core/lib/Drupal/Core/TypedData/TypedDataManager.php b/core/lib/Drupal/Core/TypedData/TypedDataManager.php index f0e8034..8090e38 100644 --- a/core/lib/Drupal/Core/TypedData/TypedDataManager.php +++ b/core/lib/Drupal/Core/TypedData/TypedDataManager.php @@ -14,6 +14,8 @@ use Drupal\Core\Plugin\DefaultPluginManager; use InvalidArgumentException; use Drupal\Core\TypedData\Validation\MetadataFactory; +use Drupal\Core\TypedData\ContextAwareInterface; +use Drupal\Core\TypedData\AnyInterface; use Drupal\Core\Validation\ConstraintManager; use Drupal\Core\Validation\DrupalTranslator; use Symfony\Component\Validator\ValidatorInterface; @@ -198,7 +200,7 @@ public function getInstance(array $options) { * 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 + * @param \Drupal\Core\TypedData\ContextAwareInterface $object * The parent typed data object, implementing the TypedDataInterface and * either the ListInterface or the ComplexDataInterface. * @param string $property_name @@ -219,18 +221,16 @@ public function getInstance(array $options) { * @todo: Add type-hinting to $object once entities implement the * TypedDataInterface. */ - public function getPropertyInstance($object, $property_name, $value = NULL) { - if ($root = $object->getRoot()) { - $key = $root->getType() . ':' . $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; - } - else { - // Missing context, thus we cannot determine a unique key for prototyping. - // Fall back to create a new prototype on each call. - $key = FALSE; + public function getPropertyInstance(ContextAwareInterface $object, $property_name, $value = NULL) { + $definition = $object->getRoot()->getDefinition(); + $key = $definition['type']; + if (isset($definition['settings'])) { + $key .= ':' . implode(',', $definition['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. @@ -384,4 +384,29 @@ public function getConstraints($definition) { } return $constraints; } + + /** + * Decided whether or not an object is typed data or not. + * + * @param mixed $object + * + * @return boolean + * Returns TRUE if $object is an instance of any of the typed data + * interfaces, else FALSE. + */ + public function isTypedData($object) { + if ($object instanceof ComplexDataInterface) { + return TRUE; + } + elseif ($object instanceof ListInterface) { + return TRUE; + } + elseif ($object instanceof PrimitiveInterface) { + return TRUE; + } + elseif ($object instanceof AnyInterface) { + return TRUE; + } + return FALSE; + } } diff --git a/core/lib/Drupal/Core/TypedData/ValidatableInterface.php b/core/lib/Drupal/Core/TypedData/ValidatableInterface.php new file mode 100644 index 0000000..ac0af19 --- /dev/null +++ b/core/lib/Drupal/Core/TypedData/ValidatableInterface.php @@ -0,0 +1,33 @@ +typedData = $typed_data; $this->name = $name; $this->factory = $factory; diff --git a/core/lib/Drupal/Core/TypedData/Validation/MetadataFactory.php b/core/lib/Drupal/Core/TypedData/Validation/MetadataFactory.php index 2858daf..44af36f 100644 --- a/core/lib/Drupal/Core/TypedData/Validation/MetadataFactory.php +++ b/core/lib/Drupal/Core/TypedData/Validation/MetadataFactory.php @@ -9,7 +9,6 @@ use Drupal\Core\TypedData\ComplexDataInterface; use Drupal\Core\TypedData\ListInterface; -use Drupal\Core\TypedData\TypedDataInterface; use Symfony\Component\Validator\MetadataFactoryInterface; /** @@ -27,7 +26,7 @@ class MetadataFactory implements MetadataFactoryInterface { * the data is the root of the typed data tree. */ public function getMetadataFor($typed_data, $name = '') { - if (!$typed_data instanceof TypedDataInterface) { + if (!\Drupal::typedData()->isTypedData($typed_data)) { throw new \InvalidArgumentException('The passed value must be a typed data object.'); } $is_container = $typed_data instanceof ComplexDataInterface || $typed_data instanceof ListInterface; @@ -39,6 +38,6 @@ public function getMetadataFor($typed_data, $name = '') { * Implements MetadataFactoryInterface::hasMetadataFor(). */ public function hasMetadataFor($value) { - return $value instanceof TypedDataInterface; + return \Drupal::typedData()->isTypedData($value); } } diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/BundleConstraint.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/BundleConstraint.php index f6ea289..ebd844b 100644 --- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/BundleConstraint.php +++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/BundleConstraint.php @@ -20,7 +20,7 @@ * @Plugin( * id = "Bundle", * label = @Translation("Bundle", context = "Validation"), - * type = "entity" + * type = { "entity", "entity_reference" } * ) */ class BundleConstraint extends Constraint { diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/BundleConstraintValidator.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/BundleConstraintValidator.php index a84251e..42f09ca 100644 --- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/BundleConstraintValidator.php +++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/BundleConstraintValidator.php @@ -18,10 +18,7 @@ class BundleConstraintValidator extends ConstraintValidator { /** * Implements \Symfony\Component\Validator\ConstraintValidatorInterface::validate(). */ - public function validate($typed_data, Constraint $constraint) { - // If the entity is contained in a reference, unwrap it first. - $entity = isset($typed_data) && !($typed_data instanceof EntityInterface) ? $typed_data->getValue() : FALSE; - + public function validate($entity, Constraint $constraint) { if (!empty($entity) && !in_array($entity->bundle(), $constraint->getBundleOption())) { $this->context->addViolation($constraint->message, array('%bundle', implode(', ', $constraint->getBundleOption()))); } diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EntityTypeConstraint.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EntityTypeConstraint.php index 1d38ae5..d480fa1 100644 --- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EntityTypeConstraint.php +++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EntityTypeConstraint.php @@ -20,7 +20,7 @@ * @Plugin( * id = "EntityType", * label = @Translation("Entity type", context = "Validation"), - * type = "entity" + * type = { "entity", "entity_reference" } * ) */ class EntityTypeConstraint extends Constraint { diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EntityTypeConstraintValidator.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EntityTypeConstraintValidator.php index 31c7cb2..304a85c 100644 --- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EntityTypeConstraintValidator.php +++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EntityTypeConstraintValidator.php @@ -19,9 +19,7 @@ class EntityTypeConstraintValidator extends ConstraintValidator { /** * Implements \Symfony\Component\Validator\ConstraintValidatorInterface::validate(). */ - public function validate($typed_data, Constraint $constraint) { - // If the entity is contained in a reference, unwrap it first. - $entity = isset($typed_data) && !($typed_data instanceof EntityInterface) ? $typed_data->getValue() : FALSE; + public function validate($entity, Constraint $constraint) { if (!empty($entity) && $entity->entityType() != $constraint->type) { $this->context->addViolation($constraint->message, array('%type' => $constraint->type)); diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module index 604cb93..8ba44d1 100644 --- a/core/modules/comment/comment.module +++ b/core/modules/comment/comment.module @@ -1482,7 +1482,7 @@ function comment_preprocess_block(&$variables) { function comment_prepare_author(Comment $comment) { // The account has been pre-loaded by CommentRenderController::buildContent(). $account = $comment->uid->entity; - if (!$account) { + if (empty($account->uid->value)) { $account = entity_create('user', array('uid' => 0, 'name' => $comment->name->value, 'homepage' => $comment->homepage->value)); } return $account->getBCEntity(); diff --git a/core/modules/comment/lib/Drupal/comment/FieldNewValue.php b/core/modules/comment/lib/Drupal/comment/FieldNewValue.php index 8f9c392..bd2fd9d 100644 --- a/core/modules/comment/lib/Drupal/comment/FieldNewValue.php +++ b/core/modules/comment/lib/Drupal/comment/FieldNewValue.php @@ -15,6 +15,7 @@ * A computed property for the integer value of the 'new' field. * * @todo: Declare the list of allowed values once supported. + * @todo Need to implement a proper interface. */ class FieldNewValue extends TypedData { diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php index d3bceb8..4616efe 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php @@ -162,13 +162,11 @@ function testSchemaData() { // Try some simple properties. $meta = config_typed()->get('system.site'); $property = $meta->get('name'); - $this->assertTrue(is_a($property, 'Drupal\Core\TypedData\Plugin\DataType\String'), 'Got the right wrapper fo the site name property.'); - $this->assertEqual($property->getType(), 'label', 'Got the right string type for site name data.'); + $this->assertTrue($property instanceof \Drupal\Core\TypedData\Plugin\DataType\String, 'Got the right wrapper fo the site name property.'); $this->assertEqual($property->getValue(), 'Drupal', 'Got the right string value for site name data.'); $property = $meta->get('page')->get('front'); - $this->assertTrue(is_a($property, 'Drupal\Core\TypedData\Plugin\DataType\String'), 'Got the right wrapper fo the page.front property.'); - $this->assertEqual($property->getType(), 'path', 'Got the right type for page.front data (undefined).'); + $this->assertTrue($property instanceof \Drupal\Core\TypedData\Plugin\DataType\String, 'Got the right wrapper fo the page.front property.'); $this->assertEqual($property->getValue(), 'user', 'Got the right value for page.front data.'); // Check nested array of properties. @@ -192,7 +190,7 @@ function testSchemaData() { $ieid = key($effects->getValue()); $effect = $effects[$ieid]; $this->assertTrue(count($effect['data']) && $effect['name']->getValue() == 'image_scale', 'Got data for the image scale effect from metadata.'); - $this->assertEqual($effect['data']['width']->getType(), 'integer', 'Got the right type for the scale effect width.'); + $this->assertTrue($effect['data']['width'] instanceof \Drupal\Core\TypedData\Plugin\DataType\Integer, 'Got the right type for the scale effect width.'); $this->assertEqual($effect['data']['width']->getValue(), 480, 'Got the right value for the scale effect width.' ); // Finally update some object using a configuration wrapper. diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Tests/Views/TranslationLinkTest.php b/core/modules/content_translation/lib/Drupal/content_translation/Tests/Views/TranslationLinkTest.php index 1f5e457..b26b0a5 100644 --- a/core/modules/content_translation/lib/Drupal/content_translation/Tests/Views/TranslationLinkTest.php +++ b/core/modules/content_translation/lib/Drupal/content_translation/Tests/Views/TranslationLinkTest.php @@ -46,6 +46,11 @@ function setUp() { parent::setUp(); + // Assign user 1 a language code so that the entity can be translated. + $user = user_load(1); + $user->langcode = 'en'; + $user->save(); + ViewTestData::importTestViews(get_class($this), array('content_translation_test_views')); } diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigEntityReferenceItemBase.php b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigEntityReferenceItemBase.php index 7229a9a..ff4472f 100644 --- a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigEntityReferenceItemBase.php +++ b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigEntityReferenceItemBase.php @@ -57,14 +57,15 @@ public function getInstance() { * {@inheritdoc} */ public function getPropertyDefinitions() { - // Definitions vary by entity type, so key them by entity type. - $target_type = $this->definition['settings']['target_type']; + // Definitions vary by entity type and bundle, so key them accordingly. + $key = $this->definition['settings']['target_type'] . ':'; + $key .= isset($this->definition['settings']['target_bundle']) ? $this->definition['settings']['target_bundle'] : ''; - if (!isset(self::$propertyDefinitions[$target_type])) { + if (!isset(static::$propertyDefinitions[$key])) { // Call the parent to define the target_id and entity properties. parent::getPropertyDefinitions(); - static::$propertyDefinitions[$target_type]['revision_id'] = array( + static::$propertyDefinitions[$key]['revision_id'] = array( // @todo: Lookup the entity type's ID data type and use it here. 'type' => 'integer', 'label' => t('Revision ID'), @@ -72,18 +73,18 @@ public function getPropertyDefinitions() { 'Range' => array('min' => 0), ), ); - static::$propertyDefinitions[$target_type]['label'] = array( + static::$propertyDefinitions[$key]['label'] = array( 'type' => 'string', 'label' => t('Label (auto-create)'), 'computed' => TRUE, ); - static::$propertyDefinitions[$target_type]['access'] = array( + static::$propertyDefinitions[$key]['access'] = array( 'type' => 'boolean', 'label' => t('Access'), 'computed' => TRUE, ); } - return static::$propertyDefinitions[$target_type]; + return static::$propertyDefinitions[$key]; } /** diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigField.php b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigField.php index dfc4fba..202071c 100644 --- a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigField.php +++ b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigField.php @@ -7,7 +7,6 @@ namespace Drupal\field\Plugin\Type\FieldType; -use Drupal\Core\TypedData\TypedDataInterface; use Drupal\Core\Entity\Field\Field; use Drupal\field\Field as FieldAPI; @@ -26,7 +25,7 @@ class ConfigField extends Field implements ConfigFieldInterface { /** * {@inheritdoc} */ - public function __construct(array $definition, $name = NULL, TypedDataInterface $parent = NULL) { + public function __construct(array $definition, $name = NULL, $parent = NULL) { parent::__construct($definition, $name, $parent); if (isset($definition['instance'])) { $this->instance = $definition['instance']; diff --git a/core/modules/file/lib/Drupal/file/Type/FileItem.php b/core/modules/file/lib/Drupal/file/Type/FileItem.php index 9b2cc4c..c8f1a9c 100644 --- a/core/modules/file/lib/Drupal/file/Type/FileItem.php +++ b/core/modules/file/lib/Drupal/file/Type/FileItem.php @@ -28,20 +28,23 @@ class FileItem extends ConfigEntityReferenceItemBase { */ public function getPropertyDefinitions() { $this->definition['settings']['target_type'] = 'file'; + // Definitions vary by entity type and bundle, so key them accordingly. + $key = $this->definition['settings']['target_type'] . ':'; + $key .= isset($this->definition['settings']['target_bundle']) ? $this->definition['settings']['target_bundle'] : ''; - if (!isset(static::$propertyDefinitions)) { - static::$propertyDefinitions = parent::getPropertyDefinitions(); + if (!isset(static::$propertyDefinitions[$key])) { + static::$propertyDefinitions[$key] = parent::getPropertyDefinitions(); - static::$propertyDefinitions['display'] = array( + static::$propertyDefinitions[$key]['display'] = array( 'type' => 'boolean', 'label' => t('Flag to control whether this file should be displayed when viewing content.'), ); - static::$propertyDefinitions['description'] = array( + static::$propertyDefinitions[$key]['description'] = array( 'type' => 'string', 'label' => t('A description of the file.'), ); } - return static::$propertyDefinitions; + return static::$propertyDefinitions[$key]; } } diff --git a/core/modules/image/lib/Drupal/image/Type/ImageItem.php b/core/modules/image/lib/Drupal/image/Type/ImageItem.php index 7d441fd..3b86fe4 100644 --- a/core/modules/image/lib/Drupal/image/Type/ImageItem.php +++ b/core/modules/image/lib/Drupal/image/Type/ImageItem.php @@ -28,28 +28,31 @@ class ImageItem extends ConfigEntityReferenceItemBase { */ public function getPropertyDefinitions() { $this->definition['settings']['target_type'] = 'file'; + // Definitions vary by entity type and bundle, so key them accordingly. + $key = $this->definition['settings']['target_type'] . ':'; + $key .= isset($this->definition['settings']['target_bundle']) ? $this->definition['settings']['target_bundle'] : ''; - if (!isset(static::$propertyDefinitions)) { - static::$propertyDefinitions = parent::getPropertyDefinitions(); + if (!isset(static::$propertyDefinitions[$key])) { + static::$propertyDefinitions[$key] = parent::getPropertyDefinitions(); - static::$propertyDefinitions['alt'] = array( + static::$propertyDefinitions[$key]['alt'] = array( 'type' => 'string', 'label' => t("Alternative image text, for the image's 'alt' attribute."), ); - static::$propertyDefinitions['title'] = array( + static::$propertyDefinitions[$key]['title'] = array( 'type' => 'string', 'label' => t("Image title text, for the image's 'title' attribute."), ); - static::$propertyDefinitions['width'] = array( + static::$propertyDefinitions[$key]['width'] = array( 'type' => 'integer', 'label' => t('The width of the image in pixels.'), ); - static::$propertyDefinitions['height'] = array( + static::$propertyDefinitions[$key]['height'] = array( 'type' => 'integer', 'label' => t('The height of the image in pixels.'), ); } - return static::$propertyDefinitions; + return static::$propertyDefinitions[$key]; } } diff --git a/core/modules/locale/lib/Drupal/locale/LocaleTypedConfig.php b/core/modules/locale/lib/Drupal/locale/LocaleTypedConfig.php index 5d6b200..9dca634 100644 --- a/core/modules/locale/lib/Drupal/locale/LocaleTypedConfig.php +++ b/core/modules/locale/lib/Drupal/locale/LocaleTypedConfig.php @@ -8,7 +8,6 @@ namespace Drupal\locale; use Drupal\Core\Language\Language; -use Drupal\Core\TypedData\ContextAwareInterface; use Drupal\Core\Config\Schema\Element; use Drupal\Core\Config\Schema\ArrayElement; @@ -168,7 +167,7 @@ protected function getArrayTranslation(ArrayElement $element, array $options) { * @return bool * Whether the element fits the translation criteria. */ - protected function translateElement(\Drupal\Core\TypedData\TypedDataInterface $element, array $options) { + protected function translateElement($element, array $options) { if ($this->canTranslate($options['source'], $options['target'])) { $definition = $element->getDefinition(); $value = $element->getValue(); diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php index c55927f..b53ba51 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php @@ -97,6 +97,7 @@ function testContentTypeLanguageConfiguration() { $this->drupalPost("admin/structure/types/manage/{$type2->type}", $edit, t('Save content type')); $this->assertRaw(t('The content type %type has been updated.', array('%type' => $type2->name))); $this->drupalLogout(); + drupal_static_reset('language_list'); // Verify language selection is not present on the node add form. $this->drupalLogin($web_user); @@ -153,6 +154,7 @@ function testContentTypeDirLang() { $edit = array(); $edit['predefined_langcode'] = 'ar'; $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language')); + drupal_static_reset('language_list'); // Install Spanish language. $edit = array(); diff --git a/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php b/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php index b914837..d0fbb8c 100644 --- a/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php +++ b/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php @@ -419,8 +419,10 @@ public function testBlockContextualLinks() { public function testMenuBundles() { $this->drupalLogin($this->big_user); $menu = $this->addCustomMenu(); + // Clear the entity info cache to ensure the static caches are rebuilt. + entity_info_cache_clear(); $bundles = entity_get_bundles('menu_link'); - $this->assertTrue($bundles[$menu->id()]); + $this->assertTrue(isset($bundles[$menu->id()])); $menus = menu_list_system_menus(); $menus[$menu->id()] = $menu->label(); ksort($menus); diff --git a/core/modules/node/node.module b/core/modules/node/node.module index b9c5bd3..447d830 100644 --- a/core/modules/node/node.module +++ b/core/modules/node/node.module @@ -2164,7 +2164,7 @@ function node_access($op, $node, $account = NULL, $langcode = NULL) { // If no language code was provided, default to the node's langcode. if (empty($langcode)) { - $langcode = $node->langcode; + $langcode = $node->language()->id; // If the Language module is enabled, try to use the language from content // negotiation. if (module_exists('language')) { diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php index e8878be..1d69638 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php @@ -11,7 +11,7 @@ use Drupal\Core\Entity\Field\FieldInterface; use Drupal\Core\Entity\Field\FieldItemInterface; use Drupal\Core\Language\Language; -use Drupal\Core\TypedData\TypedDataInterface; +use Drupal\Core\TypedData\PrimitiveInterface; /** * Tests Entity API base functionality. @@ -339,7 +339,7 @@ protected function assertSave($entity_type) { public function testIntrospection() { // All entity variations have to have the same results. foreach (entity_test_entity_types() as $entity_type) { - $this->assertIntrospection($entity_type); + $this->checkIntrospection($entity_type); } } @@ -349,17 +349,11 @@ public function testIntrospection() { * @param string $entity_type * The entity type to run the tests with. */ - protected function assertIntrospection($entity_type) { - // Test getting metadata upfront, i.e. without having an entity object. - $definition = array( - 'type' => 'entity', - 'constraints' => array( - 'EntityType' => $entity_type, - ), - 'label' => 'Test entity', - ); - $wrapped_entity = $this->container->get('typed_data')->create($definition); - $definitions = $wrapped_entity->getPropertyDefinitions($definition); + protected function checkIntrospection($entity_type) { + // Test getting metadata upfront. + // @todo: Make this work without having to create entity objects. + $entity = entity_create($entity_type, array()); + $definitions = $entity->getPropertyDefinitions(); $this->assertEqual($definitions['name']['type'], 'string_field', $entity_type .': Name field found.'); $this->assertEqual($definitions['user_id']['type'], 'entity_reference_field', $entity_type .': User field found.'); $this->assertEqual($definitions['field_test_text']['type'], 'field_item:text', $entity_type .': Test-text-field field found.'); @@ -378,7 +372,7 @@ protected function assertIntrospection($entity_type) { $userref_properties = $entity->user_id->getPropertyDefinitions(); $this->assertEqual($userref_properties['target_id']['type'], 'integer', $entity_type .': Entity id property of the user found.'); - $this->assertEqual($userref_properties['entity']['type'], 'entity', $entity_type .': Entity reference property of the user found.'); + $this->assertEqual($userref_properties['entity']['type'], 'entity_reference', $entity_type .': Entity reference property of the user found.'); $textfield_properties = $entity->field_test_text->getPropertyDefinitions(); $this->assertEqual($textfield_properties['value']['type'], 'string', $entity_type .': String value property of the test-text field found.'); @@ -439,7 +433,7 @@ protected function assertIterator($entity_type) { $this->assertTrue($field[0] instanceof FieldItemInterface, $entity_type . ": Item $delta of field $name implements interface."); foreach ($item as $value_name => $value_property) { - $this->assertTrue($value_property instanceof TypedDataInterface, $entity_type . ": Value $value_name of item $delta of field $name implements interface."); + $this->assertTrue($value_property instanceof PrimitiveInterface, $entity_type . ": Value $value_name of item $delta of field $name implements interface."); $value = $value_property->getValue(); $this->assertTrue(!isset($value) || is_scalar($value) || $value instanceof EntityInterface, $entity_type . ": Value $value_name of item $delta of field $name is a primitive or an entity."); @@ -470,21 +464,12 @@ public function testDataStructureInterfaces() { */ protected function assertDataStructureInterfaces($entity_type) { $entity = $this->createTestEntity($entity_type); - $entity->save(); - $entity_definition = array( - 'type' => 'entity', - 'constraints' => array( - 'EntityType' => $entity_type, - ), - 'label' => 'Test entity', - ); - $wrapped_entity = $this->container->get('typed_data')->create($entity_definition, $entity); // Test using the whole tree of typed data by navigating through the tree of // contained properties and getting all contained strings, limited by a // certain depth. $strings = array(); - $this->getContainedStrings($wrapped_entity, 0, $strings); + $this->getContainedStrings($entity, 0, $strings); // @todo: Once the user entity has defined properties this should contain // the user name and other user entity strings as well. @@ -505,9 +490,9 @@ protected function assertDataStructureInterfaces($entity_type) { * Recursive helper for getting all contained strings, * i.e. properties of type string. */ - public function getContainedStrings(TypedDataInterface $wrapper, $depth, array &$strings) { + public function getContainedStrings($wrapper, $depth, array &$strings) { - if ($wrapper->getType() == 'string') { + if ($wrapper instanceof \Drupal\Core\TypedData\Type\StringInterface) { $strings[] = $wrapper->getValue(); } @@ -527,22 +512,39 @@ public function getContainedStrings(TypedDataInterface $wrapper, $depth, array & } /** + * Makes sure data types are correctly derived for all entity types. + */ + public function testDataTypes() { + $types = \Drupal::typedData()->getDefinitions(); + foreach (entity_test_entity_types() as $entity_type) { + $this->assertTrue($types['entity:' . $entity_type]['class'], 'Entity data type registed.'); + } + // Check bundle types are provided as well. + entity_test_create_bundle('bundle'); + $types = \Drupal::typedData()->getDefinitions(); + $this->assertTrue($types['entity:entity_test:bundle']['class'], 'Entity bundle data type registed.'); + } + + /** * Tests validation constraints provided by the Entity API. */ public function testEntityConstraintValidation() { $entity = $this->createTestEntity('entity_test'); $entity->save(); - $entity_definition = array( - 'type' => 'entity', - 'constraints' => array( - 'EntityType' => 'entity_test', + // Create a reference field item and let it reference the entity. + $definition = array( + 'type' => 'entity_reference_field', + 'settings' => array( + 'target_type' => 'entity_test', ), 'label' => 'Test entity', ); - $wrapped_entity = $this->container->get('typed_data')->create($entity_definition, $entity); + $reference_field_item = \Drupal::TypedData()->create($definition); + $reference = $reference_field_item->get('entity'); + $reference->setValue($entity); // Test validation the typed data object. - $violations = $wrapped_entity->validate(); + $violations = $reference->validate(); $this->assertEqual($violations->count(), 0); // Test validating an entity of the wrong type. @@ -552,30 +554,31 @@ public function testEntityConstraintValidation() { 'type' => 'page', 'uid' => $user->id(), )); - // @todo: EntityWrapper can only handle entities with an id. - $node->save(); - $wrapped_entity->setValue($node); - $violations = $wrapped_entity->validate(); + $reference->setValue($node); + $violations = $reference->validate(); $this->assertEqual($violations->count(), 1); // Test bundle validation. - $entity_definition = array( - 'type' => 'entity', - 'constraints' => array( - 'EntityType' => 'node', - 'Bundle' => 'article', + $definition = array( + 'type' => 'entity_reference_field', + 'settings' => array( + 'target_type' => 'node', + 'target_bundle' => 'article', ), - 'label' => 'Test node', ); - $wrapped_entity = $this->container->get('typed_data')->create($entity_definition, $node); - - $violations = $wrapped_entity->validate(); + $reference_field_item = \Drupal::TypedData()->create($definition); + $reference = $reference_field_item->get('entity'); + $reference->setValue($node); + $violations = $reference->validate(); $this->assertEqual($violations->count(), 1); - $node->type = 'article'; + $node = entity_create('node', array( + 'type' => 'article', + 'uid' => $user->id(), + )); $node->save(); - $wrapped_entity->setValue($node); - $violations = $wrapped_entity->validate(); + $reference->setValue($node); + $violations = $reference->validate(); $this->assertEqual($violations->count(), 0); } diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityValidationTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityValidationTest.php index f1a0fdb..69bc6fd 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityValidationTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityValidationTest.php @@ -10,7 +10,6 @@ use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\Field\FieldInterface; use Drupal\Core\Entity\Field\FieldItemInterface; -use Drupal\Core\TypedData\TypedDataInterface; /** * Tests Entity API base functionality. diff --git a/core/modules/system/lib/Drupal/system/Tests/TypedData/TypedDataTest.php b/core/modules/system/lib/Drupal/system/Tests/TypedData/TypedDataTest.php index 3558d20..328bc67 100644 --- a/core/modules/system/lib/Drupal/system/Tests/TypedData/TypedDataTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/TypedData/TypedDataTest.php @@ -57,11 +57,11 @@ protected function createTypedData($definition, $value = NULL, $name = NULL) { // Construct the object. $data = $this->typedData->create($definition, $value, $name); // Assert the definition of the wrapper. - $this->assertTrue($data instanceof \Drupal\Core\TypedData\TypedDataInterface, 'Typed data object is an instance of the typed data interface.'); + $this->assertTrue(\Drupal::typedData()->isTypedData($data), 'Typed data object is an instance of a typed data interface.'); $definition = $data->getDefinition(); $this->assertTrue(!empty($definition['type']), format_string('!type data definition was returned.', array('!type' => $definition['type']))); // Assert that the correct type was constructed. - $this->assertEqual($data->getType(), $type, format_string('!type object returned type.', array('!type' => $definition['type']))); + $this->assertEqual($data->getPluginId(), $type, format_string('!type object returned type.', array('!type' => $definition['type']))); return $data; } @@ -292,7 +292,6 @@ public function testGetAndSet() { $new_value = 'test@example.com'; $typed_data->setValue($new_value); $this->assertIdentical($typed_data->getValue(), $new_value, 'Any value was changed.'); - $this->assertTrue(is_string($typed_data->getString()), 'Any value was converted to string'); $this->assertEqual($typed_data->validate()->count(), 0); $typed_data->setValue(NULL); $this->assertNull($typed_data->getValue(), 'Any wrapper is null-able.'); @@ -319,7 +318,7 @@ public function testTypedDataLists() { // Test iterating. $count = 0; foreach ($typed_data as $item) { - $this->assertTrue($item instanceof \Drupal\Core\TypedData\TypedDataInterface); + $this->assertTrue($item instanceof \Drupal\Core\TypedData\Plugin\DataType\String); $count++; } $this->assertEqual($count, 3); @@ -413,7 +412,7 @@ public function testTypedDataMaps() { // Test iterating. $count = 0; foreach ($typed_data as $item) { - $this->assertTrue($item instanceof \Drupal\Core\TypedData\TypedDataInterface); + $this->assertTrue($item instanceof \Drupal\Core\TypedData\AnyInterface); $count++; } $this->assertEqual($count, 3); @@ -449,10 +448,6 @@ public function testTypedDataMaps() { $typed_data->setValue(array('foo' => 'bar')); $this->assertEqual(array_keys($typed_data->getProperties()), array('foo')); - // Test getting the string representation. - $typed_data->setValue(array('one' => 'eins', 'two' => '', 'three' => 'drei')); - $this->assertEqual($typed_data->getString(), 'eins, drei'); - // Test isEmpty and cloning. $this->assertFalse($typed_data->isEmpty()); $clone = clone $typed_data; @@ -505,6 +500,9 @@ public function testTypedDataValidation() { 'Range' => array('min' => 5), ), ); + $integer = $this->typedData->create($definition, 7); + $this->assertTrue($integer instanceof \Drupal\Core\TypedData\ValidatableInterface); + $violations = $this->typedData->create($definition, 10)->validate(); $this->assertEqual($violations->count(), 0); @@ -614,4 +612,46 @@ public function testTypedDataValidation() { $this->assertEqual($violations[0]->getInvalidValue(), 'string'); $this->assertIdentical($violations[0]->getPropertyPath(), '0.value'); } + + /** + * Tests typed data contexts. + */ + function testTypedDataContext() { + // Test working with a simple map. + $value = array( + 'one' => 'ett', + 'two' => 'två', + 'three' => 'tre', + ); + $typed_data = $this->createTypedData(array( + 'type' => 'map', + ), $value); + + $this->assertTrue($typed_data instanceof \Drupal\Core\TypedData\ContextAwareInterface); + + $item = $typed_data->get('one'); + $this->assertEqual($item->getName(), 'one'); + $this->assertEqual($item->getPropertyPath(), 'one'); + $this->assertTrue($item->getParent() instanceof \Drupal\Core\TypedData\Plugin\DataType\Map); + $this->assertTrue($item->getRoot() instanceof \Drupal\Core\TypedData\Plugin\DataType\Map); + } + + /** + * Tests the typed data manager. + */ + function testTypedDataManager() { + // Test working with a simple map. + $value = array( + 'one' => 'första', + 'two' => 'andra', + 'three' => 'tredje', + ); + $typed_data = $this->createTypedData(array( + 'type' => 'map', + ), $value); + + $item = $this->typedData->getPropertyInstance($typed_data, 'two', 'prototyped value'); + $this->assertTrue($item instanceof \Drupal\Core\TypedData\AnyInterface); + $this->assertEqual($item->getValue(), 'prototyped value'); + } } diff --git a/core/modules/text/lib/Drupal/text/Plugin/field/field_type/TextItemBase.php b/core/modules/text/lib/Drupal/text/Plugin/field/field_type/TextItemBase.php index 80c93b3..9d8ef70 100644 --- a/core/modules/text/lib/Drupal/text/Plugin/field/field_type/TextItemBase.php +++ b/core/modules/text/lib/Drupal/text/Plugin/field/field_type/TextItemBase.php @@ -100,7 +100,7 @@ public function prepareCache() { $itemBC = $this->getValue(); $langcode = $this->getParent()->getParent()->language()->id; $this->set('safe_value', text_sanitize($this->getInstance()->settings['text_processing'], $langcode, $itemBC, 'value')); - if ($this->getType() == 'field_item:text_with_summary') { + if ($this instanceof TextWithSummaryItem) { $this->set('safe_summary', text_sanitize($this->getInstance()->settings['text_processing'], $langcode, $itemBC, 'summary')); } } diff --git a/core/modules/text/lib/Drupal/text/TextProcessed.php b/core/modules/text/lib/Drupal/text/TextProcessed.php index 9a1910f..446a005 100644 --- a/core/modules/text/lib/Drupal/text/TextProcessed.php +++ b/core/modules/text/lib/Drupal/text/TextProcessed.php @@ -7,7 +7,6 @@ namespace Drupal\text; -use Drupal\Core\TypedData\TypedDataInterface; use Drupal\Core\TypedData\TypedData; use Drupal\Core\TypedData\ReadOnlyException; use InvalidArgumentException; @@ -37,7 +36,7 @@ class TextProcessed extends TypedData { /** * Overrides TypedData::__construct(). */ - public function __construct(array $definition, $name = NULL, TypedDataInterface $parent = NULL) { + public function __construct(array $definition, $name = NULL, $parent = NULL) { parent::__construct($definition, $name, $parent); if (!isset($definition['settings']['text source'])) { @@ -48,7 +47,7 @@ public function __construct(array $definition, $name = NULL, TypedDataInterface /** * Overrides TypedData::setContext(). */ - public function setContext($name = NULL, TypedDataInterface $parent = NULL) { + public function setContext($name = NULL, $parent = NULL) { parent::setContext($name, $parent); if (isset($parent)) { $this->text = $parent->get($this->definition['settings']['text source']); diff --git a/core/modules/views_ui/lib/Drupal/views_ui/ViewUI.php b/core/modules/views_ui/lib/Drupal/views_ui/ViewUI.php index 92fa27b..636f909 100644 --- a/core/modules/views_ui/lib/Drupal/views_ui/ViewUI.php +++ b/core/modules/views_ui/lib/Drupal/views_ui/ViewUI.php @@ -11,7 +11,6 @@ use Drupal\Core\Entity\EntityStorageControllerInterface; use Drupal\views\ViewExecutable; use Drupal\Core\Database\Database; -use Drupal\Core\TypedData\TypedDataInterface; use Drupal\Core\Session\AccountInterface; use Drupal\views\Plugin\views\query\Sql; use Drupal\views\Plugin\Core\Entity\View; @@ -1081,13 +1080,6 @@ public function initTranslation($langcode) { } /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::getType(). - */ - public function getType() { - return $this->storage->getType(); - } - - /** * Implements \Drupal\Core\TypedData\TypedDataInterface::getDefinition(). */ public function getDefinition() { @@ -1095,77 +1087,42 @@ public function getDefinition() { } /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::getValue(). - */ - public function getValue() { - return $this->storage->getValue(); - } - - /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::setValue(). - */ - public function setValue($value, $notify = TRUE) { - return $this->storage->setValue($value, $notify); - } - - /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::getString(). - */ - public function getString() { - return $this->storage->getString(); - } - - /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::getConstraints(). - */ - public function getConstraints() { - return $this->storage->getConstraints(); - } - - /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::validate(). - */ - public function validate() { - return $this->storage->validate(); - } - - /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::getName(). + * {@inheritdoc} */ public function getName() { return $this->storage->getName(); } /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::getRoot(). + * {@inheritdoc} */ public function getRoot() { return $this->storage->getRoot(); } /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::getPropertyPath(). + * {@inheritdoc} */ public function getPropertyPath() { return $this->storage->getPropertyPath(); } /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::getParent(). + * {@inheritdoc} */ public function getParent() { return $this->storage->getParent(); } /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::setContext(). + * {@inheritdoc} */ - public function setContext($name = NULL, TypedDataInterface $parent = NULL) { + public function setContext($name = NULL, $parent = NULL) { return $this->storage->setContext($name, $parent); } /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::onChange(). + * {@inheritdoc} */ public function onChange($property_name) { $this->storage->onChange($property_name);