Commit 221a48c1 authored by alexpott's avatar alexpott

Issue #2346129 by tstoeckler: Introduce a TraversableTypedDataInterface and...

Issue #2346129 by tstoeckler: Introduce a TraversableTypedDataInterface and use that for typehinting instead of ArrayElement.
parent b82e28d5
...@@ -6,17 +6,12 @@ ...@@ -6,17 +6,12 @@
*/ */
namespace Drupal\Core\Config\Schema; namespace Drupal\Core\Config\Schema;
use Drupal\Core\TypedData\TraversableTypedDataInterface;
use \ArrayAccess;
use \ArrayIterator;
use \Countable;
use \IteratorAggregate;
use \Traversable;
/** /**
* Defines a generic configuration element that contains multiple properties. * 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. * Parsed elements.
...@@ -26,8 +21,8 @@ abstract class ArrayElement extends Element implements IteratorAggregate, ArrayA ...@@ -26,8 +21,8 @@ abstract class ArrayElement extends Element implements IteratorAggregate, ArrayA
/** /**
* Gets an array of contained elements. * Gets an array of contained elements.
* *
* @return array * @return \Drupal\Core\TypedData\TypedDataInterface[]
* Array of \Drupal\Core\Config\Schema\ArrayElement objects. * An array of elements contained in this element.
*/ */
protected function getElements() { protected function getElements() {
if (!isset($this->elements)) { if (!isset($this->elements)) {
...@@ -49,8 +44,8 @@ protected function getAllKeys() { ...@@ -49,8 +44,8 @@ protected function getAllKeys() {
/** /**
* Builds an array of contained elements. * Builds an array of contained elements.
* *
* @return array * @return \Drupal\Core\TypedData\TypedDataInterface[]
* Array of \Drupal\Core\Config\Schema\ArrayElement objects. * An array of elements contained in this element.
*/ */
protected abstract function parse(); protected abstract function parse();
...@@ -111,7 +106,7 @@ public function count() { ...@@ -111,7 +106,7 @@ public function count() {
* Implements IteratorAggregate::getIterator(); * Implements IteratorAggregate::getIterator();
*/ */
public function getIterator() { public function getIterator() {
return new ArrayIterator($this->getElements()); return new \ArrayIterator($this->getElements());
} }
} }
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
use Drupal\Core\Config\TypedConfigManagerInterface; use Drupal\Core\Config\TypedConfigManagerInterface;
use Drupal\Core\TypedData\PrimitiveInterface; use Drupal\Core\TypedData\PrimitiveInterface;
use Drupal\Core\TypedData\TraversableTypedDataInterface;
use Drupal\Core\TypedData\Type\BooleanInterface; use Drupal\Core\TypedData\Type\BooleanInterface;
use Drupal\Core\TypedData\Type\StringInterface; use Drupal\Core\TypedData\Type\StringInterface;
use Drupal\Core\TypedData\Type\FloatInterface; use Drupal\Core\TypedData\Type\FloatInterface;
...@@ -108,7 +109,7 @@ protected function checkValue($key, $value) { ...@@ -108,7 +109,7 @@ protected function checkValue($key, $value) {
} }
else { else {
$errors = array(); $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).'; $errors[$error_key] = 'Non-scalar value but not defined as an array (such as mapping or sequence).';
} }
......
...@@ -22,7 +22,7 @@ class Sequence extends ArrayElement implements ListInterface { ...@@ -22,7 +22,7 @@ class Sequence extends ArrayElement implements ListInterface {
protected $itemDefinition; protected $itemDefinition;
/** /**
* Overrides ArrayElement::parse() * {@inheritdoc}
*/ */
protected function parse() { protected function parse() {
// Creates a new data definition object for each item from the generic type // Creates a new data definition object for each item from the generic type
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
* *
* @ingroup typed_data * @ingroup typed_data
*/ */
interface ComplexDataInterface extends \Traversable, TypedDataInterface { interface ComplexDataInterface extends TraversableTypedDataInterface {
/** /**
* Gets a property object. * Gets a property object.
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
* *
* @ingroup typed_data * @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. * Determines whether the list contains any non-empty items.
......
<?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 {}
...@@ -39,14 +39,14 @@ abstract class TypedData implements TypedDataInterface, PluginInspectionInterfac ...@@ -39,14 +39,14 @@ abstract class TypedData implements TypedDataInterface, PluginInspectionInterfac
/** /**
* The parent typed data object. * The parent typed data object.
* *
* @var \Drupal\Core\TypedData\TypedDataInterface * @var \Drupal\Core\TypedData\TraversableTypedDataInterface|null
*/ */
protected $parent; protected $parent;
/** /**
* {@inheritdoc} * {@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); return new static($definition, $name, $parent);
} }
...@@ -153,7 +153,7 @@ public function applyDefaultValue($notify = TRUE) { ...@@ -153,7 +153,7 @@ public function applyDefaultValue($notify = TRUE) {
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function setContext($name = NULL, TypedDataInterface $parent = NULL) { public function setContext($name = NULL, TraversableTypedDataInterface $parent = NULL) {
$this->parent = $parent; $this->parent = $parent;
$this->name = $name; $this->name = $name;
} }
......
...@@ -26,7 +26,7 @@ interface TypedDataInterface { ...@@ -26,7 +26,7 @@ interface TypedDataInterface {
* @param string|null $name * @param string|null $name
* (optional) The name of the created property, or NULL if it is the root * (optional) The name of the created property, or NULL if it is the root
* of a typed data tree. Defaults to NULL. * 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 * (optional) The parent object of the data property, or NULL if it is the
* root of a typed data tree. Defaults to NULL. * root of a typed data tree. Defaults to NULL.
* *
...@@ -36,7 +36,7 @@ interface TypedDataInterface { ...@@ -36,7 +36,7 @@ interface TypedDataInterface {
* *
* @see \Drupal\Core\TypedData\TypedDataManager::create() * @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. * Gets the data definition.
...@@ -122,7 +122,7 @@ public function getName(); ...@@ -122,7 +122,7 @@ public function getName();
/** /**
* Returns the parent data structure; i.e. either complex data or a list. * 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 * The parent data structure, either complex data or a list; or NULL if this
* is the root of the typed data tree. * is the root of the typed data tree.
*/ */
...@@ -134,7 +134,7 @@ public function getParent(); ...@@ -134,7 +134,7 @@ public function getParent();
* Returns the root data for a tree of typed data objects; e.g. for an entity * 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. * 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. * The root data structure, either complex data or a list.
*/ */
public function getRoot(); public function getRoot();
...@@ -159,9 +159,9 @@ public function getPropertyPath(); ...@@ -159,9 +159,9 @@ public function getPropertyPath();
* @param string|null $name * @param string|null $name
* (optional) The name of the property or the delta of the list item, * (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. * 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 * (optional) The parent object of the data property, or NULL if it is the
* root of a typed data tree. Defaults to NULL. * 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);
} }
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
use Drupal\Component\Utility\String; use Drupal\Component\Utility\String;
use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException; use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Config\Schema\ArrayElement;
use Drupal\Core\Config\TypedConfigManagerInterface; use Drupal\Core\Config\TypedConfigManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Extension\ThemeHandlerInterface; use Drupal\Core\Extension\ThemeHandlerInterface;
...@@ -20,6 +19,7 @@ ...@@ -20,6 +19,7 @@
use Drupal\Core\Plugin\Discovery\YamlDiscovery; use Drupal\Core\Plugin\Discovery\YamlDiscovery;
use Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator; use Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator;
use Drupal\Core\Plugin\Factory\ContainerFactory; use Drupal\Core\Plugin\Factory\ContainerFactory;
use Drupal\Core\TypedData\TraversableTypedDataInterface;
use Drupal\Core\TypedData\TypedDataInterface; use Drupal\Core\TypedData\TypedDataInterface;
use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\RouteCollection;
...@@ -176,7 +176,7 @@ public function hasTranslatable($name) { ...@@ -176,7 +176,7 @@ public function hasTranslatable($name) {
protected function findTranslatable(TypedDataInterface $element) { protected function findTranslatable(TypedDataInterface $element) {
// In case this is a sequence or a mapping check whether any child element // In case this is a sequence or a mapping check whether any child element
// is translatable. // is translatable.
if ($element instanceof ArrayElement) { if ($element instanceof TraversableTypedDataInterface) {
foreach ($element as $child_element) { foreach ($element as $child_element) {
if ($this->findTranslatable($child_element)) { if ($this->findTranslatable($child_element)) {
return TRUE; return TRUE;
......
...@@ -170,9 +170,12 @@ protected function getElement(array $definition) { ...@@ -170,9 +170,12 @@ protected function getElement(array $definition) {
* A nested schema element, containing the passed-in elements. * A nested schema element, containing the passed-in elements.
*/ */
protected function getNestedElement(array $elements) { protected function getNestedElement(array $elements) {
// ConfigMapperManager::findTranslatable() checks for the abstract class // ConfigMapperManager::findTranslatable() checks for
// \Drupal\Core\Config\Schema\ArrayElement, but mocking that directly does // \Drupal\Core\TypedData\TraversableTypedDataInterface, but mocking that
// not work. // 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') $nested_element = $this->getMockBuilder('Drupal\Core\Config\Schema\Mapping')
->disableOriginalConstructor() ->disableOriginalConstructor()
->getMock(); ->getMock();
......
...@@ -10,8 +10,9 @@ ...@@ -10,8 +10,9 @@
use Drupal\Core\TypedData\ContextAwareInterface; use Drupal\Core\TypedData\ContextAwareInterface;
use Drupal\Core\TypedData\DataDefinitionInterface; use Drupal\Core\TypedData\DataDefinitionInterface;
use Drupal\Core\Config\Schema\Element; use Drupal\Core\Config\Schema\Element;
use Drupal\Core\Config\Schema\ArrayElement;
use Drupal\Core\Config\TypedConfigManagerInterface; use Drupal\Core\Config\TypedConfigManagerInterface;
use Drupal\Core\TypedData\TraversableTypedDataInterface;
use Drupal\Core\TypedData\TypedDataInterface;
/** /**
* Defines the locale configuration wrapper object. * Defines the locale configuration wrapper object.
...@@ -114,9 +115,8 @@ protected function canTranslate($from_langcode, $to_langcode) { ...@@ -114,9 +115,8 @@ protected function canTranslate($from_langcode, $to_langcode) {
/** /**
* Gets translated configuration data for a typed configuration element. * Gets translated configuration data for a typed configuration element.
* *
* @param mixed $element * @param \Drupal\Core\TypedData\TypedDataInterface $element
* Typed configuration element, either \Drupal\Core\Config\Schema\Element or * Typed configuration element.
* \Drupal\Core\Config\Schema\ArrayElement.
* @param array $options * @param array $options
* Array with translation options that must contain the keys defined in * Array with translation options that must contain the keys defined in
* \Drupal\locale\LocaleTypedConfig::translateElement(). * \Drupal\locale\LocaleTypedConfig::translateElement().
...@@ -125,9 +125,9 @@ protected function canTranslate($from_langcode, $to_langcode) { ...@@ -125,9 +125,9 @@ protected function canTranslate($from_langcode, $to_langcode) {
* Configuration data translated to the requested language if available, * Configuration data translated to the requested language if available,
* an empty array otherwise. * an empty array otherwise.
*/ */
protected function getElementTranslation($element, array $options) { protected function getElementTranslation(TypedDataInterface $element, array $options) {
$translation = array(); $translation = array();
if ($element instanceof ArrayElement) { if ($element instanceof TraversableTypedDataInterface) {
$translation = $this->getArrayTranslation($element, $options); $translation = $this->getArrayTranslation($element, $options);
} }
elseif ($this->translateElement($element, $options)) { elseif ($this->translateElement($element, $options)) {
...@@ -137,9 +137,9 @@ protected function getElementTranslation($element, array $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. * Typed configuration array element.
* @param array $options * @param array $options
* Array with translation options that must contain the keys defined in * Array with translation options that must contain the keys defined in
...@@ -148,7 +148,7 @@ protected function getElementTranslation($element, array $options) { ...@@ -148,7 +148,7 @@ protected function getElementTranslation($element, array $options) {
* @return array * @return array
* Configuration data translated to the requested language. * Configuration data translated to the requested language.
*/ */
protected function getArrayTranslation(ArrayElement $element, array $options) { protected function getArrayTranslation(TraversableTypedDataInterface $element, array $options) {
$translation = array(); $translation = array();
foreach ($element as $key => $property) { foreach ($element as $key => $property) {
$value = $this->getElementTranslation($property, $options); $value = $this->getElementTranslation($property, $options);
...@@ -179,7 +179,7 @@ protected function getArrayTranslation(ArrayElement $element, array $options) { ...@@ -179,7 +179,7 @@ protected function getArrayTranslation(ArrayElement $element, array $options) {
* @return bool * @return bool
* Whether the element fits the translation criteria. * 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'])) { if ($this->canTranslate($options['source'], $options['target'])) {
$definition = $element->getDataDefinition(); $definition = $element->getDataDefinition();
$value = $element->getValue(); $value = $element->getValue();
......
...@@ -252,7 +252,7 @@ public function testGetParent() { ...@@ -252,7 +252,7 @@ public function testGetParent() {
*/ */
public function testSetContext() { public function testSetContext() {
$name = $this->randomMachineName(); $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. // Our mocked entity->setContext() returns NULL, so assert that.
$this->assertNull($this->entityAdapter->setContext($name, $parent)); $this->assertNull($this->entityAdapter->setContext($name, $parent));
$this->assertEquals($name, $this->entityAdapter->getName()); $this->assertEquals($name, $this->entityAdapter->getName());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment