Patched to Drupal 8.4.8 level. See https://www.drupal.org/sa-core-2018-004 and patch...
[yaffs-website] / web / core / lib / Drupal / Core / Config / Schema / ArrayElement.php
1 <?php
2
3 namespace Drupal\Core\Config\Schema;
4
5 use Drupal\Core\TypedData\ComplexDataInterface;
6
7 /**
8  * Defines a generic configuration element that contains multiple properties.
9  */
10 abstract class ArrayElement extends Element implements \IteratorAggregate, TypedConfigInterface, ComplexDataInterface {
11
12   /**
13    * Parsed elements.
14    */
15   protected $elements;
16
17   /**
18    * Gets valid configuration data keys.
19    *
20    * @return array
21    *   Array of valid configuration data keys.
22    */
23   protected function getAllKeys() {
24     return is_array($this->value) ? array_keys($this->value) : [];
25   }
26
27   /**
28    * Builds an array of contained elements.
29    *
30    * @return \Drupal\Core\TypedData\TypedDataInterface[]
31    *   An array of elements contained in this element.
32    */
33   protected function parse() {
34     $elements = [];
35     foreach ($this->getAllKeys() as $key) {
36       $value = isset($this->value[$key]) ? $this->value[$key] : NULL;
37       $definition = $this->getElementDefinition($key);
38       $elements[$key] = $this->createElement($definition, $value, $key);
39     }
40     return $elements;
41   }
42
43   /**
44    * Gets data definition object for contained element.
45    *
46    * @param int|string $key
47    *   Property name or index of the element.
48    *
49    * @return \Drupal\Core\TypedData\DataDefinitionInterface
50    */
51   abstract protected function getElementDefinition($key);
52
53   /**
54    * {@inheritdoc}
55    */
56   public function get($name) {
57     $parts = explode('.', $name);
58     $root_key = array_shift($parts);
59     $elements = $this->getElements();
60     if (isset($elements[$root_key])) {
61       $element = $elements[$root_key];
62       // If $property_name contained a dot recurse into the keys.
63       while ($element && ($key = array_shift($parts)) !== NULL) {
64         if ($element instanceof TypedConfigInterface) {
65           $element = $element->get($key);
66         }
67         else {
68           $element = NULL;
69         }
70       }
71     }
72     if (isset($element)) {
73       return $element;
74     }
75     else {
76       throw new \InvalidArgumentException("The configuration property $name doesn't exist.");
77     }
78   }
79
80   /**
81    * {@inheritdoc}
82    */
83   public function getElements() {
84     if (!isset($this->elements)) {
85       $this->elements = $this->parse();
86     }
87     return $this->elements;
88   }
89
90   /**
91    * {@inheritdoc}
92    */
93   public function isEmpty() {
94     return empty($this->value);
95   }
96
97   /**
98    * {@inheritdoc}
99    */
100   public function toArray() {
101     return isset($this->value) ? $this->value : [];
102   }
103
104   /**
105    * {@inheritdoc}
106    */
107   public function onChange($name) {
108     // Notify the parent of changes.
109     if (isset($this->parent)) {
110       $this->parent->onChange($this->name);
111     }
112   }
113
114   /**
115    * {@inheritdoc}
116    */
117   public function getIterator() {
118     return new \ArrayIterator($this->getElements());
119   }
120
121   /**
122    * Creates a contained typed configuration object.
123    *
124    * @param \Drupal\Core\TypedData\DataDefinitionInterface $definition
125    *   The data definition object.
126    * @param mixed $value
127    *   (optional) The data value. If set, it has to match one of the supported
128    *   data type format as documented for the data type classes.
129    * @param string $key
130    *   The key of the contained element.
131    *
132    * @return \Drupal\Core\TypedData\TypedDataInterface
133    */
134   protected function createElement($definition, $value, $key) {
135     return $this->getTypedDataManager()->create($definition, $value, $key, $this);
136   }
137
138   /**
139    * Creates a new data definition object from a type definition array and
140    * actual configuration data.
141    *
142    * @param array $definition
143    *   The base type definition array, for which a data definition should be
144    *   created.
145    * @param $value
146    *   The value of the configuration element.
147    * @param string $key
148    *   The key of the contained element.
149    *
150    * @return \Drupal\Core\TypedData\DataDefinitionInterface
151    */
152   protected function buildDataDefinition($definition, $value, $key) {
153     return $this->getTypedDataManager()->buildDataDefinition($definition, $value, $key, $this);
154   }
155
156   /**
157    * Determines if this element allows NULL as a value.
158    *
159    * @return bool
160    *   TRUE if NULL is a valid value, FALSE otherwise.
161    */
162   public function isNullable() {
163     return isset($this->definition['nullable']) && $this->definition['nullable'] == TRUE;
164   }
165
166   /**
167    * {@inheritdoc}
168    */
169   public function set($property_name, $value, $notify = TRUE) {
170     $this->value[$property_name] = $value;
171     // Config schema elements do not make use of notifications. Thus, we skip
172     // notifying parents.
173     return $this;
174   }
175
176   /**
177    * {@inheritdoc}
178    */
179   public function getProperties($include_computed = FALSE) {
180     $properties = [];
181     foreach (array_keys($this->value) as $name) {
182       $properties[$name] = $this->get($name);
183     }
184     return $properties;
185   }
186
187 }