diff --git a/core/lib/Drupal/Core/Config/Schema/ArrayElement.php b/core/lib/Drupal/Core/Config/Schema/ArrayElement.php index f801c28724bb94378a46955a8a5e307094df7874..8becdd7f0fff7b409806324b000cdafd870be741 100644 --- a/core/lib/Drupal/Core/Config/Schema/ArrayElement.php +++ b/core/lib/Drupal/Core/Config/Schema/ArrayElement.php @@ -6,17 +6,12 @@ */ namespace Drupal\Core\Config\Schema; - -use \ArrayAccess; -use \ArrayIterator; -use \Countable; -use \IteratorAggregate; -use \Traversable; +use Drupal\Core\TypedData\TraversableTypedDataInterface; /** * Defines a generic configuration element that contains multiple properties. */ -abstract class ArrayElement extends Element implements IteratorAggregate, ArrayAccess, Countable { +abstract class ArrayElement extends Element implements \IteratorAggregate, TraversableTypedDataInterface, \ArrayAccess, \Countable { /** * Parsed elements. @@ -26,8 +21,8 @@ abstract class ArrayElement extends Element implements IteratorAggregate, ArrayA /** * Gets an array of contained elements. * - * @return array - * Array of \Drupal\Core\Config\Schema\ArrayElement objects. + * @return \Drupal\Core\TypedData\TypedDataInterface[] + * An array of elements contained in this element. */ protected function getElements() { if (!isset($this->elements)) { @@ -49,8 +44,8 @@ protected function getAllKeys() { /** * Builds an array of contained elements. * - * @return array - * Array of \Drupal\Core\Config\Schema\ArrayElement objects. + * @return \Drupal\Core\TypedData\TypedDataInterface[] + * An array of elements contained in this element. */ protected abstract function parse(); @@ -111,7 +106,7 @@ public function count() { * Implements IteratorAggregate::getIterator(); */ public function getIterator() { - return new ArrayIterator($this->getElements()); + return new \ArrayIterator($this->getElements()); } } diff --git a/core/lib/Drupal/Core/Config/Schema/SchemaCheckTrait.php b/core/lib/Drupal/Core/Config/Schema/SchemaCheckTrait.php index 4d2bd11658ad8c25bc5a455131859baec99afdc7..0fccd471564f419430f530ad2a35ed2b91ed0bd6 100644 --- a/core/lib/Drupal/Core/Config/Schema/SchemaCheckTrait.php +++ b/core/lib/Drupal/Core/Config/Schema/SchemaCheckTrait.php @@ -9,6 +9,7 @@ use Drupal\Core\Config\TypedConfigManagerInterface; use Drupal\Core\TypedData\PrimitiveInterface; +use Drupal\Core\TypedData\TraversableTypedDataInterface; use Drupal\Core\TypedData\Type\BooleanInterface; use Drupal\Core\TypedData\Type\StringInterface; use Drupal\Core\TypedData\Type\FloatInterface; @@ -108,7 +109,7 @@ protected function checkValue($key, $value) { } else { $errors = array(); - if (!$element instanceof ArrayElement) { + if (!$element instanceof TraversableTypedDataInterface) { $errors[$error_key] = 'Non-scalar value but not defined as an array (such as mapping or sequence).'; } diff --git a/core/lib/Drupal/Core/Config/Schema/Sequence.php b/core/lib/Drupal/Core/Config/Schema/Sequence.php index e5b6a356ed33ae06d6e93e1bfc9adb932b79530f..630bb50d1b9beef1b239eed681f76243c73afbf5 100644 --- a/core/lib/Drupal/Core/Config/Schema/Sequence.php +++ b/core/lib/Drupal/Core/Config/Schema/Sequence.php @@ -22,7 +22,7 @@ class Sequence extends ArrayElement implements ListInterface { protected $itemDefinition; /** - * Overrides ArrayElement::parse() + * {@inheritdoc} */ protected function parse() { // Creates a new data definition object for each item from the generic type diff --git a/core/lib/Drupal/Core/TypedData/ComplexDataInterface.php b/core/lib/Drupal/Core/TypedData/ComplexDataInterface.php index 1397485f92cacfc9fb2dfdf7f44c85cdd8dd7a24..0a5b38a5ceb64037a1aa651e95c8927b2dc24314 100644 --- a/core/lib/Drupal/Core/TypedData/ComplexDataInterface.php +++ b/core/lib/Drupal/Core/TypedData/ComplexDataInterface.php @@ -23,7 +23,7 @@ * * @ingroup typed_data */ -interface ComplexDataInterface extends \Traversable, TypedDataInterface { +interface ComplexDataInterface extends TraversableTypedDataInterface { /** * Gets a property object. diff --git a/core/lib/Drupal/Core/TypedData/ListInterface.php b/core/lib/Drupal/Core/TypedData/ListInterface.php index ce59dfb35afb5cc3bdc19f88220e9a3f6bdea3fe..2c5dbc7f6f05cfced59ef36f6fb58b03c830e175 100644 --- a/core/lib/Drupal/Core/TypedData/ListInterface.php +++ b/core/lib/Drupal/Core/TypedData/ListInterface.php @@ -20,7 +20,7 @@ * * @ingroup typed_data */ -interface ListInterface extends TypedDataInterface, \ArrayAccess, \Countable, \Traversable { +interface ListInterface extends TraversableTypedDataInterface, \ArrayAccess, \Countable { /** * Determines whether the list contains any non-empty items. diff --git a/core/lib/Drupal/Core/TypedData/TraversableTypedDataInterface.php b/core/lib/Drupal/Core/TypedData/TraversableTypedDataInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..d42557ee752d78e97f0351bf10564accd81c6a27 --- /dev/null +++ b/core/lib/Drupal/Core/TypedData/TraversableTypedDataInterface.php @@ -0,0 +1,13 @@ +<?php + +/** + * @file + * Contains \Drupal\Core\TypedData\TraversableTypedDataInterface. + */ + +namespace Drupal\Core\TypedData; + +/** + * An interface for typed data objects that can be traversed. + */ +interface TraversableTypedDataInterface extends TypedDataInterface, \Traversable {} diff --git a/core/lib/Drupal/Core/TypedData/TypedData.php b/core/lib/Drupal/Core/TypedData/TypedData.php index b0f614c4b075d3b094e041cf704e94f7038f95e4..3216d21668883699da45f674022819ebdae5f4d2 100644 --- a/core/lib/Drupal/Core/TypedData/TypedData.php +++ b/core/lib/Drupal/Core/TypedData/TypedData.php @@ -39,14 +39,14 @@ abstract class TypedData implements TypedDataInterface, PluginInspectionInterfac /** * The parent typed data object. * - * @var \Drupal\Core\TypedData\TypedDataInterface + * @var \Drupal\Core\TypedData\TraversableTypedDataInterface|null */ protected $parent; /** * {@inheritdoc} */ - public static function createInstance($definition, $name = NULL, TypedDataInterface $parent = NULL) { + public static function createInstance($definition, $name = NULL, TraversableTypedDataInterface $parent = NULL) { return new static($definition, $name, $parent); } @@ -153,7 +153,7 @@ public function applyDefaultValue($notify = TRUE) { /** * {@inheritdoc} */ - public function setContext($name = NULL, TypedDataInterface $parent = NULL) { + public function setContext($name = NULL, TraversableTypedDataInterface $parent = NULL) { $this->parent = $parent; $this->name = $name; } diff --git a/core/lib/Drupal/Core/TypedData/TypedDataInterface.php b/core/lib/Drupal/Core/TypedData/TypedDataInterface.php index 74d083fe567e2b01d046d03d9b223766404fd223..7b038e51c19d71eca8efcd6d41c56edcb7b26faa 100644 --- a/core/lib/Drupal/Core/TypedData/TypedDataInterface.php +++ b/core/lib/Drupal/Core/TypedData/TypedDataInterface.php @@ -26,7 +26,7 @@ interface TypedDataInterface { * @param string|null $name * (optional) The name of the created property, or NULL if it is the root * of a typed data tree. Defaults to NULL. - * @param \Drupal\Core\TypedData\TypedDataInterface $parent + * @param \Drupal\Core\TypedData\TraversableTypedDataInterface $parent * (optional) The parent object of the data property, or NULL if it is the * root of a typed data tree. Defaults to NULL. * @@ -36,7 +36,7 @@ interface TypedDataInterface { * * @see \Drupal\Core\TypedData\TypedDataManager::create() */ - public static function createInstance($definition, $name = NULL, TypedDataInterface $parent = NULL); + public static function createInstance($definition, $name = NULL, TraversableTypedDataInterface $parent = NULL); /** * Gets the data definition. @@ -122,7 +122,7 @@ 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 + * @return \Drupal\Core\TypedData\TraversableTypedDataInterface|null * The parent data structure, either complex data or a list; or NULL if this * is the root of the typed data tree. */ @@ -134,7 +134,7 @@ public function getParent(); * 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 + * @return \Drupal\Core\TypedData\TraversableTypedDataInterface * The root data structure, either complex data or a list. */ public function getRoot(); @@ -159,9 +159,9 @@ public function getPropertyPath(); * @param string|null $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|null $parent + * @param \Drupal\Core\TypedData\TraversableTypedDataInterface|null $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); + public function setContext($name = NULL, TraversableTypedDataInterface $parent = NULL); } diff --git a/core/modules/config_translation/src/ConfigMapperManager.php b/core/modules/config_translation/src/ConfigMapperManager.php index 9a0b46e413daf12d86d9b68cfdc9b95ffc096ecf..09b64986ec3c84154dcdaf1cb525ceb46a189545 100644 --- a/core/modules/config_translation/src/ConfigMapperManager.php +++ b/core/modules/config_translation/src/ConfigMapperManager.php @@ -10,7 +10,6 @@ use Drupal\Component\Utility\String; use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException; use Drupal\Core\Cache\CacheBackendInterface; -use Drupal\Core\Config\Schema\ArrayElement; use Drupal\Core\Config\TypedConfigManagerInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Extension\ThemeHandlerInterface; @@ -20,6 +19,7 @@ use Drupal\Core\Plugin\Discovery\YamlDiscovery; use Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator; use Drupal\Core\Plugin\Factory\ContainerFactory; +use Drupal\Core\TypedData\TraversableTypedDataInterface; use Drupal\Core\TypedData\TypedDataInterface; use Symfony\Component\Routing\RouteCollection; @@ -176,7 +176,7 @@ public function hasTranslatable($name) { protected function findTranslatable(TypedDataInterface $element) { // In case this is a sequence or a mapping check whether any child element // is translatable. - if ($element instanceof ArrayElement) { + if ($element instanceof TraversableTypedDataInterface) { foreach ($element as $child_element) { if ($this->findTranslatable($child_element)) { return TRUE; diff --git a/core/modules/config_translation/tests/src/Unit/ConfigMapperManagerTest.php b/core/modules/config_translation/tests/src/Unit/ConfigMapperManagerTest.php index c28b663a4b8997c82a947c8e90bdcc9449b7398c..cdf89b5a50f2a137d74fb4508af63c68531eeebd 100644 --- a/core/modules/config_translation/tests/src/Unit/ConfigMapperManagerTest.php +++ b/core/modules/config_translation/tests/src/Unit/ConfigMapperManagerTest.php @@ -170,9 +170,12 @@ protected function getElement(array $definition) { * A nested schema element, containing the passed-in elements. */ protected function getNestedElement(array $elements) { - // ConfigMapperManager::findTranslatable() checks for the abstract class - // \Drupal\Core\Config\Schema\ArrayElement, but mocking that directly does - // not work. + // ConfigMapperManager::findTranslatable() checks for + // \Drupal\Core\TypedData\TraversableTypedDataInterface, but mocking that + // directly does not work, because we need to implement \IteratorAggregate + // in order for getIterator() to be called. Therefore we need to mock + // \Drupal\Core\Config\Schema\ArrayElement, but that is abstract, so we + // need to mock one of the subclasses of it. $nested_element = $this->getMockBuilder('Drupal\Core\Config\Schema\Mapping') ->disableOriginalConstructor() ->getMock(); diff --git a/core/modules/locale/src/LocaleTypedConfig.php b/core/modules/locale/src/LocaleTypedConfig.php index ab373fe85f9a4216d476ba0e06dfaad717656172..ee0b470e81d9dbccf6eef6894a28360635341192 100644 --- a/core/modules/locale/src/LocaleTypedConfig.php +++ b/core/modules/locale/src/LocaleTypedConfig.php @@ -10,8 +10,9 @@ use Drupal\Core\TypedData\ContextAwareInterface; use Drupal\Core\TypedData\DataDefinitionInterface; use Drupal\Core\Config\Schema\Element; -use Drupal\Core\Config\Schema\ArrayElement; use Drupal\Core\Config\TypedConfigManagerInterface; +use Drupal\Core\TypedData\TraversableTypedDataInterface; +use Drupal\Core\TypedData\TypedDataInterface; /** * Defines the locale configuration wrapper object. @@ -114,9 +115,8 @@ protected function canTranslate($from_langcode, $to_langcode) { /** * Gets translated configuration data for a typed configuration element. * - * @param mixed $element - * Typed configuration element, either \Drupal\Core\Config\Schema\Element or - * \Drupal\Core\Config\Schema\ArrayElement. + * @param \Drupal\Core\TypedData\TypedDataInterface $element + * Typed configuration element. * @param array $options * Array with translation options that must contain the keys defined in * \Drupal\locale\LocaleTypedConfig::translateElement(). @@ -125,9 +125,9 @@ protected function canTranslate($from_langcode, $to_langcode) { * Configuration data translated to the requested language if available, * an empty array otherwise. */ - protected function getElementTranslation($element, array $options) { + protected function getElementTranslation(TypedDataInterface $element, array $options) { $translation = array(); - if ($element instanceof ArrayElement) { + if ($element instanceof TraversableTypedDataInterface) { $translation = $this->getArrayTranslation($element, $options); } elseif ($this->translateElement($element, $options)) { @@ -137,9 +137,9 @@ protected function getElementTranslation($element, array $options) { } /** - * Gets translated configuration data for an element of type ArrayElement. + * Gets translated configuration data for a traversable element. * - * @param \Drupal\Core\Config\Schema\ArrayElement $element + * @param \Drupal\Core\TypedData\TraversableTypedDataInterface $element * Typed configuration array element. * @param array $options * Array with translation options that must contain the keys defined in @@ -148,7 +148,7 @@ protected function getElementTranslation($element, array $options) { * @return array * Configuration data translated to the requested language. */ - protected function getArrayTranslation(ArrayElement $element, array $options) { + protected function getArrayTranslation(TraversableTypedDataInterface $element, array $options) { $translation = array(); foreach ($element as $key => $property) { $value = $this->getElementTranslation($property, $options); @@ -179,7 +179,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(TypedDataInterface $element, array $options) { if ($this->canTranslate($options['source'], $options['target'])) { $definition = $element->getDataDefinition(); $value = $element->getValue(); diff --git a/core/tests/Drupal/Tests/Core/Entity/TypedData/EntityAdapterUnitTest.php b/core/tests/Drupal/Tests/Core/Entity/TypedData/EntityAdapterUnitTest.php index 5556c6edd0d7b0ae04b6a68a86514d5239900e02..0628c89945a32758b38101d03a6f933e101bedf7 100644 --- a/core/tests/Drupal/Tests/Core/Entity/TypedData/EntityAdapterUnitTest.php +++ b/core/tests/Drupal/Tests/Core/Entity/TypedData/EntityAdapterUnitTest.php @@ -252,7 +252,7 @@ public function testGetParent() { */ public function testSetContext() { $name = $this->randomMachineName(); - $parent = $this->getMock('\Drupal\Core\TypedData\TypedDataInterface'); + $parent = $this->getMock('\Drupal\Core\TypedData\TraversableTypedDataInterface'); // Our mocked entity->setContext() returns NULL, so assert that. $this->assertNull($this->entityAdapter->setContext($name, $parent)); $this->assertEquals($name, $this->entityAdapter->getName());