Skip to content
Snippets Groups Projects
Commit 221a48c1 authored by Alex Pott's avatar Alex Pott
Browse files

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
No related branches found
No related tags found
2 merge requests!7452Issue #1797438. HTML5 validation is preventing form submit and not fully...,!789Issue #3210310: Adjust Database API to remove deprecated Drupal 9 code in Drupal 10
Showing
with 53 additions and 41 deletions
......@@ -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());
}
}
......@@ -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).';
}
......
......@@ -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
......
......@@ -23,7 +23,7 @@
*
* @ingroup typed_data
*/
interface ComplexDataInterface extends \Traversable, TypedDataInterface {
interface ComplexDataInterface extends TraversableTypedDataInterface {
/**
* Gets a property object.
......
......@@ -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.
......
<?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
/**
* 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;
}
......
......@@ -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);
}
......@@ -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;
......
......@@ -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();
......
......@@ -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();
......
......@@ -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());
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment