Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

ArrayNodeDefinition.php

Zuletzt modifiziert: 02.04.2025, 15:03 - Dateigröße: 14.90 KiB


001  <?php
002   
003  /*
004   * This file is part of the Symfony package.
005   *
006   * (c) Fabien Potencier <fabien@symfony.com>
007   *
008   * For the full copyright and license information, please view the LICENSE
009   * file that was distributed with this source code.
010   */
011   
012  namespace Symfony\Component\Config\Definition\Builder;
013   
014  use Symfony\Component\Config\Definition\ArrayNode;
015  use Symfony\Component\Config\Definition\Exception\InvalidDefinitionException;
016  use Symfony\Component\Config\Definition\PrototypedArrayNode;
017   
018  /**
019   * This class provides a fluent interface for defining an array node.
020   *
021   * @author Johannes M. Schmitt <schmittjoh@gmail.com>
022   */
023  class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinitionInterface
024  {
025      protected $performDeepMerging = true;
026      protected $ignoreExtraKeys = false;
027      protected $removeExtraKeys = true;
028      protected $children = [];
029      protected $prototype;
030      protected $atLeastOne = false;
031      protected $allowNewKeys = true;
032      protected $key;
033      protected $removeKeyItem;
034      protected $addDefaults = false;
035      protected $addDefaultChildren = false;
036      protected $nodeBuilder;
037      protected $normalizeKeys = true;
038   
039      /**
040       * {@inheritdoc}
041       */
042      public function __construct($name, NodeParentInterface $parent = null)
043      {
044          parent::__construct($name, $parent);
045   
046          $this->nullEquivalent = [];
047          $this->trueEquivalent = [];
048      }
049   
050      /**
051       * {@inheritdoc}
052       */
053      public function setBuilder(NodeBuilder $builder)
054      {
055          $this->nodeBuilder = $builder;
056      }
057   
058      /**
059       * {@inheritdoc}
060       */
061      public function children()
062      {
063          return $this->getNodeBuilder();
064      }
065   
066      /**
067       * Sets a prototype for child nodes.
068       *
069       * @param string $type The type of node
070       *
071       * @return NodeDefinition
072       */
073      public function prototype($type)
074      {
075          return $this->prototype = $this->getNodeBuilder()->node(null, $type)->setParent($this);
076      }
077   
078      /**
079       * @return VariableNodeDefinition
080       */
081      public function variablePrototype()
082      {
083          return $this->prototype('variable');
084      }
085   
086      /**
087       * @return ScalarNodeDefinition
088       */
089      public function scalarPrototype()
090      {
091          return $this->prototype('scalar');
092      }
093   
094      /**
095       * @return BooleanNodeDefinition
096       */
097      public function booleanPrototype()
098      {
099          return $this->prototype('boolean');
100      }
101   
102      /**
103       * @return IntegerNodeDefinition
104       */
105      public function integerPrototype()
106      {
107          return $this->prototype('integer');
108      }
109   
110      /**
111       * @return FloatNodeDefinition
112       */
113      public function floatPrototype()
114      {
115          return $this->prototype('float');
116      }
117   
118      /**
119       * @return ArrayNodeDefinition
120       */
121      public function arrayPrototype()
122      {
123          return $this->prototype('array');
124      }
125   
126      /**
127       * @return EnumNodeDefinition
128       */
129      public function enumPrototype()
130      {
131          return $this->prototype('enum');
132      }
133   
134      /**
135       * Adds the default value if the node is not set in the configuration.
136       *
137       * This method is applicable to concrete nodes only (not to prototype nodes).
138       * If this function has been called and the node is not set during the finalization
139       * phase, it's default value will be derived from its children default values.
140       *
141       * @return $this
142       */
143      public function addDefaultsIfNotSet()
144      {
145          $this->addDefaults = true;
146   
147          return $this;
148      }
149   
150      /**
151       * Adds children with a default value when none are defined.
152       *
153       * This method is applicable to prototype nodes only.
154       *
155       * @param int|string|array|null $children The number of children|The child name|The children names to be added
156       *
157       * @return $this
158       */
159      public function addDefaultChildrenIfNoneSet($children = null)
160      {
161          $this->addDefaultChildren = $children;
162   
163          return $this;
164      }
165   
166      /**
167       * Requires the node to have at least one element.
168       *
169       * This method is applicable to prototype nodes only.
170       *
171       * @return $this
172       */
173      public function requiresAtLeastOneElement()
174      {
175          $this->atLeastOne = true;
176   
177          return $this;
178      }
179   
180      /**
181       * Disallows adding news keys in a subsequent configuration.
182       *
183       * If used all keys have to be defined in the same configuration file.
184       *
185       * @return $this
186       */
187      public function disallowNewKeysInSubsequentConfigs()
188      {
189          $this->allowNewKeys = false;
190   
191          return $this;
192      }
193   
194      /**
195       * Sets a normalization rule for XML configurations.
196       *
197       * @param string $singular The key to remap
198       * @param string $plural   The plural of the key for irregular plurals
199       *
200       * @return $this
201       */
202      public function fixXmlConfig($singular, $plural = null)
203      {
204          $this->normalization()->remap($singular, $plural);
205   
206          return $this;
207      }
208   
209      /**
210       * Sets the attribute which value is to be used as key.
211       *
212       * This is useful when you have an indexed array that should be an
213       * associative array. You can select an item from within the array
214       * to be the key of the particular item. For example, if "id" is the
215       * "key", then:
216       *
217       *     [
218       *         ['id' => 'my_name', 'foo' => 'bar'],
219       *     ];
220       *
221       *   becomes
222       *
223       *     [
224       *         'my_name' => ['foo' => 'bar'],
225       *     ];
226       *
227       * If you'd like "'id' => 'my_name'" to still be present in the resulting
228       * array, then you can set the second argument of this method to false.
229       *
230       * This method is applicable to prototype nodes only.
231       *
232       * @param string $name          The name of the key
233       * @param bool   $removeKeyItem Whether or not the key item should be removed
234       *
235       * @return $this
236       */
237      public function useAttributeAsKey($name, $removeKeyItem = true)
238      {
239          $this->key = $name;
240          $this->removeKeyItem = $removeKeyItem;
241   
242          return $this;
243      }
244   
245      /**
246       * Sets whether the node can be unset.
247       *
248       * @param bool $allow
249       *
250       * @return $this
251       */
252      public function canBeUnset($allow = true)
253      {
254          $this->merge()->allowUnset($allow);
255   
256          return $this;
257      }
258   
259      /**
260       * Adds an "enabled" boolean to enable the current section.
261       *
262       * By default, the section is disabled. If any configuration is specified then
263       * the node will be automatically enabled:
264       *
265       * enableableArrayNode: {enabled: true, ...}   # The config is enabled & default values get overridden
266       * enableableArrayNode: ~                      # The config is enabled & use the default values
267       * enableableArrayNode: true                   # The config is enabled & use the default values
268       * enableableArrayNode: {other: value, ...}    # The config is enabled & default values get overridden
269       * enableableArrayNode: {enabled: false, ...}  # The config is disabled
270       * enableableArrayNode: false                  # The config is disabled
271       *
272       * @return $this
273       */
274      public function canBeEnabled()
275      {
276          $this
277              ->addDefaultsIfNotSet()
278              ->treatFalseLike(['enabled' => false])
279              ->treatTrueLike(['enabled' => true])
280              ->treatNullLike(['enabled' => true])
281              ->beforeNormalization()
282                  ->ifArray()
283                  ->then(function ($v) {
284                      $v['enabled'] = isset($v['enabled']) ? $v['enabled'] : true;
285   
286                      return $v;
287                  })
288              ->end()
289              ->children()
290                  ->booleanNode('enabled')
291                      ->defaultFalse()
292          ;
293   
294          return $this;
295      }
296   
297      /**
298       * Adds an "enabled" boolean to enable the current section.
299       *
300       * By default, the section is enabled.
301       *
302       * @return $this
303       */
304      public function canBeDisabled()
305      {
306          $this
307              ->addDefaultsIfNotSet()
308              ->treatFalseLike(['enabled' => false])
309              ->treatTrueLike(['enabled' => true])
310              ->treatNullLike(['enabled' => true])
311              ->children()
312                  ->booleanNode('enabled')
313                      ->defaultTrue()
314          ;
315   
316          return $this;
317      }
318   
319      /**
320       * Disables the deep merging of the node.
321       *
322       * @return $this
323       */
324      public function performNoDeepMerging()
325      {
326          $this->performDeepMerging = false;
327   
328          return $this;
329      }
330   
331      /**
332       * Allows extra config keys to be specified under an array without
333       * throwing an exception.
334       *
335       * Those config values are ignored and removed from the resulting
336       * array. This should be used only in special cases where you want
337       * to send an entire configuration array through a special tree that
338       * processes only part of the array.
339       *
340       * @param bool $remove Whether to remove the extra keys
341       *
342       * @return $this
343       */
344      public function ignoreExtraKeys($remove = true)
345      {
346          $this->ignoreExtraKeys = true;
347          $this->removeExtraKeys = $remove;
348   
349          return $this;
350      }
351   
352      /**
353       * Sets key normalization.
354       *
355       * @param bool $bool Whether to enable key normalization
356       *
357       * @return $this
358       */
359      public function normalizeKeys($bool)
360      {
361          $this->normalizeKeys = (bool) $bool;
362   
363          return $this;
364      }
365   
366      /**
367       * {@inheritdoc}
368       */
369      public function append(NodeDefinition $node)
370      {
371          $this->children[$node->name] = $node->setParent($this);
372   
373          return $this;
374      }
375   
376      /**
377       * Returns a node builder to be used to add children and prototype.
378       *
379       * @return NodeBuilder The node builder
380       */
381      protected function getNodeBuilder()
382      {
383          if (null === $this->nodeBuilder) {
384              $this->nodeBuilder = new NodeBuilder();
385          }
386   
387          return $this->nodeBuilder->setParent($this);
388      }
389   
390      /**
391       * {@inheritdoc}
392       */
393      protected function createNode()
394      {
395          if (null === $this->prototype) {
396              $node = new ArrayNode($this->name, $this->parent);
397   
398              $this->validateConcreteNode($node);
399   
400              $node->setAddIfNotSet($this->addDefaults);
401   
402              foreach ($this->children as $child) {
403                  $child->parent = $node;
404                  $node->addChild($child->getNode());
405              }
406          } else {
407              $node = new PrototypedArrayNode($this->name, $this->parent);
408   
409              $this->validatePrototypeNode($node);
410   
411              if (null !== $this->key) {
412                  $node->setKeyAttribute($this->key, $this->removeKeyItem);
413              }
414   
415              if (false === $this->allowEmptyValue) {
416                  @trigger_error(sprintf('Using %s::cannotBeEmpty() at path "%s" has no effect, consider requiresAtLeastOneElement() instead. In 4.0 both methods will behave the same.', __CLASS__, $node->getPath()), \E_USER_DEPRECATED);
417              }
418   
419              if (true === $this->atLeastOne) {
420                  $node->setMinNumberOfElements(1);
421              }
422   
423              if ($this->default) {
424                  $node->setDefaultValue($this->defaultValue);
425              }
426   
427              if (false !== $this->addDefaultChildren) {
428                  $node->setAddChildrenIfNoneSet($this->addDefaultChildren);
429                  if ($this->prototype instanceof static && null === $this->prototype->prototype) {
430                      $this->prototype->addDefaultsIfNotSet();
431                  }
432              }
433   
434              $this->prototype->parent = $node;
435              $node->setPrototype($this->prototype->getNode());
436          }
437   
438          $node->setAllowNewKeys($this->allowNewKeys);
439          $node->addEquivalentValue(null, $this->nullEquivalent);
440          $node->addEquivalentValue(true, $this->trueEquivalent);
441          $node->addEquivalentValue(false, $this->falseEquivalent);
442          $node->setPerformDeepMerging($this->performDeepMerging);
443          $node->setRequired($this->required);
444          $node->setDeprecated($this->deprecationMessage);
445          $node->setIgnoreExtraKeys($this->ignoreExtraKeys, $this->removeExtraKeys);
446          $node->setNormalizeKeys($this->normalizeKeys);
447   
448          if (null !== $this->normalization) {
449              $node->setNormalizationClosures($this->normalization->before);
450              $node->setXmlRemappings($this->normalization->remappings);
451          }
452   
453          if (null !== $this->merge) {
454              $node->setAllowOverwrite($this->merge->allowOverwrite);
455              $node->setAllowFalse($this->merge->allowFalse);
456          }
457   
458          if (null !== $this->validation) {
459              $node->setFinalValidationClosures($this->validation->rules);
460          }
461   
462          return $node;
463      }
464   
465      /**
466       * Validate the configuration of a concrete node.
467       *
468       * @throws InvalidDefinitionException
469       */
470      protected function validateConcreteNode(ArrayNode $node)
471      {
472          $path = $node->getPath();
473   
474          if (null !== $this->key) {
475              throw new InvalidDefinitionException(sprintf('->useAttributeAsKey() is not applicable to concrete nodes at path "%s".', $path));
476          }
477   
478          if (false === $this->allowEmptyValue) {
479              @trigger_error(sprintf('->cannotBeEmpty() is not applicable to concrete nodes at path "%s". In 4.0 it will throw an exception.', $path), \E_USER_DEPRECATED);
480          }
481   
482          if (true === $this->atLeastOne) {
483              throw new InvalidDefinitionException(sprintf('->requiresAtLeastOneElement() is not applicable to concrete nodes at path "%s".', $path));
484          }
485   
486          if ($this->default) {
487              throw new InvalidDefinitionException(sprintf('->defaultValue() is not applicable to concrete nodes at path "%s".', $path));
488          }
489   
490          if (false !== $this->addDefaultChildren) {
491              throw new InvalidDefinitionException(sprintf('->addDefaultChildrenIfNoneSet() is not applicable to concrete nodes at path "%s".', $path));
492          }
493      }
494   
495      /**
496       * Validate the configuration of a prototype node.
497       *
498       * @throws InvalidDefinitionException
499       */
500      protected function validatePrototypeNode(PrototypedArrayNode $node)
501      {
502          $path = $node->getPath();
503   
504          if ($this->addDefaults) {
505              throw new InvalidDefinitionException(sprintf('->addDefaultsIfNotSet() is not applicable to prototype nodes at path "%s".', $path));
506          }
507   
508          if (false !== $this->addDefaultChildren) {
509              if ($this->default) {
510                  throw new InvalidDefinitionException(sprintf('A default value and default children might not be used together at path "%s".', $path));
511              }
512   
513              if (null !== $this->key && (null === $this->addDefaultChildren || \is_int($this->addDefaultChildren) && $this->addDefaultChildren > 0)) {
514                  throw new InvalidDefinitionException(sprintf('->addDefaultChildrenIfNoneSet() should set default children names as ->useAttributeAsKey() is used at path "%s".', $path));
515              }
516   
517              if (null === $this->key && (\is_string($this->addDefaultChildren) || \is_array($this->addDefaultChildren))) {
518                  throw new InvalidDefinitionException(sprintf('->addDefaultChildrenIfNoneSet() might not set default children names as ->useAttributeAsKey() is not used at path "%s".', $path));
519              }
520          }
521      }
522  }
523