Issue #2298687 by tstoeckler, Jose Reyero, hussainweb, rpayanm: Sequence and Mapping implement interfaces incorrectly, make them honest about what they support
parent
fd73d486d7
commit
4337033622
|
@ -6,31 +6,35 @@
|
|||
*/
|
||||
|
||||
namespace Drupal\Core\Config\Schema;
|
||||
use Drupal\Core\TypedData\TraversableTypedDataInterface;
|
||||
|
||||
use Drupal\Component\Utility\String;
|
||||
use Drupal\Core\Config\TypedConfigManagerInterface;
|
||||
use Drupal\Core\TypedData\TypedData;
|
||||
|
||||
/**
|
||||
* 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, TypedConfigInterface {
|
||||
|
||||
/**
|
||||
* The typed config manager.
|
||||
*
|
||||
* @var \Drupal\Core\Config\TypedConfigManagerInterface
|
||||
*/
|
||||
protected $typedConfig;
|
||||
|
||||
/**
|
||||
* The configuration value.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $value;
|
||||
|
||||
/**
|
||||
* Parsed elements.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
|
@ -47,59 +51,97 @@ abstract class ArrayElement extends Element implements \IteratorAggregate, Trave
|
|||
* @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().
|
||||
* Gets data definition object for contained element.
|
||||
*
|
||||
* @param int|string $key
|
||||
* Property name or index of the element.
|
||||
*
|
||||
* @return \Drupal\Core\TypedData\DataDefinitionInterface
|
||||
*/
|
||||
public function validate() {
|
||||
foreach ($this->getElements() as $element) {
|
||||
if (!$element->validate()) {
|
||||
return FALSE;
|
||||
protected abstract function getElementDefinition($key);
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
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 TypedConfigInterface) {
|
||||
$element = $element->get($key);
|
||||
}
|
||||
else {
|
||||
$element = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ArrayAccess::offsetExists().
|
||||
*/
|
||||
public function offsetExists($offset) {
|
||||
return array_key_exists($offset, $this->getElements());
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ArrayAccess::offsetGet().
|
||||
*/
|
||||
public function offsetGet($offset) {
|
||||
$elements = $this->getElements();
|
||||
return $elements[$offset];
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ArrayAccess::offsetSet().
|
||||
*/
|
||||
public function offsetSet($offset, $value) {
|
||||
if ($value instanceof TypedDataInterface) {
|
||||
$value = $value->getValue();
|
||||
if (isset($element)) {
|
||||
return $element;
|
||||
}
|
||||
else {
|
||||
throw new \InvalidArgumentException(String::format("The configuration property @key doesn't exist.", array('@key' => $name)));
|
||||
}
|
||||
$this->value[$offset] = $value;
|
||||
unset($this->elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ArrayAccess::offsetUnset().
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetUnset($offset) {
|
||||
unset($this->value[$offset]);
|
||||
public function set($key, $value) {
|
||||
$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 Countable::count().
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function count() {
|
||||
return count($this->getElements());
|
||||
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($name) {
|
||||
// Notify the parent of changes.
|
||||
if (isset($this->parent)) {
|
||||
$this->parent->onChange($this->name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -109,4 +151,52 @@ abstract class ArrayElement extends Element implements \IteratorAggregate, Trave
|
|||
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 $key
|
||||
* The key of the contained element.
|
||||
*
|
||||
* @return \Drupal\Core\TypedData\TypedDataInterface
|
||||
*/
|
||||
protected function createElement($definition, $value, $key) {
|
||||
return $this->typedConfig->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 $this->typedConfig->buildDataDefinition($definition, $value, $key, $this);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the typed config manager on the instance.
|
||||
*
|
||||
* This must be called immediately after construction to enable
|
||||
* self::parseElement() and self::buildDataDefinition() to work.
|
||||
*
|
||||
* @param \Drupal\Core\Config\TypedConfigManagerInterface $typed_config
|
||||
*/
|
||||
public function setTypedConfig(TypedConfigManagerInterface $typed_config) {
|
||||
$this->typedConfig = $typed_config;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
namespace Drupal\Core\Config\Schema;
|
||||
|
||||
use Drupal\Core\Config\TypedConfigManagerInterface;
|
||||
use Drupal\Core\TypedData\TypedData;
|
||||
|
||||
/**
|
||||
|
@ -15,13 +14,6 @@ use Drupal\Core\TypedData\TypedData;
|
|||
*/
|
||||
abstract class Element extends TypedData {
|
||||
|
||||
/**
|
||||
* The typed config manager.
|
||||
*
|
||||
* @var \Drupal\Core\Config\TypedConfigManagerInterface
|
||||
*/
|
||||
protected $typedConfig;
|
||||
|
||||
/**
|
||||
* The configuration value.
|
||||
*
|
||||
|
@ -29,32 +21,4 @@ abstract class Element extends TypedData {
|
|||
*/
|
||||
protected $value;
|
||||
|
||||
/**
|
||||
* Create typed config object.
|
||||
*/
|
||||
protected function parseElement($key, $data, $definition) {
|
||||
return $this->typedConfig->create($definition, $data, $key, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build data definition object for contained elements.
|
||||
*
|
||||
* @return \Drupal\Core\TypedData\DataDefinitionInterface
|
||||
*/
|
||||
protected function buildDataDefinition($definition, $value, $key) {
|
||||
return $this->typedConfig->buildDataDefinition($definition, $value, $key, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the typed config manager on the instance.
|
||||
*
|
||||
* This must be called immediately after construction to enable
|
||||
* self::parseElement() and self::buildDataDefinition() to work.
|
||||
*
|
||||
* @param \Drupal\Core\Config\TypedConfigManagerInterface $typed_config
|
||||
*/
|
||||
public function setTypedConfig(TypedConfigManagerInterface $typed_config) {
|
||||
$this->typedConfig = $typed_config;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,10 +12,4 @@ namespace Drupal\Core\Config\Schema;
|
|||
*/
|
||||
class Ignore extends Element {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
public function validate() {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,151 +7,28 @@
|
|||
|
||||
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;
|
||||
class Mapping extends ArrayElement {
|
||||
|
||||
/**
|
||||
* {@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);
|
||||
}
|
||||
protected 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,112 +7,24 @@
|
|||
|
||||
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 {
|
||||
|
||||
/**
|
||||
* Data definition
|
||||
*
|
||||
* @var \Drupal\Core\TypedData\DataDefinitionInterface
|
||||
*/
|
||||
protected $itemDefinition;
|
||||
class Sequence extends ArrayElement {
|
||||
|
||||
/**
|
||||
* {@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.
|
||||
protected function getElementDefinition($key) {
|
||||
$value = isset($this->value[$key]) ? $this->value[$key] : NULL;
|
||||
$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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get($key) {
|
||||
$elements = $this->getElements();
|
||||
return $elements[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function first() {
|
||||
return $this->get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function set($index, $value) {
|
||||
$this->offsetSet($index, $value);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function removeItem($index) {
|
||||
$this->offsetUnset($index);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function appendItem($value = NULL) {
|
||||
$offset = $this->count();
|
||||
$this->offsetSet($offset, $value);
|
||||
return $this->offsetGet($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function filter($callback) {
|
||||
$this->value = array_filter($this->value, $callback);
|
||||
unset($this->elements);
|
||||
return $this;
|
||||
return $this->buildDataDefinition($definition, $value, $key);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Config\Schema\TypedConfigInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Config\Schema;
|
||||
|
||||
use Drupal\Core\TypedData\TraversableTypedDataInterface;
|
||||
|
||||
/**
|
||||
* Interface for a typed configuration object that contains multiple elements.
|
||||
*
|
||||
* A list of typed configuration contains any number of items whose type
|
||||
* will depend on the configuration schema but also on the configuration
|
||||
* data being parsed.
|
||||
*
|
||||
* When implementing this interface which extends Traversable, make sure to list
|
||||
* IteratorAggregate or Iterator before this interface in the implements clause.
|
||||
*/
|
||||
interface TypedConfigInterface extends TraversableTypedDataInterface {
|
||||
|
||||
/**
|
||||
* Determines whether the data structure is empty.
|
||||
*
|
||||
* @return boolean
|
||||
* TRUE if the data structure is empty, FALSE otherwise.
|
||||
*/
|
||||
public function isEmpty();
|
||||
|
||||
/**
|
||||
* Gets an array of contained elements.
|
||||
*
|
||||
* @return array
|
||||
* Array of \Drupal\Core\TypedData\TypedDataInterface objects.
|
||||
*/
|
||||
public function getElements();
|
||||
|
||||
/**
|
||||
* Gets a contained typed configuration element.
|
||||
*
|
||||
* @param $name
|
||||
* The name of the property to get; e.g., 'title' or 'name'. Nested
|
||||
* elements can be get using multiple dot delimited names, for example,
|
||||
* 'page.front'.
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* If an invalid property name is given.
|
||||
*
|
||||
* @return \Drupal\Core\TypedData\TypedDataInterface
|
||||
* The property object.
|
||||
*/
|
||||
public function get($name);
|
||||
|
||||
/**
|
||||
* Replaces the item at the specified position in this list.
|
||||
*
|
||||
* @param int|string $key
|
||||
* Property name or index of the item to replace.
|
||||
* @param mixed $value
|
||||
* Value to be stored at the specified position. It can be a raw
|
||||
* configuration value or \Drupal\Core\TypedData\TypedDataInterface
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function set($key, $value);
|
||||
|
||||
/**
|
||||
* Returns an array of all property values.
|
||||
*
|
||||
* @return array
|
||||
* An array of property values, keyed by property name.
|
||||
*/
|
||||
public function toArray();
|
||||
|
||||
}
|
|
@ -12,10 +12,4 @@ namespace Drupal\Core\Config\Schema;
|
|||
*/
|
||||
class Undefined extends Element {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
public function validate() {
|
||||
return isset($this->value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,9 +10,9 @@ namespace Drupal\Core\Config;
|
|||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\Component\Utility\String;
|
||||
use Drupal\Core\Cache\CacheBackendInterface;
|
||||
use Drupal\Core\Config\Schema\ArrayElement;
|
||||
use Drupal\Core\Config\Schema\ConfigSchemaAlterException;
|
||||
use Drupal\Core\Config\Schema\ConfigSchemaDiscovery;
|
||||
use Drupal\Core\Config\Schema\Element;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\TypedData\TypedDataManager;
|
||||
|
||||
|
@ -67,8 +67,8 @@ class TypedConfigManager extends TypedDataManager implements TypedConfigManagerI
|
|||
* @param string $name
|
||||
* Configuration object name.
|
||||
*
|
||||
* @return \Drupal\Core\Config\Schema\Element
|
||||
* Typed configuration element.
|
||||
* @return \Drupal\Core\Config\Schema\TypedConfigInterface
|
||||
* Typed configuration data.
|
||||
*/
|
||||
public function get($name) {
|
||||
$data = $this->configStorage->read($name);
|
||||
|
@ -335,7 +335,7 @@ class TypedConfigManager extends TypedDataManager implements TypedConfigManagerI
|
|||
$instance = parent::createInstance($data_type, $configuration);
|
||||
// Enable elements to construct their own definitions using the typed config
|
||||
// manager.
|
||||
if ($instance instanceof Element) {
|
||||
if ($instance instanceof ArrayElement) {
|
||||
$instance->setTypedConfig($this);
|
||||
}
|
||||
return $instance;
|
||||
|
|
|
@ -69,21 +69,21 @@ class ConfigSchemaTest extends KernelTestBase {
|
|||
|
||||
// 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';
|
||||
|
@ -197,7 +197,7 @@ class ConfigSchemaTest extends KernelTestBase {
|
|||
|
||||
// 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';
|
||||
|
||||
|
@ -244,7 +244,7 @@ class ConfigSchemaTest extends KernelTestBase {
|
|||
|
||||
// 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',
|
||||
|
@ -255,7 +255,7 @@ class ConfigSchemaTest extends KernelTestBase {
|
|||
|
||||
// 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',
|
||||
|
@ -266,7 +266,7 @@ class ConfigSchemaTest extends KernelTestBase {
|
|||
|
||||
// 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',
|
||||
|
@ -295,28 +295,26 @@ class ConfigSchemaTest extends KernelTestBase {
|
|||
$this->assertTrue(empty($definition['translatable']), 'Got the right translatability setting for page.front data.');
|
||||
|
||||
// Check nested array of properties.
|
||||
$list = $meta->get('page');
|
||||
$list = $meta->get('page')->getElements();
|
||||
$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();
|
||||
// And test some TypedConfigInterface methods.
|
||||
$properties = $list;
|
||||
$this->assertTrue(count($properties) == 3 && $properties['front'] == $list['front'], 'Got the right properties for site page.');
|
||||
$values = $list->toArray();
|
||||
$values = $meta->get('page')->toArray();
|
||||
$this->assertTrue(count($values) == 3 && $values['front'] == 'user/login', 'Got the right property values for site page.');
|
||||
|
||||
// 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');
|
||||
$this->assertTrue(count($effects->toArray()) == 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';
|
||||
|
@ -423,7 +421,7 @@ class ConfigSchemaTest extends KernelTestBase {
|
|||
* @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');
|
||||
|
||||
|
@ -436,17 +434,17 @@ class ConfigSchemaTest extends KernelTestBase {
|
|||
$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.*');
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace Drupal\config_translation\Form;
|
|||
use Drupal\config_translation\ConfigMapperManagerInterface;
|
||||
use Drupal\Core\Config\TypedConfigManagerInterface;
|
||||
use Drupal\Core\TypedData\TypedDataInterface;
|
||||
use Drupal\Core\TypedData\TraversableTypedDataInterface;
|
||||
use Drupal\Core\Form\BaseFormIdInterface;
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
|
|
@ -83,7 +83,7 @@ class LocaleConfigTranslationTest extends WebTestBase {
|
|||
|
||||
// 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.
|
||||
|
|
Loading…
Reference in New Issue