Overview

Namespaces

  • Contrib
    • Bundle
      • CoverallsBundle
        • Console
        • Entity
      • CoverallsV1Bundle
        • Api
        • Collector
        • Command
        • Config
        • Entity
          • Git
    • Component
      • File
      • Log
      • System
        • Git
  • Guzzle
    • Batch
      • Exception
    • Cache
    • Common
      • Exception
    • Http
      • Curl
      • Exception
      • Message
      • QueryAggregator
    • Inflection
    • Iterator
    • Log
    • Parser
      • Cookie
      • Message
      • UriTemplate
      • Url
    • Plugin
      • Async
      • Backoff
      • Cache
      • Cookie
        • CookieJar
        • Exception
      • CurlAuth
      • ErrorResponse
        • Exception
      • History
      • Log
      • Md5
      • Mock
      • Oauth
    • Service
      • Builder
      • Command
        • Factory
        • LocationVisitor
          • Request
          • Response
      • Description
      • Exception
      • Resource
    • Stream
  • PHP
  • Psr
    • Log
  • Symfony
    • Component
      • Config
        • Definition
          • Builder
          • Exception
        • Exception
        • Loader
        • Resource
        • Util
      • Console
        • Command
        • Formatter
        • Helper
        • Input
        • Output
        • Tester
      • EventDispatcher
        • Debug
      • Finder
        • Adapter
        • Comparator
        • Exception
        • Expression
        • Iterator
        • Shell
      • Stopwatch
      • Yaml
        • Exception

Classes

  • ArrayNodeDefinition
  • BooleanNodeDefinition
  • EnumNodeDefinition
  • ExprBuilder
  • FloatNodeDefinition
  • IntegerNodeDefinition
  • MergeBuilder
  • NodeBuilder
  • NodeDefinition
  • NormalizationBuilder
  • NumericNodeDefinition
  • ScalarNodeDefinition
  • TreeBuilder
  • ValidationBuilder
  • VariableNodeDefinition

