diff --git a/core/lib/Drupal/Core/Config/Schema/ArrayElement.php b/core/lib/Drupal/Core/Config/Schema/ArrayElement.php index f801c28..c8b1a06 100644 --- a/core/lib/Drupal/Core/Config/Schema/ArrayElement.php +++ b/core/lib/Drupal/Core/Config/Schema/ArrayElement.php @@ -16,7 +16,7 @@ /** * 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, ListElementInterface { /** * Parsed elements. @@ -24,19 +24,6 @@ protected $elements; /** - * Gets an array of contained elements. - * - * @return array - * Array of \Drupal\Core\Config\Schema\ArrayElement objects. - */ - protected function getElements() { - if (!isset($this->elements)) { - $this->elements = $this->parse(); - } - return $this->elements; - } - - /** * Gets valid configuration data keys. * * @return array @@ -55,15 +42,80 @@ protected function getAllKeys() { protected abstract function parse(); /** - * Implements TypedDataInterface::validate(). + * {@inheritdoc} */ - public function validate() { - foreach ($this->getElements() as $element) { - if (!$element->validate()) { - return FALSE; + 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 ($element instanceof ListElementInterface) { + $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' => $property_name))); + } + } + + /** + * {@inheritdoc} + */ + public function set($key, $value) { + // 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; + } + + /** + * {@inheritdoc} + */ + public function getElements() { + if (!isset($this->elements)) { + $this->elements = $this->parse(); + } + return $this->elements; + } + + /** + * {@inheritdoc} + */ + public function isEmpty() { + return empty($this->value); + } + + /** + * {@inheritdoc} + */ + public function toArray() { + return isset($this->value) ? $this->value : array(); + } + + /** + * {@inheritdoc} + */ + public function onChange($key) { + // Notify the parent of changes. + if (isset($this->parent)) { + $this->parent->onChange($this->name); + } } /** @@ -85,11 +137,7 @@ public function offsetGet($offset) { * Implements ArrayAccess::offsetSet(). */ public function offsetSet($offset, $value) { - if ($value instanceof TypedDataInterface) { - $value = $value->getValue(); - } - $this->value[$offset] = $value; - unset($this->elements); + $this->set($offset, $value); } /** diff --git a/core/lib/Drupal/Core/Config/Schema/Ignore.php b/core/lib/Drupal/Core/Config/Schema/Ignore.php index 20701b8..d005302 100644 --- a/core/lib/Drupal/Core/Config/Schema/Ignore.php +++ b/core/lib/Drupal/Core/Config/Schema/Ignore.php @@ -12,10 +12,4 @@ */ class Ignore extends Element { - /** - * {@inheritdoc}. - */ - public function validate() { - return TRUE; - } } diff --git a/core/lib/Drupal/Core/Config/Schema/ListElementInterface.php b/core/lib/Drupal/Core/Config/Schema/ListElementInterface.php new file mode 100644 index 0000000..b6a384f --- /dev/null +++ b/core/lib/Drupal/Core/Config/Schema/ListElementInterface.php @@ -0,0 +1,86 @@ +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))); - } - } + public function set($key, $value) { + parent::set($key, $value); + // We may need to rebuild property definitions. + unset($this->propertyDefinitions); - /** - * 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 $property; - } - - /** - * Implements Drupal\Core\TypedData\ComplexDataInterface::getProperties(). - */ - public function getProperties($include_computed = FALSE) { - return $this->getElements(); - } - - /** - * {@inheritdoc} - */ - public function toArray() { - return $this->getValue(); + return $this; } /** @@ -137,21 +86,4 @@ public function getPropertyDefinitions() { 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); - } - } - } diff --git a/core/lib/Drupal/Core/Config/Schema/SchemaCheckTrait.php b/core/lib/Drupal/Core/Config/Schema/SchemaCheckTrait.php index 0836eaf..d4be93c 100644 --- a/core/lib/Drupal/Core/Config/Schema/SchemaCheckTrait.php +++ b/core/lib/Drupal/Core/Config/Schema/SchemaCheckTrait.php @@ -107,7 +107,7 @@ protected function checkValue($key, $value) { } else { $errors = array(); - if (!$element instanceof ArrayElement) { + if (!$element instanceof ListElementInterface) { $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 e5b6a35..26576ef 100644 --- a/core/lib/Drupal/Core/Config/Schema/Sequence.php +++ b/core/lib/Drupal/Core/Config/Schema/Sequence.php @@ -7,22 +7,19 @@ namespace Drupal\Core\Config\Schema; -use Drupal\Core\TypedData\ListInterface; - /** * 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 { +class Sequence extends ArrayElement { /** - * Data definition - * - * @var \Drupal\Core\TypedData\DataDefinitionInterface - */ - protected $itemDefinition; - - /** - * Overrides ArrayElement::parse() + * {@inheritdoc} */ protected function parse() { // Creates a new data definition object for each item from the generic type @@ -38,55 +35,4 @@ protected function parse() { 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); - } - } - - /** - * {@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; - } - } diff --git a/core/lib/Drupal/Core/Config/Schema/Undefined.php b/core/lib/Drupal/Core/Config/Schema/Undefined.php index 1bcf744..6f62b0d 100644 --- a/core/lib/Drupal/Core/Config/Schema/Undefined.php +++ b/core/lib/Drupal/Core/Config/Schema/Undefined.php @@ -12,10 +12,4 @@ */ class Undefined extends Element { - /** - * {@inheritdoc}. - */ - public function validate() { - return isset($this->value); - } } diff --git a/core/modules/config/src/Tests/ConfigSchemaTest.php b/core/modules/config/src/Tests/ConfigSchemaTest.php index 7401247..fc4f9ae 100644 --- a/core/modules/config/src/Tests/ConfigSchemaTest.php +++ b/core/modules/config/src/Tests/ConfigSchemaTest.php @@ -280,8 +280,8 @@ function testSchemaData() { $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', 'Got the right value for page.front data from the list.'); - // And test some ComplexDataInterface methods. - $properties = $list->getProperties(); + // And test some ListElementInterface methods. + $properties = $list->getElements(); $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', 'Got the right property values for site page.'); diff --git a/core/modules/config_translation/src/ConfigMapperManager.php b/core/modules/config_translation/src/ConfigMapperManager.php index 8eb3735..c241485 100644 --- a/core/modules/config_translation/src/ConfigMapperManager.php +++ b/core/modules/config_translation/src/ConfigMapperManager.php @@ -10,7 +10,7 @@ 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\Schema\ListElementInterface; use Drupal\Core\Config\TypedConfigManagerInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Extension\ThemeHandlerInterface; @@ -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 ListElementInterface) { foreach ($element as $child_element) { if ($this->findTranslatable($child_element)) { return TRUE; diff --git a/core/modules/config_translation/tests/src/ConfigMapperManagerTest.php b/core/modules/config_translation/tests/src/ConfigMapperManagerTest.php index d7c47cb..86a4719 100644 --- a/core/modules/config_translation/tests/src/ConfigMapperManagerTest.php +++ b/core/modules/config_translation/tests/src/ConfigMapperManagerTest.php @@ -170,12 +170,7 @@ 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. - $nested_element = $this->getMockBuilder('Drupal\Core\Config\Schema\Mapping') - ->disableOriginalConstructor() - ->getMock(); + $nested_element = $this->getMock('Drupal\Core\Config\Schema\ListElementInterface'); $nested_element->expects($this->once()) ->method('getIterator') ->will($this->returnValue(new \ArrayIterator($elements))); diff --git a/core/modules/locale/src/LocaleTypedConfig.php b/core/modules/locale/src/LocaleTypedConfig.php index 36e39a9..a01f50f 100644 --- a/core/modules/locale/src/LocaleTypedConfig.php +++ b/core/modules/locale/src/LocaleTypedConfig.php @@ -10,7 +10,7 @@ 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\Schema\ListElementInterface; /** * Defines the locale configuration wrapper object. @@ -105,7 +105,7 @@ protected function canTranslate($from_langcode, $to_langcode) { * * @param mixed $element * Typed configuration element, either \Drupal\Core\Config\Schema\Element or - * \Drupal\Core\Config\Schema\ArrayElement. + * \Drupal\Core\Config\Schema\ListElementInterface. * @param array $options * Array with translation options that must contain the keys defined in * \Drupal\locale\LocaleTypedConfig::translateElement() @@ -116,7 +116,7 @@ protected function canTranslate($from_langcode, $to_langcode) { */ protected function getElementTranslation($element, array $options) { $translation = array(); - if ($element instanceof ArrayElement) { + if ($element instanceof ListElementInterface) { $translation = $this->getArrayTranslation($element, $options); } elseif ($this->translateElement($element, $options)) { @@ -126,9 +126,9 @@ protected function getElementTranslation($element, array $options) { } /** - * Gets translated configuration data for an element of type ArrayElement. + * Gets translated configuration data for an element of type ListElementInterface. * - * @param \Drupal\Core\Config\Schema\ArrayElement $element + * @param \Drupal\Core\Config\Schema\ListElementInterface $element * Typed configuration array element. * @param array $options * Array with translation options that must contain the keys defined in @@ -137,7 +137,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(ListElementInterface $element, array $options) { $translation = array(); foreach ($element as $key => $property) { $value = $this->getElementTranslation($property, $options); diff --git a/core/modules/locale/src/Tests/LocaleConfigTranslationTest.php b/core/modules/locale/src/Tests/LocaleConfigTranslationTest.php index 94ec34d..5befd1a 100644 --- a/core/modules/locale/src/Tests/LocaleConfigTranslationTest.php +++ b/core/modules/locale/src/Tests/LocaleConfigTranslationTest.php @@ -81,7 +81,7 @@ 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/locale/src/Tests/LocaleImportFunctionalTest.php b/core/modules/locale/src/Tests/LocaleImportFunctionalTest.php index be3c22a..4e02ffd 100644 --- a/core/modules/locale/src/Tests/LocaleImportFunctionalTest.php +++ b/core/modules/locale/src/Tests/LocaleImportFunctionalTest.php @@ -297,7 +297,7 @@ function testConfigPoFile() { foreach ($config_strings as $config_key => $config_string) { $wrapper = $locale_config->get($config_key); $translation = $wrapper->getTranslation($langcode); - $properties = $translation->getProperties(); + $properties = $translation->getElements(); $this->assertEqual(count($properties), 1, 'Got the right number of properties with strict translation'); $this->assertEqual($properties[$config_string[2]]->getValue(), $config_string[1]); }