diff --git a/core/lib/Drupal/Core/Config/Schema/ArrayElement.php b/core/lib/Drupal/Core/Config/Schema/ArrayElement.php index 8becdd7..73e9402 100644 --- a/core/lib/Drupal/Core/Config/Schema/ArrayElement.php +++ b/core/lib/Drupal/Core/Config/Schema/ArrayElement.php @@ -6,12 +6,16 @@ */ namespace Drupal\Core\Config\Schema; + +use Drupal\Component\Utility\String; use Drupal\Core\TypedData\TraversableTypedDataInterface; +use Drupal\Core\TypedData\TypedData; +use Drupal\Core\TypedData\TypedDataInterface; /** * Defines a generic configuration element that contains multiple properties. */ -abstract class ArrayElement extends Element implements \IteratorAggregate, TraversableTypedDataInterface, \ArrayAccess, \Countable { +abstract class ArrayElement extends TypedData implements \IteratorAggregate, TraversableTypedDataInterface { /** * Parsed elements. @@ -19,19 +23,6 @@ protected $elements; /** - * Gets an array of contained elements. - * - * @return \Drupal\Core\TypedData\TypedDataInterface[] - * An array of elements contained in this element. - */ - protected function getElements() { - if (!isset($this->elements)) { - $this->elements = $this->parse(); - } - return $this->elements; - } - - /** * Gets valid configuration data keys. * * @return array @@ -47,59 +38,91 @@ protected function getAllKeys() { * @return \Drupal\Core\TypedData\TypedDataInterface[] * An array of elements contained in this element. */ - protected abstract function parse(); + protected function parse() { + $elements = array(); + foreach ($this->getAllKeys() as $key) { + $value = isset($this->value[$key]) ? $this->value[$key] : NULL; + $definition = $this->getElementDefinition($key); + $elements[$key] = $this->createElement($definition, $value, $key); + } + return $elements; + } /** - * Implements TypedDataInterface::validate(). + * {@inheritdoc} */ - public function validate() { - foreach ($this->getElements() as $element) { - if (!$element->validate()) { - return FALSE; + public function get($name) { + $parts = explode('.', $name); + $root_key = array_shift($parts); + $elements = $this->getElements(); + if (isset($elements[$root_key])) { + $element = $elements[$root_key]; + // If $property_name contained a dot recurse into the keys. + while ($element && ($key = array_shift($parts)) !== NULL) { + if ($element instanceof TraversableTypedDataInterface) { + $element = $element->get($key); + } + else { + $element = NULL; + } } } - return TRUE; + if (isset($element)) { + return $element; + } + else { + throw new \InvalidArgumentException(String::format("The configuration property @key doesn't exist.", array('@key' => $name))); + } } /** - * Implements ArrayAccess::offsetExists(). + * {@inheritdoc} */ - public function offsetExists($offset) { - return array_key_exists($offset, $this->getElements()); + public function set($key, $value, $notify = TRUE) { + // Support setting values via typed data objects. + if ($value instanceof TypedDataInterface) { + $value = $value->getValue(); + } + $this->value[$key] = $value; + // Parsed elements must be rebuilt with new values + unset($this->elements); + // Directly notify ourselves. + $this->onChange($key, $value); + return $this; } /** - * Implements ArrayAccess::offsetGet(). + * {@inheritdoc} */ - public function offsetGet($offset) { - $elements = $this->getElements(); - return $elements[$offset]; + public function getElements($include_computed = FALSE) { + if (!isset($this->elements)) { + $this->elements = $this->parse(); + } + return $this->elements; } /** - * Implements ArrayAccess::offsetSet(). + * {@inheritdoc} */ - public function offsetSet($offset, $value) { - if ($value instanceof TypedDataInterface) { - $value = $value->getValue(); - } - $this->value[$offset] = $value; - unset($this->elements); + public function isEmpty() { + return empty($this->value); } /** - * Implements ArrayAccess::offsetUnset(). + * {@inheritdoc} */ - public function offsetUnset($offset) { - unset($this->value[$offset]); - unset($this->elements); + public function toArray() { + return isset($this->value) ? $this->value : array(); } /** - * Implements Countable::count(). + * {@inheritdoc} */ - public function count() { - return count($this->getElements()); + public function onChange($name) { + // Notify the parent of changes. + if (isset($this->parent)) { + $this->parent->onChange($this->name); + } } /** @@ -109,4 +132,39 @@ public function getIterator() { return new \ArrayIterator($this->getElements()); } + /** + * Creates a contained typed configuration object. + * + * @param \Drupal\Core\TypedData\DataDefinitionInterface $definition + * The data definition object. + * @param mixed $value + * (optional) The data value. If set, it has to match one of the supported + * data type format as documented for the data type classes. + * @param string $name + * The key of the contained element. + * + * @return \Drupal\Core\TypedData\TypedDataInterface + */ + protected function createElement($definition, $value, $key) { + return \Drupal::service('config.typed')->create($definition, $value, $key, $this); + } + + /** + * Creates a new data definition object from a type definition array and + * actual configuration data. + * + * @param array $definition + * The base type definition array, for which a data definition should be + * created. + * @param $value + * The value of the configuration element. + * @param string $key + * The key of the contained element. + * + * @return \Drupal\Core\TypedData\DataDefinitionInterface + */ + protected function buildDataDefinition($definition, $value, $key) { + return \Drupal::service('config.typed')->buildDataDefinition($definition, $value, $key, $this); + } + } diff --git a/core/lib/Drupal/Core/Config/Schema/Element.php b/core/lib/Drupal/Core/Config/Schema/Element.php deleted file mode 100644 index c492d42..0000000 --- a/core/lib/Drupal/Core/Config/Schema/Element.php +++ /dev/null @@ -1,40 +0,0 @@ -create($definition, $data, $key, $this); - } - - /** - * Build data definition object for contained elements. - * - * @return \Drupal\Core\TypedData\DataDefinitionInterface - */ - protected function buildDataDefinition($definition, $value, $key) { - return \Drupal::service('config.typed')->buildDataDefinition($definition, $value, $key, $this); - } - -} diff --git a/core/lib/Drupal/Core/Config/Schema/Ignore.php b/core/lib/Drupal/Core/Config/Schema/Ignore.php index 20701b8..22556f8 100644 --- a/core/lib/Drupal/Core/Config/Schema/Ignore.php +++ b/core/lib/Drupal/Core/Config/Schema/Ignore.php @@ -7,15 +7,11 @@ namespace Drupal\Core\Config\Schema; +use Drupal\Core\TypedData\TypedData; + /** * Configuration property to ignore. */ -class Ignore extends Element { +class Ignore extends TypedData { - /** - * {@inheritdoc}. - */ - public function validate() { - return TRUE; - } } diff --git a/core/lib/Drupal/Core/Config/Schema/Mapping.php b/core/lib/Drupal/Core/Config/Schema/Mapping.php index eed1da8..28f22e8 100644 --- a/core/lib/Drupal/Core/Config/Schema/Mapping.php +++ b/core/lib/Drupal/Core/Config/Schema/Mapping.php @@ -8,150 +8,29 @@ namespace Drupal\Core\Config\Schema; use Drupal\Core\TypedData\ComplexDataInterface; -use Drupal\Component\Utility\String; /** * Defines a mapping configuration element. * - * Wraps configuration data and metadata allowing access to configuration data - * using the ComplexDataInterface API. This object may contain any number and - * type of nested properties. + * This object may contain any number and type of nested properties and each + * property key may have its own definition in the 'mapping' property of the + * configuration schema. + * + * Properties in the configuration value that are not defined in the mapping + * will get the 'undefined' data type. + * + * Read https://drupal.org/node/1905070 for more details about configuration + * schema, types and type resolution. */ class Mapping extends ArrayElement implements ComplexDataInterface { /** - * An array of data definitions. - * - * @var \Drupal\Core\TypedData\DataDefinitionInterface[] - */ - protected $propertyDefinitions; - - /** - * {@inheritdoc} - */ - protected function parse() { - $elements = array(); - foreach ($this->getPropertyDefinitions() as $key => $definition) { - $elements[$key] = $this->parseElement($key, $this->value[$key], $definition); - } - return $elements; - } - - /** * {@inheritdoc} - * - * Since all configuration objects are mappings the function will except a dot - * delimited key to access nested values, for example, 'page.front'. - */ - public function get($property_name) { - $parts = explode('.', $property_name); - $root_key = array_shift($parts); - $elements = $this->getElements(); - if (isset($elements[$root_key])) { - $element = $elements[$root_key]; - // If $property_name contained a dot recurse into the keys. - while ($element && ($key = array_shift($parts)) !== NULL) { - if (method_exists($element, 'get')) { - $element = $element->get($key); - } - else { - $element = NULL; - } - } - } - if (isset($element)) { - return $element; - } - else { - throw new \InvalidArgumentException(String::format("The configuration property @key doesn't exist.", array('@key' => $property_name))); - } - } - - /** - * Implements Drupal\Core\TypedData\ComplexDataInterface::set(). - */ - public function set($property_name, $value, $notify = TRUE) { - // 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; - $property = $this->get($property_name); - } - else { - // In these objects, when clearing the value, the property is gone. - // As this needs to return a property, we get it before we delete it. - $property = $this->get($property_name); - unset($this->value[$property_name]); - $property->setValue($value); - } - // Notify the parent of any changes. - if ($notify && isset($this->parent)) { - $this->parent->onChange($this->name); - } - return $this; - } - - /** - * Implements Drupal\Core\TypedData\ComplexDataInterface::getProperties(). - */ - public function getProperties($include_computed = FALSE) { - return $this->getElements(); - } - - /** - * {@inheritdoc} - */ - public function toArray() { - return $this->getValue(); - } - - /** - * Gets the definition of a contained property. - * - * @param string $name - * The name of property. - * - * @return \Drupal\Core\TypedData\DataDefinitionInterface|null - * The definition of the property or NULL if the property does not exist. - */ - public function getPropertyDefinition($name) { - $definitions = $this->getPropertyDefinitions(); - return isset($definitions[$name]) ? isset($definitions[$name]) : NULL; - } - - /** - * Gets an array of property definitions of contained properties. - * - * @return \Drupal\Core\TypedData\DataDefinitionInterface[] - * An array of property definitions of contained properties, keyed by - * property name. - */ - public function getPropertyDefinitions() { - if (!isset($this->propertyDefinitions)) { - $this->propertyDefinitions = array(); - foreach ($this->getAllKeys() as $key) { - $definition = isset($this->definition['mapping'][$key]) ? $this->definition['mapping'][$key] : array(); - $this->propertyDefinitions[$key] = $this->buildDataDefinition($definition, $this->value[$key], $key); - } - } - return $this->propertyDefinitions; - } - - /** - * Implements Drupal\Core\TypedData\ComplexDataInterface::isEmpty(). - */ - public function isEmpty() { - return empty($this->value); - } - - /** - * Implements \Drupal\Core\TypedData\ComplexDataInterface::onChange(). */ - public function onChange($property_name) { - // Notify the parent of changes. - if (isset($this->parent)) { - $this->parent->onChange($this->name); - } + public function getElementDefinition($key) { + $value = isset($this->value[$key]) ? $this->value[$key] : NULL; + $definition = isset($this->definition['mapping'][$key]) ? $this->definition['mapping'][$key] : array(); + return $this->buildDataDefinition($definition, $value, $key); } } diff --git a/core/lib/Drupal/Core/Config/Schema/Sequence.php b/core/lib/Drupal/Core/Config/Schema/Sequence.php index bce81a9..4190330 100644 --- a/core/lib/Drupal/Core/Config/Schema/Sequence.php +++ b/core/lib/Drupal/Core/Config/Schema/Sequence.php @@ -8,85 +8,35 @@ namespace Drupal\Core\Config\Schema; use Drupal\Core\TypedData\ListInterface; +use Drupal\Core\TypedData\ListTrait; /** * Defines a configuration element of type Sequence. + * + * This object may contain any number and type of nested elements that share + * a common definition in the 'sequence' property of the configuration schema. + * + * Read https://drupal.org/node/1905070 for more details about configuration + * schema, types and type resolution. */ class Sequence extends ArrayElement implements ListInterface { - /** - * Data definition - * - * @var \Drupal\Core\TypedData\DataDefinitionInterface - */ - protected $itemDefinition; + use ListTrait; /** * {@inheritdoc} */ - protected function parse() { - // Creates a new data definition object for each item from the generic type - // definition array and actual configuration data for that item. Type - // definitions may contain variables to be replaced and those depend on - // each item's data. - $definition = isset($this->definition['sequence'][0]) ? $this->definition['sequence'][0] : array(); - $elements = array(); - foreach ($this->value as $key => $value) { - $data_definition = $this->buildDataDefinition($definition, $value, $key); - $elements[$key] = $this->parseElement($key, $value, $data_definition); - } - return $elements; - } - - /** - * Implements Drupal\Core\TypedData\ListInterface::isEmpty(). - */ - public function isEmpty() { - return empty($this->value); - } - - /** - * Implements Drupal\Core\TypedData\ListInterface::getItemDefinition(). - */ public function getItemDefinition() { - if (!isset($this->itemDefinition)) { - $definition = isset($this->definition['sequence'][0]) ? $this->definition['sequence'][0] : array(); - $this->itemDefinition = $this->buildDataDefinition($definition, NULL); - } - return $this->itemDefinition; - } - - /** - * Implements \Drupal\Core\TypedData\ListInterface::onChange(). - */ - public function onChange($delta) { - // Notify the parent of changes. - if (isset($this->parent)) { - $this->parent->onChange($this->name); - } + return $this->getElementDefinition(0); } /** * {@inheritdoc} */ - public function get($key) { - $elements = $this->getElements(); - return $elements[$key]; - } - - /** - * {@inheritdoc} - */ - public function first() { - return $this->get(0); - } - - /** - * {@inheritdoc} - */ - public function set($index, $item) { - $this->offsetSet($index, $item); - return $this; + public function getElementDefinition($key) { + $value = isset($this->value[$key]) ? $this->value[$key] : NULL; + $definition = isset($this->definition['sequence'][0]) ? $this->definition['sequence'][0] : array(); + return $this->buildDataDefinition($definition, $value, $key); } /** diff --git a/core/lib/Drupal/Core/Config/Schema/Undefined.php b/core/lib/Drupal/Core/Config/Schema/Undefined.php index 1bcf744..4906de7 100644 --- a/core/lib/Drupal/Core/Config/Schema/Undefined.php +++ b/core/lib/Drupal/Core/Config/Schema/Undefined.php @@ -7,15 +7,11 @@ namespace Drupal\Core\Config\Schema; +use Drupal\Core\TypedData\TypedData; + /** * Undefined configuration element. */ -class Undefined extends Element { +class Undefined extends TypedData { - /** - * {@inheritdoc}. - */ - public function validate() { - return isset($this->value); - } } diff --git a/core/lib/Drupal/Core/Config/TypedConfigManager.php b/core/lib/Drupal/Core/Config/TypedConfigManager.php index fb1c198..0f05c5d 100644 --- a/core/lib/Drupal/Core/Config/TypedConfigManager.php +++ b/core/lib/Drupal/Core/Config/TypedConfigManager.php @@ -64,8 +64,8 @@ public function __construct(StorageInterface $configStorage, StorageInterface $s * @param string $name * Configuration object name. * - * @return \Drupal\Core\Config\Schema\Element - * Typed configuration element. + * @return \Drupal\Core\TypedData\TraversableTypedDataInterface + * Typed configuration data. */ public function get($name) { $data = $this->configStorage->read($name); diff --git a/core/lib/Drupal/Core/Config/TypedConfigManagerInterface.php b/core/lib/Drupal/Core/Config/TypedConfigManagerInterface.php index 84d347b..f9e0f84 100644 --- a/core/lib/Drupal/Core/Config/TypedConfigManagerInterface.php +++ b/core/lib/Drupal/Core/Config/TypedConfigManagerInterface.php @@ -10,6 +10,7 @@ use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface; use Drupal\Component\Plugin\PluginManagerInterface; use Drupal\Core\TypedData\DataDefinitionInterface; +use Drupal\Core\TypedData\TraversableTypedDataInterface; /** * Defines an interface for typed configuration manager. @@ -42,10 +43,9 @@ public function get($name); * - name: (optional) If a property or list item is to be created, the name * of the property or the delta of the list item. * - parent: (optional) If a property or list item is to be created, the - * parent typed data object implementing either the ListInterface or the - * ComplexDataInterface. + * parent typed data object implementing TraversableTypedDataInterface. * - * @return \Drupal\Core\Config\Schema\Element + * @return \Drupal\Core\TypedData\TypedDataInterface * The instantiated typed configuration object. */ public function createInstance($data_type, array $configuration = array()); @@ -61,15 +61,14 @@ public function createInstance($data_type, array $configuration = array()); * @param string $name * (optional) If a property or list item is to be created, the name of the * property or the delta of the list item. - * @param mixed $parent + * @param \Drupal\Core\TypedData\TraversableTypedDataInterface $parent * (optional) If a property or list item is to be created, the parent typed - * data object implementing either the ListInterface or the - * ComplexDataInterface. + * data object. * - * @return \Drupal\Core\Config\Schema\Element + * @return \Drupal\Core\TypedData\TypedDataInterface * The instantiated typed data object. */ - public function create(DataDefinitionInterface $definition, $value, $name = NULL, $parent = NULL); + public function create(DataDefinitionInterface $definition, $value, $name = NULL, TraversableTypedDataInterface $parent = NULL); /** * Creates a new data definition object from a type definition array and diff --git a/core/lib/Drupal/Core/Entity/ContentEntityBase.php b/core/lib/Drupal/Core/Entity/ContentEntityBase.php index a767326..4fd9beb 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php @@ -939,7 +939,7 @@ public function referencedEntities() { foreach ($this->getFields() as $field_items) { foreach ($field_items as $field_item) { // Loop over all properties of a field item. - foreach ($field_item->getProperties(TRUE) as $property) { + foreach ($field_item->getElements(TRUE) as $property) { if ($property instanceof EntityReference && $entity = $property->getValue()) { $referenced_entities[] = $entity; } diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityAdapter.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityAdapter.php index bbcb0bb..8fb5ade 100644 --- a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityAdapter.php +++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityAdapter.php @@ -112,7 +112,7 @@ public function set($property_name, $value, $notify = TRUE) { /** * {@inheritdoc} */ - public function getProperties($include_computed = FALSE) { + public function getElements($include_computed = FALSE) { if (!isset($this->entity)) { throw new MissingDataException(String::format('Unable to get properties as no entity has been provided.')); } @@ -127,6 +127,13 @@ public function getProperties($include_computed = FALSE) { /** * {@inheritdoc} */ + public function getElementDefinition($name) { + return $this->getDataDefinition()->getPropertyDefinition($name); + } + + /** + * {@inheritdoc} + */ public function toArray() { if (!isset($this->entity)) { throw new MissingDataException(String::format('Unable to get property values as no entity has been provided.')); @@ -170,7 +177,7 @@ public function getString() { */ public function applyDefaultValue($notify = TRUE) { // Apply the default value of all properties. - foreach ($this->getProperties() as $property) { + foreach ($this->getElements() as $property) { $property->applyDefaultValue(FALSE); } return $this; diff --git a/core/lib/Drupal/Core/Field/FieldItemBase.php b/core/lib/Drupal/Core/Field/FieldItemBase.php index b411b88..f11bd13 100644 --- a/core/lib/Drupal/Core/Field/FieldItemBase.php +++ b/core/lib/Drupal/Core/Field/FieldItemBase.php @@ -51,6 +51,18 @@ public static function mainPropertyName() { */ public function __construct(DataDefinitionInterface $definition, $name = NULL, TypedDataInterface $parent = NULL) { parent::__construct($definition, $name, $parent); + // Data types such as Integer or String use a simple value property to + // manage their value, which is why TypedData::getValue() uses that property + // for convencience of those data types. By declaring it as a member + // variable of the TypedData class, however, PHP sets a NULL value to it + // upon instantiation. This breaks field types which have a 'value' property + // as by inheriting from this class they inherit from TypedData as well and, + // thus, $field_item->value returns NULL directly instead of asking + // FieldItemBase::__get() for the proper value stored in + // $field_item->values['value']. Hence, we unset the NULL value. + // @todo Clean this up. + unset($this->value); + // Initialize computed properties by default, such that they get cloned // with the whole item. foreach ($this->definition->getPropertyDefinitions() as $name => $definition) { diff --git a/core/lib/Drupal/Core/Field/FieldItemListInterface.php b/core/lib/Drupal/Core/Field/FieldItemListInterface.php index fcaa9b1..9fde3e8 100644 --- a/core/lib/Drupal/Core/Field/FieldItemListInterface.php +++ b/core/lib/Drupal/Core/Field/FieldItemListInterface.php @@ -28,7 +28,7 @@ * When implementing this interface which extends Traversable, make sure to list * IteratorAggregate or Iterator before this interface in the implements clause. */ -interface FieldItemListInterface extends ListInterface, AccessibleInterface { +interface FieldItemListInterface extends ListInterface, AccessibleInterface, \Countable, \ArrayAccess { /** * Gets the entity that field belongs to. diff --git a/core/lib/Drupal/Core/TypedData/ComplexDataInterface.php b/core/lib/Drupal/Core/TypedData/ComplexDataInterface.php index b60f84d..1a566db 100644 --- a/core/lib/Drupal/Core/TypedData/ComplexDataInterface.php +++ b/core/lib/Drupal/Core/TypedData/ComplexDataInterface.php @@ -24,79 +24,4 @@ * @ingroup typed_data */ interface ComplexDataInterface extends TraversableTypedDataInterface { - - /** - * Gets a property object. - * - * @param $property_name - * The name of the property to get; e.g., 'title' or 'name'. - * - * @return \Drupal\Core\TypedData\TypedDataInterface - * The property object. - * - * @throws \InvalidArgumentException - * If an invalid property name is given. - * @throws \Drupal\Core\TypedData\Exception\MissingDataException - * If the complex data structure is unset and no property can be created. - */ - public function get($property_name); - - /** - * Sets a property value. - * - * @param $property_name - * The name of the property to set; e.g., 'title' or 'name'. - * @param $value - * The value to set, or NULL to unset the property. - * @param bool $notify - * (optional) Whether to notify the parent object of the change. Defaults to - * TRUE. If the update stems from a parent object, set it to FALSE to avoid - * being notified again. - * - * @return $this - * - * @throws \InvalidArgumentException - * If the specified property does not exist. - * @throws \Drupal\Core\TypedData\Exception\MissingDataException - * If the complex data structure is unset and no property can be set. - */ - public function set($property_name, $value, $notify = TRUE); - - /** - * Gets an array of property objects. - * - * @param bool $include_computed - * If set to TRUE, computed properties are included. Defaults to FALSE. - * - * @return \Drupal\Core\TypedData\TypedDataInterface[] - * An array of property objects implementing the TypedDataInterface, keyed - * by property name. - * - * @throws \Drupal\Core\TypedData\Exception\MissingDataException - * If the complex data structure is unset and no property can be created. - */ - public function getProperties($include_computed = FALSE); - - /** - * Returns an array of all property values. - * - * Gets an array of plain property values including all not-computed - * properties. - * - * @return array - * An array of property values, keyed by property name. - * - * @throws \Drupal\Core\TypedData\Exception\MissingDataException - * If the complex data structure is unset and no property can be created. - */ - public function toArray(); - - /** - * Determines whether the data structure is empty. - * - * @return boolean - * TRUE if the data structure is empty, FALSE otherwise. - */ - public function isEmpty(); - } diff --git a/core/lib/Drupal/Core/TypedData/ListInterface.php b/core/lib/Drupal/Core/TypedData/ListInterface.php index 09dce07..500467b 100644 --- a/core/lib/Drupal/Core/TypedData/ListInterface.php +++ b/core/lib/Drupal/Core/TypedData/ListInterface.php @@ -20,15 +20,7 @@ * * @ingroup typed_data */ -interface ListInterface extends TraversableTypedDataInterface, \ArrayAccess, \Countable { - - /** - * Determines whether the list contains any non-empty items. - * - * @return boolean - * TRUE if the list is empty, FALSE otherwise. - */ - public function isEmpty(); +interface ListInterface extends TraversableTypedDataInterface { /** * Gets the definition of a contained item. @@ -39,37 +31,6 @@ public function isEmpty(); public function getItemDefinition(); /** - * Returns the item at the specified position in this list. - * - * @param int $index - * Index of the item to return. - * - * @return \Drupal\Core\TypedData\TypedDataInterface - * The item at the specified position in this list. An empty item is created - * if it does not exist yet. - * - * @throws \Drupal\Core\TypedData\Exception\MissingDataException - * If the complex data structure is unset and no item can be created. - */ - public function get($index); - - /** - * Replaces the item at the specified position in this list. - * - * @param int $index - * Index of the item to replace. - * @param mixed - * Item to be stored at the specified position. - * - * @return static - * Returns the list. - * - * @throws \Drupal\Core\TypedData\Exception\MissingDataException - * If the complex data structure is unset and no item can be set. - */ - public function set($index, $item); - - /** * Returns the first item in this list. * * @return \Drupal\Core\TypedData\TypedDataInterface diff --git a/core/lib/Drupal/Core/TypedData/ListTrait.php b/core/lib/Drupal/Core/TypedData/ListTrait.php new file mode 100644 index 0000000..aafed5b --- /dev/null +++ b/core/lib/Drupal/Core/TypedData/ListTrait.php @@ -0,0 +1,31 @@ +get(0); + } + +} + diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/ItemList.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/ItemList.php index 52fc0b0..461f388 100644 --- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/ItemList.php +++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/ItemList.php @@ -7,8 +7,9 @@ namespace Drupal\Core\TypedData\Plugin\DataType; -use Drupal\Core\TypedData\ComplexDataInterface; use Drupal\Core\TypedData\ListInterface; +use Drupal\Core\TypedData\ListTrait; +use Drupal\Core\TypedData\TraversableTypedDataInterface; use Drupal\Core\TypedData\TypedData; use Drupal\Core\TypedData\TypedDataInterface; @@ -28,7 +29,9 @@ * definition_class = "\Drupal\Core\TypedData\ListDataDefinition" * ) */ -class ItemList extends TypedData implements \IteratorAggregate, ListInterface { +class ItemList extends TypedData implements \IteratorAggregate, ListInterface, \Countable, \ArrayAccess { + + use ListTrait; /** * Numerically indexed array of items. @@ -115,7 +118,7 @@ public function get($index) { /** * {@inheritdoc} */ - public function set($index, $item) { + public function set($index, $item, $notify = TRUE) { if (is_numeric($index)) { // Support setting values via typed data objects. if ($item instanceof TypedDataInterface) { @@ -132,8 +135,8 @@ public function set($index, $item) { /** * {@inheritdoc} */ - public function first() { - return $this->get(0); + public function getElements($include_computed = FALSE) { + return $this->list; } /** @@ -167,13 +170,20 @@ protected function createItem($offset = 0, $value = NULL) { } /** - * Implements \Drupal\Core\TypedData\ListInterface::getItemDefinition(). + * {@inheritdoc} */ public function getItemDefinition() { return $this->definition->getItemDefinition(); } /** + * {@inheritdoc} + */ + public function getElementDefinition($name) { + return $this->getItemDefinition(); + } + + /** * Implements \ArrayAccess::offsetSet(). */ public function offsetSet($offset, $value) { @@ -199,11 +209,11 @@ public function count() { } /** - * Implements \Drupal\Core\TypedData\ListInterface::isEmpty(). + * {@inheritdoc} */ public function isEmpty() { foreach ($this->list as $item) { - if ($item instanceof ComplexDataInterface || $item instanceof ListInterface) { + if ($item instanceof TraversableTypedDataInterface) { if (!$item->isEmpty()) { return FALSE; } @@ -242,7 +252,7 @@ public function filter($callback) { } /** - * Implements \Drupal\Core\TypedData\ListInterface::onChange(). + * {@inheritdoc} */ public function onChange($delta) { // Notify the parent of changes. @@ -261,4 +271,11 @@ public function __clone() { } } + /** + * {@inheritdoc} + */ + public function toArray() { + return iterator_to_array($this->getIterator()); + } + } diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php index 7694db5..d2d099a 100644 --- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php +++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php @@ -65,6 +65,14 @@ protected function getPropertyDefinitions() { /** * {@inheritdoc} */ + public function getElementDefinition($name) { + return $this->getDataDefinition()->getPropertyDefinition($name); + } + + + /** + * {@inheritdoc} + */ public function getValue() { // Update the values and return them. foreach ($this->properties as $name => $property) { @@ -111,7 +119,7 @@ public function setValue($values, $notify = TRUE) { */ public function getString() { $strings = array(); - foreach ($this->getProperties() as $property) { + foreach ($this->getElements() as $property) { $strings[] = $property->getString(); } // Remove any empty strings resulting from empty items. @@ -168,7 +176,7 @@ protected function writePropertyValue($property_name, $value) { /** * Implements \Drupal\Core\TypedData\ComplexDataInterface::getProperties(). */ - public function getProperties($include_computed = FALSE) { + public function getElements($include_computed = FALSE) { $properties = array(); foreach ($this->definition->getPropertyDefinitions() as $name => $definition) { if ($include_computed || !$definition->isComputed()) { @@ -183,7 +191,7 @@ public function getProperties($include_computed = FALSE) { */ public function toArray() { $values = array(); - foreach ($this->getProperties() as $name => $property) { + foreach ($this->getElements() as $name => $property) { $values[$name] = $property->getValue(); } return $values; @@ -193,7 +201,7 @@ public function toArray() { * Implements \IteratorAggregate::getIterator(). */ public function getIterator() { - return new \ArrayIterator($this->getProperties()); + return new \ArrayIterator($this->getElements()); } /** @@ -246,7 +254,7 @@ public function onChange($property_name, $notify = TRUE) { */ public function applyDefaultValue($notify = TRUE) { // Apply the default value of all properties. - foreach ($this->getProperties() as $property) { + foreach ($this->getElements() as $property) { $property->applyDefaultValue(FALSE); } return $this; diff --git a/core/lib/Drupal/Core/TypedData/TraversableTypedDataInterface.php b/core/lib/Drupal/Core/TypedData/TraversableTypedDataInterface.php index 34b1df5..a37f15a 100644 --- a/core/lib/Drupal/Core/TypedData/TraversableTypedDataInterface.php +++ b/core/lib/Drupal/Core/TypedData/TraversableTypedDataInterface.php @@ -13,6 +13,81 @@ interface TraversableTypedDataInterface extends TypedDataInterface, \Traversable { /** + * Gets an element. + * + * This returns a property object for complex data objects and an item for + * item list objects. + * + * @param string|int $key + * The name of the property or the index of the item to get. + * + * @return \Drupal\Core\TypedData\TypedDataInterface + * The property object. + * + * @throws \InvalidArgumentException + * If an invalid property name or item index is given. + * @throws \Drupal\Core\TypedData\Exception\MissingDataException + * If the data structure is unset and no property can be created. + */ + public function get($key); + + /** + * Sets an element value. + * + * @param $key + * The name of the property or the index of the item to set. + * @param $value + * The value to set, or NULL to unset the property. + * @param bool $notify + * (optional) Whether to notify the parent object of the change. Defaults to + * TRUE. If the update stems from a parent object, set it to FALSE to avoid + * being notified again. + * + * @return \Drupal\Core\TypedData\TypedDataInterface + * The property object. + * + * @throws \InvalidArgumentException + * If the specified property does not exist. + * @throws \Drupal\Core\TypedData\Exception\MissingDataException + * If the complex data structure is unset and no property can be set. + */ + public function set($key, $value, $notify = TRUE); + + /** + * Gets an array of contained elements. + * + * @param bool $include_computed + * (optional) If set to TRUE, computed properties are included. Defaults to + * FALSE. + * + * @return \Drupal\Core\TypedData\TypedDataInterface[] + * An array of the contained objects. + * + * @throws \Drupal\Core\TypedData\Exception\MissingDataException + * If the complex data structure is unset and no property can be created. + */ + public function getElements($include_computed = FALSE); + + /** + * Gets the definition of a contained element. + * + * @param string|int $key + * The name of the property or the index of the item to get. + * + * @return \Drupal\Core\TypedData\DataDefinitionInterface|null + * The definition of the property or NULL if the property does not exist. + */ + public function getElementDefinition($name); + + /** + * Determines whether the data object contains any non-empty items. + * + * @return boolean + * TRUE if the data object is empty, FALSE otherwise. + */ + public function isEmpty(); + + /** * React to changes to a child property or item. * * Note that this is invoked after any changes have been applied. @@ -22,4 +97,18 @@ */ public function onChange($name); + /** + * Returns an array of all property values. + * + * Gets an array of plain property values including all not-computed + * properties. + * + * @return array + * An array of property values, keyed by property name. + * + * @throws \Drupal\Core\TypedData\Exception\MissingDataException + * If the data structure is unset and no property can be created. + */ + public function toArray(); + } diff --git a/core/lib/Drupal/Core/TypedData/TypedData.php b/core/lib/Drupal/Core/TypedData/TypedData.php index 3216d21..bd7caa7 100644 --- a/core/lib/Drupal/Core/TypedData/TypedData.php +++ b/core/lib/Drupal/Core/TypedData/TypedData.php @@ -44,6 +44,13 @@ protected $parent; /** + * The configuration value. + * + * @var mixed + */ + protected $value; + + /** * {@inheritdoc} */ public static function createInstance($definition, $name = NULL, TraversableTypedDataInterface $parent = NULL) { diff --git a/core/lib/Drupal/Core/TypedData/TypedDataManager.php b/core/lib/Drupal/Core/TypedData/TypedDataManager.php index d42a3d2..38c1264 100644 --- a/core/lib/Drupal/Core/TypedData/TypedDataManager.php +++ b/core/lib/Drupal/Core/TypedData/TypedDataManager.php @@ -74,8 +74,7 @@ public function __construct(\Traversable $namespaces, CacheBackendInterface $cac * - name: (optional) If a property or list item is to be created, the name * of the property or the delta of the list item. * - parent: (optional) If a property or list item is to be created, the - * parent typed data object implementing either the ListInterface or the - * ComplexDataInterface. + * parent typed data object implementing TraversableTypedDataInterface. * * @return \Drupal\Core\TypedData\TypedDataInterface * The instantiated typed data object. @@ -110,10 +109,9 @@ public function createInstance($data_type, array $configuration = array()) { * @param string $name * (optional) If a property or list item is to be created, the name of the * property or the delta of the list item. - * @param mixed $parent + * @param \Drupal\Core\TypedData\TraversableTypedDataInterface $parent * (optional) If a property or list item is to be created, the parent typed - * data object implementing either the ListInterface or the - * ComplexDataInterface. + * data object. * * @return \Drupal\Core\TypedData\TypedDataInterface * The instantiated typed data object. @@ -129,7 +127,7 @@ public function createInstance($data_type, array $configuration = array()) { * @see \Drupal\Core\TypedData\Plugin\DataType\Uri * @see \Drupal\Core\TypedData\Plugin\DataType\Binary */ - public function create(DataDefinitionInterface $definition, $value = NULL, $name = NULL, $parent = NULL) { + public function create(DataDefinitionInterface $definition, $value = NULL, $name = NULL, TraversableTypedDataInterface $parent = NULL) { $typed_data = $this->createInstance($definition->getDataType(), array( 'data_definition' => $definition, 'name' => $name, @@ -196,9 +194,8 @@ public function createListDataDefinition($item_type) { * * @param array $options * An array of options with the following keys: - * - object: The parent typed data object, implementing the - * TypedDataInterface and either the ListInterface or the - * ComplexDataInterface. + * - object: The parent typed data object, implementing + * TraversableTypedDataInterface. * - property: The name of the property to instantiate, or the delta of the * the list item to instantiate. * - value: The value to set. If set, it has to match one of the supported @@ -206,7 +203,7 @@ public function createListDataDefinition($item_type) { * * @throws \InvalidArgumentException * If the given property is not known, or the passed object does not - * implement the ListInterface or the ComplexDataInterface. + * implement TraversableTypedDataInterface. * * @return \Drupal\Core\TypedData\TypedDataInterface * The new property instance. @@ -228,9 +225,8 @@ 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 - * The parent typed data object, implementing the TypedDataInterface and - * either the ListInterface or the ComplexDataInterface. + * @param \Drupal\Core\TypedData\TraversableTypedDataInterface $object + * The parent typed data object. * @param string $property_name * The name of the property to instantiate, or the delta of an list item. * @param mixed $value @@ -239,14 +235,14 @@ public function getInstance(array $options) { * * @throws \InvalidArgumentException * If the given property is not known, or the passed object does not - * implement the ListInterface or the ComplexDataInterface. + * implement TraversableTypedDataInterface. * * @return \Drupal\Core\TypedData\TypedDataInterface * The new property instance. * * @see \Drupal\Core\TypedData\TypedDataManager::create() */ - public function getPropertyInstance(TypedDataInterface $object, $property_name, $value = NULL) { + public function getPropertyInstance(TraversableTypedDataInterface $object, $property_name, $value = NULL) { // For performance, try to reuse existing prototypes instead of // constructing new objects when possible. A prototype is reused when // creating a data object: @@ -271,17 +267,16 @@ public function getPropertyInstance(TypedDataInterface $object, $property_name, $parts[] = $object->getPropertyPath() . '.' . (is_numeric($property_name) ? 0 : $property_name); $key = implode(':', $parts); - // Create the prototype if needed. + // Make sure we have a prototype. Then, clone the prototype and set object + // specific values, i.e. the value and the context. if (!isset($this->prototypes[$key])) { - // Fetch the data definition for the child object from the parent. - if ($object instanceof ComplexDataInterface) { - $definition = $object->getDataDefinition()->getPropertyDefinition($property_name); - } - elseif ($object instanceof ListInterface) { - $definition = $object->getItemDefinition(); + // Create the initial prototype. For that we need to fetch the definition + // of the to be created property instance from the parent. + if ($object instanceof TraversableTypedDataInterface) { + $definition = $object->getElementDefinition($property_name); } else { - throw new \InvalidArgumentException("The passed object has to either implement the ComplexDataInterface or the ListInterface."); + throw new \InvalidArgumentException("The passed object has to either implement TraversableTypedDataInterface."); } if (!$definition) { throw new \InvalidArgumentException('Property ' . String::checkPlain($property_name) . ' is unknown.'); diff --git a/core/lib/Drupal/Core/TypedData/Validation/MetadataFactory.php b/core/lib/Drupal/Core/TypedData/Validation/MetadataFactory.php index 2858daf..53253ff 100644 --- a/core/lib/Drupal/Core/TypedData/Validation/MetadataFactory.php +++ b/core/lib/Drupal/Core/TypedData/Validation/MetadataFactory.php @@ -7,8 +7,7 @@ namespace Drupal\Core\TypedData\Validation; -use Drupal\Core\TypedData\ComplexDataInterface; -use Drupal\Core\TypedData\ListInterface; +use Drupal\Core\TypedData\TraversableTypedDataInterface; use Drupal\Core\TypedData\TypedDataInterface; use Symfony\Component\Validator\MetadataFactoryInterface; @@ -30,7 +29,7 @@ public function getMetadataFor($typed_data, $name = '') { if (!$typed_data instanceof TypedDataInterface) { throw new \InvalidArgumentException('The passed value must be a typed data object.'); } - $is_container = $typed_data instanceof ComplexDataInterface || $typed_data instanceof ListInterface; + $is_container = $typed_data instanceof TraversableTypedDataInterface; $class = '\Drupal\Core\TypedData\Validation\\' . ($is_container ? 'PropertyContainerMetadata' : 'Metadata'); return new $class($typed_data, $name, $this); } diff --git a/core/lib/Drupal/Core/TypedData/Validation/PropertyContainerMetadata.php b/core/lib/Drupal/Core/TypedData/Validation/PropertyContainerMetadata.php index f5850eb..86c06f8 100644 --- a/core/lib/Drupal/Core/TypedData/Validation/PropertyContainerMetadata.php +++ b/core/lib/Drupal/Core/TypedData/Validation/PropertyContainerMetadata.php @@ -7,8 +7,7 @@ namespace Drupal\Core\TypedData\Validation; -use Drupal\Core\TypedData\ComplexDataInterface; -use Drupal\Core\TypedData\ListInterface; +use Drupal\Core\TypedData\TraversableTypedDataInterface; use Symfony\Component\Validator\PropertyMetadataContainerInterface; use Symfony\Component\Validator\ValidationVisitorInterface; @@ -55,10 +54,7 @@ public function hasPropertyMetadata($property_name) { * Implements PropertyMetadataContainerInterface::getPropertyMetadata(). */ public function getPropertyMetadata($property_name) { - if ($this->typedData instanceof ListInterface) { - return array(new Metadata($this->typedData[$property_name], $property_name)); - } - elseif ($this->typedData instanceof ComplexDataInterface) { + if ($this->typedData instanceof TraversableTypedDataInterface) { return array(new Metadata($this->typedData->get($property_name), $property_name)); } else { diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ComplexDataConstraintValidator.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ComplexDataConstraintValidator.php index 31ffc5b..0913749 100644 --- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ComplexDataConstraintValidator.php +++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ComplexDataConstraintValidator.php @@ -8,6 +8,7 @@ namespace Drupal\Core\Validation\Plugin\Validation\Constraint; use Drupal\Core\TypedData\ComplexDataInterface; +use Drupal\Core\TypedData\TraversableTypedDataInterface; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\Exception\UnexpectedTypeException; @@ -33,8 +34,7 @@ public function validate($value, Constraint $constraint) { foreach ($constraint->properties as $name => $constraints) { $property = $value->get($name); - $is_container = $property instanceof ComplexDataInterface || $property instanceof ListInterface; - if (!$is_container) { + if (!($property instanceof TraversableTypedDataInterface)) { $property = $property->getValue(); } elseif ($property->isEmpty()) { diff --git a/core/modules/config/src/Tests/ConfigSchemaTest.php b/core/modules/config/src/Tests/ConfigSchemaTest.php index c7a6f55..19967a1 100644 --- a/core/modules/config/src/Tests/ConfigSchemaTest.php +++ b/core/modules/config/src/Tests/ConfigSchemaTest.php @@ -68,21 +68,21 @@ function testSchemaMapping() { // Check type detection on elements with undefined types. $config = \Drupal::service('config.typed')->get('config_schema_test.someschema'); - $definition = $config['testitem']->getDataDefinition()->toArray(); + $definition = $config->get('testitem')->getDataDefinition()->toArray(); $expected = array(); $expected['label'] = 'Test item'; $expected['class'] = '\Drupal\Core\Config\Schema\Undefined'; $expected['type'] = 'undefined'; $expected['definition_class'] = '\Drupal\Core\TypedData\DataDefinition'; $this->assertEqual($definition, $expected, 'Automatic type detected for a scalar is undefined.'); - $definition = $config['testlist']->getDataDefinition()->toArray(); + $definition = $config->get('testlist')->getDataDefinition()->toArray(); $expected = array(); $expected['label'] = 'Test list'; $expected['class'] = '\Drupal\Core\Config\Schema\Undefined'; $expected['type'] = 'undefined'; $expected['definition_class'] = '\Drupal\Core\TypedData\DataDefinition'; $this->assertEqual($definition, $expected, 'Automatic type detected for a list is undefined.'); - $definition = $config['testnoschema']->getDataDefinition()->toArray(); + $definition = $config->get('testnoschema')->getDataDefinition()->toArray(); $expected = array(); $expected['label'] = 'Undefined'; $expected['class'] = '\Drupal\Core\Config\Schema\Undefined'; @@ -196,7 +196,7 @@ function testSchemaMapping() { // Most complex case, get metadata for actual configuration element. $effects = \Drupal::service('config.typed')->get('image.style.medium')->get('effects'); - $definition = $effects['bddf0d06-42f9-4c75-a700-a33cafa25ea0']['data']->getDataDefinition()->toArray(); + $definition = $effects->get('bddf0d06-42f9-4c75-a700-a33cafa25ea0')->get('data')->getDataDefinition()->toArray(); // This should be the schema for image.effect.image_scale, reuse previous one. $expected['type'] = 'image.effect.image_scale'; @@ -230,7 +230,7 @@ function testSchemaMappingWithParents() { // Test fetching parent one level up. $entry = $config_data->get('one_level'); - $definition = $entry['testitem']->getDataDefinition()->toArray(); + $definition = $entry->get('testitem')->getDataDefinition()->toArray(); $expected = array( 'type' => 'config_schema_test.someschema.with_parents.key_1', 'label' => 'Test item nested one level', @@ -241,7 +241,7 @@ function testSchemaMappingWithParents() { // Test fetching parent two levels up. $entry = $config_data->get('two_levels'); - $definition = $entry['wrapper']['testitem']->getDataDefinition()->toArray(); + $definition = $entry->get('wrapper')->get('testitem')->getDataDefinition()->toArray(); $expected = array( 'type' => 'config_schema_test.someschema.with_parents.key_2', 'label' => 'Test item nested two levels', @@ -252,7 +252,7 @@ function testSchemaMappingWithParents() { // Test fetching parent three levels up. $entry = $config_data->get('three_levels'); - $definition = $entry['wrapper_1']['wrapper_2']['testitem']->getDataDefinition()->toArray(); + $definition = $entry->get('wrapper_1')->get('wrapper_2')->get('testitem')->getDataDefinition()->toArray(); $expected = array( 'type' => 'config_schema_test.someschema.with_parents.key_3', 'label' => 'Test item nested three levels', @@ -282,27 +282,29 @@ function testSchemaData() { // Check nested array of properties. $list = $meta->get('page'); - $this->assertEqual(count($list), 3, 'Got a list with the right number of properties for site page data'); - $this->assertTrue(isset($list['front']) && isset($list['403']) && isset($list['404']), 'Got a list with the right properties for site page data.'); - $this->assertEqual($list['front']->getValue(), 'user/login', 'Got the right value for page.front data from the list.'); - - // And test some ComplexDataInterface methods. - $properties = $list->getProperties(); - $this->assertTrue(count($properties) == 3 && $properties['front'] == $list['front'], 'Got the right properties for site page.'); - $values = $list->toArray(); - $this->assertTrue(count($values) == 3 && $values['front'] == 'user/login', 'Got the right property values for site page.'); + $this->assertTrue((bool) $list->get('front')); + $this->assertTrue((bool) $list->get('403')); + $this->assertTrue((bool) $list->get('404')); + $this->assertEqual($list->get('front')->getValue(), 'user/login', 'Got the right value for page.front data from the list.'); + + // And test some TraversableTypedDataInterface methods. + $properties = $list->getElements(); + $this->assertIdentical(count($properties), 3); + // assertIdentical() cannot be used here as that uses var_export() on the + // passed objects, but this typed data object contains recursive references. + $this->assertTrue($properties['front'] === $list->get('front')); + $values = $meta->get('page'); + $this->assertIdentical($values->get('front')->getValue(), 'user/login'); // Now let's try something more complex, with nested objects. $wrapper = \Drupal::service('config.typed')->get('image.style.large'); $effects = $wrapper->get('effects'); - - // The function is_array() doesn't work with ArrayAccess, so we use count(). $this->assertTrue(count($effects) == 1, 'Got an array with effects for image.style.large data'); $uuid = key($effects->getValue()); - $effect = $effects[$uuid]; - $this->assertTrue(count($effect['data']) && $effect['id']->getValue() == 'image_scale', 'Got data for the image scale effect from metadata.'); - $this->assertTrue($effect['data']['width'] instanceof IntegerInterface, '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.' ); + $effect = $effects->get($uuid)->getElements(); + $this->assertTrue(!$effect['data']->isEmpty() && $effect['id']->getValue() == 'image_scale', 'Got data for the image scale effect from metadata.'); + $this->assertTrue($effect['data']->get('width') instanceof IntegerInterface, 'Got the right type for the scale effect width.'); + $this->assertEqual($effect['data']->get('width')->getValue(), 480, 'Got the right value for the scale effect width.' ); // Finally update some object using a configuration wrapper. $new_slogan = 'Site slogan for testing configuration metadata'; @@ -409,7 +411,7 @@ function testSchemaFallback() { * @see \Drupal\Core\Config\TypedConfigManager::getFallbackName() */ function testColonsInSchemaTypeDetermination() { - $tests = \Drupal::service('config.typed')->get('config_schema_test.plugin_types')->get('tests'); + $tests = \Drupal::service('config.typed')->get('config_schema_test.plugin_types')->get('tests')->getElements(); $definition = $tests[0]->getDataDefinition()->toArray(); $this->assertEqual($definition['type'], 'test.plugin_types.boolean'); @@ -422,17 +424,17 @@ function testColonsInSchemaTypeDetermination() { $definition = $tests[3]->getDataDefinition()->toArray(); $this->assertEqual($definition['type'], 'test.plugin_types.*'); - $tests = \Drupal::service('config.typed')->get('config_schema_test.plugin_types')->get('test_with_parents'); - $definition = $tests[0]['settings']->getDataDefinition()->toArray(); + $tests = \Drupal::service('config.typed')->get('config_schema_test.plugin_types')->get('test_with_parents')->getElements(); + $definition = $tests[0]->get('settings')->getDataDefinition()->toArray(); $this->assertEqual($definition['type'], 'test_with_parents.plugin_types.boolean'); - $definition = $tests[1]['settings']->getDataDefinition()->toArray(); + $definition = $tests[1]->get('settings')->getDataDefinition()->toArray(); $this->assertEqual($definition['type'], 'test_with_parents.plugin_types.boolean:*'); - $definition = $tests[2]['settings']->getDataDefinition()->toArray(); + $definition = $tests[2]->get('settings')->getDataDefinition()->toArray(); $this->assertEqual($definition['type'], 'test_with_parents.plugin_types.*'); - $definition = $tests[3]['settings']->getDataDefinition()->toArray(); + $definition = $tests[3]->get('settings')->getDataDefinition()->toArray(); $this->assertEqual($definition['type'], 'test_with_parents.plugin_types.*'); } diff --git a/core/modules/locale/src/LocaleTypedConfig.php b/core/modules/locale/src/LocaleTypedConfig.php index ee0b470..3332cbe 100644 --- a/core/modules/locale/src/LocaleTypedConfig.php +++ b/core/modules/locale/src/LocaleTypedConfig.php @@ -9,15 +9,15 @@ use Drupal\Core\TypedData\ContextAwareInterface; use Drupal\Core\TypedData\DataDefinitionInterface; -use Drupal\Core\Config\Schema\Element; use Drupal\Core\Config\TypedConfigManagerInterface; use Drupal\Core\TypedData\TraversableTypedDataInterface; +use Drupal\Core\TypedData\TypedData; use Drupal\Core\TypedData\TypedDataInterface; /** * Defines the locale configuration wrapper object. */ -class LocaleTypedConfig extends Element { +class LocaleTypedConfig extends TypedData { /** * The typed configuration data. diff --git a/core/modules/locale/src/Tests/LocaleConfigTranslationTest.php b/core/modules/locale/src/Tests/LocaleConfigTranslationTest.php index ed3104b..27f120d 100644 --- a/core/modules/locale/src/Tests/LocaleConfigTranslationTest.php +++ b/core/modules/locale/src/Tests/LocaleConfigTranslationTest.php @@ -83,7 +83,7 @@ public function testConfigTranslation() { // Get translation and check we've only got the site name. $translation = $wrapper->getTranslation($langcode); - $properties = $translation->getProperties(); + $properties = $translation->getElements(); $this->assertEqual(count($properties), 1, 'Got the right number of properties after translation'); // Check the translated site name is displayed. diff --git a/core/modules/system/src/Tests/Entity/EntityFieldTest.php b/core/modules/system/src/Tests/Entity/EntityFieldTest.php index fdc66e6..4e7a241 100644 --- a/core/modules/system/src/Tests/Entity/EntityFieldTest.php +++ b/core/modules/system/src/Tests/Entity/EntityFieldTest.php @@ -14,6 +14,7 @@ use Drupal\Core\Field\FieldItemInterface; use Drupal\Core\TypedData\ComplexDataDefinitionInterface; use Drupal\Core\TypedData\DataDefinitionInterface; +use Drupal\Core\TypedData\TraversableTypedDataInterface; use Drupal\Core\TypedData\Type\StringInterface; use Drupal\Core\TypedData\TypedDataInterface; use Drupal\node\Entity\NodeType; @@ -564,12 +565,7 @@ public function getContainedStrings(TypedDataInterface $wrapper, $depth, array & // Recurse until a certain depth is reached if possible. if ($depth < 7) { - if ($wrapper instanceof \Drupal\Core\TypedData\ListInterface) { - foreach ($wrapper as $item) { - $this->getContainedStrings($item, $depth + 1, $strings); - } - } - elseif ($wrapper instanceof \Drupal\Core\TypedData\ComplexDataInterface) { + if ($wrapper instanceof TraversableTypedDataInterface) { foreach ($wrapper as $property) { $this->getContainedStrings($property, $depth + 1, $strings); } diff --git a/core/modules/system/src/Tests/TypedData/TypedDataTest.php b/core/modules/system/src/Tests/TypedData/TypedDataTest.php index 99032f4..8ae1d99 100644 --- a/core/modules/system/src/Tests/TypedData/TypedDataTest.php +++ b/core/modules/system/src/Tests/TypedData/TypedDataTest.php @@ -476,14 +476,14 @@ public function testTypedDataMaps() { 'three' => 'drei' )); - $properties = $typed_data->getProperties(); + $properties = $typed_data->getElements(); $this->assertEqual(array_keys($properties), array_keys($value)); $this->assertIdentical($properties['one'], $typed_data->get('one'), 'Properties are identical.'); // Test setting a not defined property. It shouldn't show up in the // properties, but be kept in the values. $typed_data->setValue(array('foo' => 'bar')); - $this->assertEqual(array_keys($typed_data->getProperties()), array('one', 'two', 'three')); + $this->assertEqual(array_keys($typed_data->getElements()), array('one', 'two', 'three')); $this->assertEqual(array_keys($typed_data->getValue()), array('foo', 'one', 'two', 'three')); // Test getting the string representation. diff --git a/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageTest.php b/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageTest.php index e90d145..3e103b3 100644 --- a/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageTest.php +++ b/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageTest.php @@ -973,7 +973,7 @@ public function testCreate() { ->will($this->returnValue(array('id' => 'id'))); // ContentEntityStorageBase iterates over the entity which calls this method - // internally in ContentEntityBase::getProperties(). + // internally in ContentEntityBase::getElements(). $this->entityManager->expects($this->once()) ->method('getFieldDefinitions') ->will($this->returnValue(array())); diff --git a/core/tests/Drupal/Tests/Core/Entity/TypedData/EntityAdapterUnitTest.php b/core/tests/Drupal/Tests/Core/Entity/TypedData/EntityAdapterUnitTest.php index 0628c89..2d5cbb5 100644 --- a/core/tests/Drupal/Tests/Core/Entity/TypedData/EntityAdapterUnitTest.php +++ b/core/tests/Drupal/Tests/Core/Entity/TypedData/EntityAdapterUnitTest.php @@ -322,10 +322,10 @@ public function testSetWithoutData() { } /** - * @covers ::getProperties + * @covers ::getElements */ - public function testGetProperties() { - $fields = $this->entityAdapter->getProperties(); + public function testGetElements() { + $fields = $this->entityAdapter->getElements(); $this->assertInstanceOf('Drupal\Core\Field\FieldItemListInterface', $fields['id']); $this->assertInstanceOf('Drupal\Core\Field\FieldItemListInterface', $fields['revision_id']); }