Interfaces

  • NodeParentInterface
  • ParentNodeDefinitionInterface
  • Overview
  • Namespace
  • Class
  • Tree
  • Todo
  1: <?php
  2: 
  3: /*
  4:  * This file is part of the Symfony package.
  5:  *
  6:  * (c) Fabien Potencier <fabien@symfony.com>
  7:  *
  8:  * For the full copyright and license information, please view the LICENSE
  9:  * file that was distributed with this source code.
 10:  */
 11: 
 12: namespace Symfony\Component\Config\Definition\Builder;
 13: 
 14: use Symfony\Component\Config\Definition\ArrayNode;
 15: use Symfony\Component\Config\Definition\PrototypedArrayNode;
 16: use Symfony\Component\Config\Definition\Exception\InvalidDefinitionException;
 17: 
 18: /**
 19:  * This class provides a fluent interface for defining an array node.
 20:  *
 21:  * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 22:  */
 23: class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinitionInterface
 24: {
 25:     protected $performDeepMerging;
 26:     protected $ignoreExtraKeys;
 27:     protected $children;
 28:     protected $prototype;
 29:     protected $atLeastOne;
 30:     protected $allowNewKeys;
 31:     protected $key;
 32:     protected $removeKeyItem;
 33:     protected $addDefaults;
 34:     protected $addDefaultChildren;
 35:     protected $nodeBuilder;
 36:     protected $normalizeKeys;
 37: 
 38:     /**
 39:      * {@inheritDoc}
 40:      */
 41:     public function __construct($name, NodeParentInterface $parent = null)
 42:     {
 43:         parent::__construct($name, $parent);
 44: 
 45:         $this->children = array();
 46:         $this->addDefaults = false;
 47:         $this->addDefaultChildren = false;
 48:         $this->allowNewKeys = true;
 49:         $this->atLeastOne = false;
 50:         $this->allowEmptyValue = true;
 51:         $this->performDeepMerging = true;
 52:         $this->nullEquivalent = array();
 53:         $this->trueEquivalent = array();
 54:         $this->normalizeKeys = true;
 55:     }
 56: 
 57:     /**
 58:      * Sets a custom children builder.
 59:      *
 60:      * @param NodeBuilder $builder A custom NodeBuilder
 61:      */
 62:     public function setBuilder(NodeBuilder $builder)
 63:     {
 64:         $this->nodeBuilder = $builder;
 65:     }
 66: 
 67:     /**
 68:      * Returns a builder to add children nodes.
 69:      *
 70:      * @return NodeBuilder
 71:      */
 72:     public function children()
 73:     {
 74:         return $this->getNodeBuilder();
 75:     }
 76: 
 77:     /**
 78:      * Sets a prototype for child nodes.
 79:      *
 80:      * @param string $type the type of node
 81:      *
 82:      * @return NodeDefinition
 83:      */
 84:     public function prototype($type)
 85:     {
 86:         return $this->prototype = $this->getNodeBuilder()->node(null, $type)->setParent($this);
 87:     }
 88: 
 89:     /**
 90:      * Adds the default value if the node is not set in the configuration.
 91:      *
 92:      * This method is applicable to concrete nodes only (not to prototype nodes).
 93:      * If this function has been called and the node is not set during the finalization
 94:      * phase, it's default value will be derived from its children default values.
 95:      *
 96:      * @return ArrayNodeDefinition
 97:      */
 98:     public function addDefaultsIfNotSet()
 99:     {
100:         $this->addDefaults = true;
101: 
102:         return $this;
103:     }
104: 
105:     /**
106:      * Adds children with a default value when none are defined.
107:      *
108:      * @param integer|string|array|null $children The number of children|The child name|The children names to be added
109:      *
110:      * This method is applicable to prototype nodes only.
111:      *
112:      * @return ArrayNodeDefinition
113:      */
114:     public function addDefaultChildrenIfNoneSet($children = null)
115:     {
116:         $this->addDefaultChildren = $children;
117: 
118:         return $this;
119:     }
120: 
121:     /**
122:      * Requires the node to have at least one element.
123:      *
124:      * This method is applicable to prototype nodes only.
125:      *
126:      * @return ArrayNodeDefinition
127:      */
128:     public function requiresAtLeastOneElement()
129:     {
130:         $this->atLeastOne = true;
131: 
132:         return $this;
133:     }
134: 
135:     /**
136:      * Disallows adding news keys in a subsequent configuration.
137:      *
138:      * If used all keys have to be defined in the same configuration file.
139:      *
140:      * @return ArrayNodeDefinition
141:      */
142:     public function disallowNewKeysInSubsequentConfigs()
143:     {
144:         $this->allowNewKeys = false;
145: 
146:         return $this;
147:     }
148: 
149:     /**
150:      * Sets a normalization rule for XML configurations.
151:      *
152:      * @param string $singular The key to remap
153:      * @param string $plural   The plural of the key for irregular plurals
154:      *
155:      * @return ArrayNodeDefinition
156:      */
157:     public function fixXmlConfig($singular, $plural = null)
158:     {
159:         $this->normalization()->remap($singular, $plural);
160: 
161:         return $this;
162:     }
163: 
164:     /**
165:      * Sets the attribute which value is to be used as key.
166:      *
167:      * This is useful when you have an indexed array that should be an
168:      * associative array. You can select an item from within the array
169:      * to be the key of the particular item. For example, if "id" is the
170:      * "key", then:
171:      *
172:      *     array(
173:      *         array('id' => 'my_name', 'foo' => 'bar'),
174:      *     );
175:      *
176:      *   becomes
177:      *
178:      *     array(
179:      *         'my_name' => array('foo' => 'bar'),
180:      *     );
181:      *
182:      * If you'd like "'id' => 'my_name'" to still be present in the resulting
183:      * array, then you can set the second argument of this method to false.
184:      *
185:      * This method is applicable to prototype nodes only.
186:      *
187:      * @param string  $name          The name of the key
188:      * @param Boolean $removeKeyItem Whether or not the key item should be removed.
189:      *
190:      * @return ArrayNodeDefinition
191:      */
192:     public function useAttributeAsKey($name, $removeKeyItem = true)
193:     {
194:         $this->key = $name;
195:         $this->removeKeyItem = $removeKeyItem;
196: 
197:         return $this;
198:     }
199: 
200:     /**
201:      * Sets whether the node can be unset.
202:      *
203:      * @param Boolean $allow
204:      *
205:      * @return ArrayNodeDefinition
206:      */
207:     public function canBeUnset($allow = true)
208:     {
209:         $this->merge()->allowUnset($allow);
210: 
211:         return $this;
212:     }
213: 
214:     /**
215:      * Adds an "enabled" boolean to enable the current section.
216:      *
217:      * By default, the section is disabled. If any configuration is specified then
218:      * the node will be automatically enabled:
219:      *
220:      * enableableArrayNode: {enabled: true, ...}   # The config is enabled & default values get overridden
221:      * enableableArrayNode: ~                      # The config is enabled & use the default values
222:      * enableableArrayNode: true                   # The config is enabled & use the default values
223:      * enableableArrayNode: {other: value, ...}    # The config is enabled & default values get overridden
224:      * enableableArrayNode: {enabled: false, ...}  # The config is disabled
225:      * enableableArrayNode: false                  # The config is disabled
226:      *
227:      * @return ArrayNodeDefinition
228:      */
229:     public function canBeEnabled()
230:     {
231:         $this
232:             ->addDefaultsIfNotSet()
233:             ->treatFalseLike(array('enabled' => false))
234:             ->treatTrueLike(array('enabled' => true))
235:             ->treatNullLike(array('enabled' => true))
236:             ->beforeNormalization()
237:                 ->ifArray()
238:                 ->then(function($v) {
239:                     $v['enabled'] = isset($v['enabled']) ? $v['enabled'] : true;
240: 
241:                     return $v;
242:                 })
243:             ->end()
244:             ->children()
245:                 ->booleanNode('enabled')
246:                     ->defaultFalse()
247:         ;
248: 
249:         return $this;
250:     }
251: 
252:     /**
253:      * Adds an "enabled" boolean to enable the current section.
254:      *
255:      * By default, the section is enabled.
256:      *
257:      * @return ArrayNodeDefinition
258:      */
259:     public function canBeDisabled()
260:     {
261:         $this
262:             ->addDefaultsIfNotSet()
263:             ->treatFalseLike(array('enabled' => false))
264:             ->treatTrueLike(array('enabled' => true))
265:             ->treatNullLike(array('enabled' => true))
266:             ->children()
267:                 ->booleanNode('enabled')
268:                     ->defaultTrue()
269:         ;
270: 
271:         return $this;
272:     }
273: 
274:     /**
275:      * Disables the deep merging of the node.
276:      *
277:      * @return ArrayNodeDefinition
278:      */
279:     public function performNoDeepMerging()
280:     {
281:         $this->performDeepMerging = false;
282: 
283:         return $this;
284:     }
285: 
286:     /**
287:      * Allows extra config keys to be specified under an array without
288:      * throwing an exception.
289:      *
290:      * Those config values are simply ignored. This should be used only
291:      * in special cases where you want to send an entire configuration
292:      * array through a special tree that processes only part of the array.
293:      *
294:      * @return ArrayNodeDefinition
295:      */
296:     public function ignoreExtraKeys()
297:     {
298:         $this->ignoreExtraKeys = true;
299: 
300:         return $this;
301:     }
302: 
303:     /**
304:      * Sets key normalization.
305:      *
306:      * @param Boolean $bool Whether to enable key normalization
307:      *
308:      * @return ArrayNodeDefinition
309:      */
310:     public function normalizeKeys($bool)
311:     {
312:         $this->normalizeKeys = (Boolean) $bool;
313: 
314:         return $this;
315:     }
316: 
317:     /**
318:      * Appends a node definition.
319:      *
320:      *     $node = new ArrayNodeDefinition()
321:      *         ->children()
322:      *             ->scalarNode('foo')->end()
323:      *             ->scalarNode('baz')->end()
324:      *         ->end()
325:      *         ->append($this->getBarNodeDefinition())
326:      *     ;
327:      *
328:      * @param NodeDefinition $node A NodeDefinition instance
329:      *
330:      * @return ArrayNodeDefinition This node
331:      */
332:     public function append(NodeDefinition $node)
333:     {
334:         $this->children[$node->name] = $node->setParent($this);
335: 
336:         return $this;
337:     }
338: 
339:     /**
340:      * Returns a node builder to be used to add children and prototype
341:      *
342:      * @return NodeBuilder The node builder
343:      */
344:     protected function getNodeBuilder()
345:     {
346:         if (null === $this->nodeBuilder) {
347:             $this->nodeBuilder = new NodeBuilder();
348:         }
349: 
350:         return $this->nodeBuilder->setParent($this);
351:     }
352: 
353:     /**
354:      * {@inheritDoc}
355:      */
356:     protected function createNode()
357:     {
358:         if (null === $this->prototype) {
359:             $node = new ArrayNode($this->name, $this->parent);
360: 
361:             $this->validateConcreteNode($node);
362: 
363:             $node->setAddIfNotSet($this->addDefaults);
364: 
365:             foreach ($this->children as $child) {
366:                 $child->parent = $node;
367:                 $node->addChild($child->getNode());
368:             }
369:         } else {
370:             $node = new PrototypedArrayNode($this->name, $this->parent);
371: 
372:             $this->validatePrototypeNode($node);
373: 
374:             if (null !== $this->key) {
375:                 $node->setKeyAttribute($this->key, $this->removeKeyItem);
376:             }
377: 
378:             if (true === $this->atLeastOne) {
379:                 $node->setMinNumberOfElements(1);
380:             }
381: 
382:             if ($this->default) {
383:                 $node->setDefaultValue($this->defaultValue);
384:             }
385: 
386:             if (false !== $this->addDefaultChildren) {
387:                 $node->setAddChildrenIfNoneSet($this->addDefaultChildren);
388:                 if ($this->prototype instanceof static && null === $this->prototype->prototype) {
389:                     $this->prototype->addDefaultsIfNotSet();
390:                 }
391:             }
392: 
393:             $this->prototype->parent = $node;
394:             $node->setPrototype($this->prototype->getNode());
395:         }
396: 
397:         $node->setAllowNewKeys($this->allowNewKeys);
398:         $node->addEquivalentValue(null, $this->nullEquivalent);
399:         $node->addEquivalentValue(true, $this->trueEquivalent);
400:         $node->addEquivalentValue(false, $this->falseEquivalent);
401:         $node->setPerformDeepMerging($this->performDeepMerging);
402:         $node->setRequired($this->required);
403:         $node->setIgnoreExtraKeys($this->ignoreExtraKeys);
404:         $node->setNormalizeKeys($this->normalizeKeys);
405: 
406:         if (null !== $this->normalization) {
407:             $node->setNormalizationClosures($this->normalization->before);
408:             $node->setXmlRemappings($this->normalization->remappings);
409:         }
410: 
411:         if (null !== $this->merge) {
412:             $node->setAllowOverwrite($this->merge->allowOverwrite);
413:             $node->setAllowFalse($this->merge->allowFalse);
414:         }
415: 
416:         if (null !== $this->validation) {
417:             $node->setFinalValidationClosures($this->validation->rules);
418:         }
419: 
420:         return $node;
421:     }
422: 
423:     /**
424:      * Validate the configuration of a concrete node.
425:      *
426:      * @param ArrayNode $node The related node
427:      *
428:      * @throws InvalidDefinitionException
429:      */
430:     protected function validateConcreteNode(ArrayNode $node)
431:     {
432:         $path = $node->getPath();
433: 
434:         if (null !== $this->key) {
435:             throw new InvalidDefinitionException(
436:                 sprintf('->useAttributeAsKey() is not applicable to concrete nodes at path "%s"', $path)
437:             );
438:         }
439: 
440:         if (true === $this->atLeastOne) {
441:             throw new InvalidDefinitionException(
442:                 sprintf('->requiresAtLeastOneElement() is not applicable to concrete nodes at path "%s"', $path)
443:             );
444:         }
445: 
446:         if ($this->default) {
447:             throw new InvalidDefinitionException(
448:                 sprintf('->defaultValue() is not applicable to concrete nodes at path "%s"', $path)
449:             );
450:         }
451: 
452:         if (false !== $this->addDefaultChildren) {
453:             throw new InvalidDefinitionException(
454:                 sprintf('->addDefaultChildrenIfNoneSet() is not applicable to concrete nodes at path "%s"', $path)
455:             );
456:         }
457:     }
458: 
459:     /**
460:      * Validate the configuration of a prototype node.
461:      *
462:      * @param PrototypedArrayNode $node The related node
463:      *
464:      * @throws InvalidDefinitionException
465:      */
466:     protected function validatePrototypeNode(PrototypedArrayNode $node)
467:     {
468:         $path = $node->getPath();
469: 
470:         if ($this->addDefaults) {
471:             throw new InvalidDefinitionException(
472:                 sprintf('->addDefaultsIfNotSet() is not applicable to prototype nodes at path "%s"', $path)
473:             );
474:         }
475: 
476:         if (false !== $this->addDefaultChildren) {
477:             if ($this->default) {
478:                 throw new InvalidDefinitionException(
479:                     sprintf('A default value and default children might not be used together at path "%s"', $path)
480:                 );
481:             }
482: 
483:             if (null !== $this->key && (null === $this->addDefaultChildren || is_integer($this->addDefaultChildren) && $this->addDefaultChildren > 0)) {
484:                 throw new InvalidDefinitionException(
485:                     sprintf('->addDefaultChildrenIfNoneSet() should set default children names as ->useAttributeAsKey() is used at path "%s"', $path)
486:                 );
487:             }
488: 
489:             if (null === $this->key && (is_string($this->addDefaultChildren) || is_array($this->addDefaultChildren))) {
490:                 throw new InvalidDefinitionException(
491:                     sprintf('->addDefaultChildrenIfNoneSet() might not set default children names as ->useAttributeAsKey() is not used at path "%s"', $path)
492:                 );
493:             }
494:         }
495:     }
496: }
497: 
php-coveralls API documentation generated by ApiGen 2.8.0