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. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
ArrayNodeDefinition.php
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