ArrayElement.php 4.7 KB

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