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

  • ArrayNode
  • BaseNode
  • BooleanNode
  • EnumNode
  • FloatNode
  • IntegerNode
  • NumericNode
  • Processor
  • PrototypedArrayNode
  • ReferenceDumper
  • ScalarNode
  • VariableNode

Interfaces

  • ConfigurationInterface
  • NodeInterface
  • PrototypeNodeInterface
  • 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;
 13: 
 14: use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
 15: use Symfony\Component\Config\Definition\Exception\DuplicateKeyException;
 16: use Symfony\Component\Config\Definition\Exception\UnsetKeyException;
 17: use Symfony\Component\Config\Definition\Exception\Exception;
 18: 
 19: /**
 20:  * Represents a prototyped Array node in the config tree.
 21:  *
 22:  * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 23:  */
 24: class PrototypedArrayNode extends ArrayNode
 25: {
 26:     protected $prototype;
 27:     protected $keyAttribute;
 28:     protected $removeKeyAttribute;
 29:     protected $minNumberOfElements;
 30:     protected $defaultValue;
 31:     protected $defaultChildren;
 32: 
 33:     /**
 34:      * Constructor.
 35:      *
 36:      * @param string        $name   The Node's name
 37:      * @param NodeInterface $parent The node parent
 38:      */
 39:     public function __construct($name, NodeInterface $parent = null)
 40:     {
 41:         parent::__construct($name, $parent);
 42: 
 43:         $this->minNumberOfElements = 0;
 44:         $this->defaultValue = array();
 45:     }
 46: 
 47:     /**
 48:      * Sets the minimum number of elements that a prototype based node must
 49:      * contain. By default this is zero, meaning no elements.
 50:      *
 51:      * @param integer $number
 52:      */
 53:     public function setMinNumberOfElements($number)
 54:     {
 55:         $this->minNumberOfElements = $number;
 56:     }
 57: 
 58:     /**
 59:      * Sets the attribute which value is to be used as key.
 60:      *
 61:      * This is useful when you have an indexed array that should be an
 62:      * associative array. You can select an item from within the array
 63:      * to be the key of the particular item. For example, if "id" is the
 64:      * "key", then:
 65:      *
 66:      *     array(
 67:      *         array('id' => 'my_name', 'foo' => 'bar'),
 68:      *     );
 69:      *
 70:      *  becomes
 71:      *
 72:      *      array(
 73:      *          'my_name' => array('foo' => 'bar'),
 74:      *      );
 75:      *
 76:      * If you'd like "'id' => 'my_name'" to still be present in the resulting
 77:      * array, then you can set the second argument of this method to false.
 78:      *
 79:      * @param string  $attribute The name of the attribute which value is to be used as a key
 80:      * @param Boolean $remove    Whether or not to remove the key
 81:      */
 82:     public function setKeyAttribute($attribute, $remove = true)
 83:     {
 84:         $this->keyAttribute = $attribute;
 85:         $this->removeKeyAttribute = $remove;
 86:     }
 87: 
 88:     /**
 89:      * Retrieves the name of the attribute which value should be used as key.
 90:      *
 91:      * @return string The name of the attribute
 92:      */
 93:     public function getKeyAttribute()
 94:     {
 95:         return $this->keyAttribute;
 96:     }
 97: 
 98:     /**
 99:      * Sets the default value of this node.
100:      *
101:      * @param string $value
102:      *
103:      * @throws \InvalidArgumentException if the default value is not an array
104:      */
105:     public function setDefaultValue($value)
106:     {
107:         if (!is_array($value)) {
108:             throw new \InvalidArgumentException($this->getPath().': the default value of an array node has to be an array.');
109:         }
110: 
111:         $this->defaultValue = $value;
112:     }
113: 
114:     /**
115:      * Checks if the node has a default value.
116:      *
117:      * @return Boolean
118:      */
119:     public function hasDefaultValue()
120:     {
121:         return true;
122:     }
123: 
124:     /**
125:      * Adds default children when none are set.
126:      *
127:      * @param integer|string|array|null $children The number of children|The child name|The children names to be added
128:      */
129:     public function setAddChildrenIfNoneSet($children = array('defaults'))
130:     {
131:         if (null === $children) {
132:             $this->defaultChildren = array('defaults');
133:         } else {
134:             $this->defaultChildren = is_integer($children) && $children > 0 ? range(1, $children) : (array) $children;
135:         }
136:     }
137: 
138:     /**
139:      * Retrieves the default value.
140:      *
141:      * The default value could be either explicited or derived from the prototype
142:      * default value.
143:      *
144:      * @return array The default value
145:      */
146:     public function getDefaultValue()
147:     {
148:         if (null !== $this->defaultChildren) {
149:             $default = $this->prototype->hasDefaultValue() ? $this->prototype->getDefaultValue() : array();
150:             $defaults = array();
151:             foreach (array_values($this->defaultChildren) as $i => $name) {
152:                 $defaults[null === $this->keyAttribute ? $i : $name] = $default;
153:             }
154: 
155:             return $defaults;
156:         }
157: 
158:         return $this->defaultValue;
159:     }
160: 
161:     /**
162:      * Sets the node prototype.
163:      *
164:      * @param PrototypeNodeInterface $node
165:      */
166:     public function setPrototype(PrototypeNodeInterface $node)
167:     {
168:         $this->prototype = $node;
169:     }
170: 
171:     /**
172:      * Retrieves the prototype
173:      *
174:      * @return PrototypeNodeInterface The prototype
175:      */
176:     public function getPrototype()
177:     {
178:         return $this->prototype;
179:     }
180: 
181:     /**
182:      * Disable adding concrete children for prototyped nodes.
183:      *
184:      * @param NodeInterface $node The child node to add
185:      *
186:      * @throws Exception
187:      */
188:     public function addChild(NodeInterface $node)
189:     {
190:         throw new Exception('A prototyped array node can not have concrete children.');
191:     }
192: 
193:     /**
194:      * Finalizes the value of this node.
195:      *
196:      * @param mixed $value
197:      *
198:      * @return mixed The finalized value
199:      *
200:      * @throws UnsetKeyException
201:      * @throws InvalidConfigurationException if the node doesn't have enough children
202:      */
203:     protected function finalizeValue($value)
204:     {
205:         if (false === $value) {
206:             $msg = sprintf('Unsetting key for path "%s", value: %s', $this->getPath(), json_encode($value));
207:             throw new UnsetKeyException($msg);
208:         }
209: 
210:         foreach ($value as $k => $v) {
211:             $this->prototype->setName($k);
212:             try {
213:                 $value[$k] = $this->prototype->finalize($v);
214:             } catch (UnsetKeyException $unset) {
215:                 unset($value[$k]);
216:             }
217:         }
218: 
219:         if (count($value) < $this->minNumberOfElements) {
220:             $msg = sprintf('The path "%s" should have at least %d element(s) defined.', $this->getPath(), $this->minNumberOfElements);
221:             $ex = new InvalidConfigurationException($msg);
222:             $ex->setPath($this->getPath());
223: 
224:             throw $ex;
225:         }
226: 
227:         return $value;
228:     }
229: 
230:     /**
231:      * Normalizes the value.
232:      *
233:      * @param mixed $value The value to normalize
234:      *
235:      * @return mixed The normalized value
236:      *
237:      * @throws InvalidConfigurationException
238:      * @throws DuplicateKeyException
239:      */
240:     protected function normalizeValue($value)
241:     {
242:         if (false === $value) {
243:             return $value;
244:         }
245: 
246:         $value = $this->remapXml($value);
247: 
248:         $isAssoc = array_keys($value) !== range(0, count($value) -1);
249:         $normalized = array();
250:         foreach ($value as $k => $v) {
251:             if (null !== $this->keyAttribute && is_array($v)) {
252:                 if (!isset($v[$this->keyAttribute]) && is_int($k) && !$isAssoc) {
253:                     $msg = sprintf('The attribute "%s" must be set for path "%s".', $this->keyAttribute, $this->getPath());
254:                     $ex = new InvalidConfigurationException($msg);
255:                     $ex->setPath($this->getPath());
256: 
257:                     throw $ex;
258:                 } elseif (isset($v[$this->keyAttribute])) {
259:                     $k = $v[$this->keyAttribute];
260: 
261:                     // remove the key attribute when required
262:                     if ($this->removeKeyAttribute) {
263:                         unset($v[$this->keyAttribute]);
264:                     }
265: 
266:                     // if only "value" is left
267:                     if (1 == count($v) && isset($v['value'])) {
268:                         $v = $v['value'];
269:                     }
270:                 }
271: 
272:                 if (array_key_exists($k, $normalized)) {
273:                     $msg = sprintf('Duplicate key "%s" for path "%s".', $k, $this->getPath());
274:                     $ex = new DuplicateKeyException($msg);
275:                     $ex->setPath($this->getPath());
276: 
277:                     throw $ex;
278:                 }
279:             }
280: 
281:             $this->prototype->setName($k);
282:             if (null !== $this->keyAttribute || $isAssoc) {
283:                 $normalized[$k] = $this->prototype->normalize($v);
284:             } else {
285:                 $normalized[] = $this->prototype->normalize($v);
286:             }
287:         }
288: 
289:         return $normalized;
290:     }
291: 
292:     /**
293:      * Merges values together.
294:      *
295:      * @param mixed $leftSide  The left side to merge.
296:      * @param mixed $rightSide The right side to merge.
297:      *
298:      * @return mixed The merged values
299:      *
300:      * @throws InvalidConfigurationException
301:      * @throws \RuntimeException
302:      */
303:     protected function mergeValues($leftSide, $rightSide)
304:     {
305:         if (false === $rightSide) {
306:             // if this is still false after the last config has been merged the
307:             // finalization pass will take care of removing this key entirely
308:             return false;
309:         }
310: 
311:         if (false === $leftSide || !$this->performDeepMerging) {
312:             return $rightSide;
313:         }
314: 
315:         foreach ($rightSide as $k => $v) {
316:             // prototype, and key is irrelevant, so simply append the element
317:             if (null === $this->keyAttribute) {
318:                 $leftSide[] = $v;
319:                 continue;
320:             }
321: 
322:             // no conflict
323:             if (!array_key_exists($k, $leftSide)) {
324:                 if (!$this->allowNewKeys) {
325:                     $ex = new InvalidConfigurationException(sprintf(
326:                         'You are not allowed to define new elements for path "%s". ' .
327:                         'Please define all elements for this path in one config file.',
328:                         $this->getPath()
329:                     ));
330:                     $ex->setPath($this->getPath());
331: 
332:                     throw $ex;
333:                 }
334: 
335:                 $leftSide[$k] = $v;
336:                 continue;
337:             }
338: 
339:             $this->prototype->setName($k);
340:             $leftSide[$k] = $this->prototype->merge($leftSide[$k], $v);
341:         }
342: 
343:         return $leftSide;
344:     }
345: }
346: 
php-coveralls API documentation generated by ApiGen 2.8.0