Verzeichnisstruktur phpBB-3.1.0


Veröffentlicht
27.10.2014

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

PrototypedArrayNode.php

Zuletzt modifiziert: 09.10.2024, 12:58 - Dateigröße: 10.10 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;
013   
014  use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
015  use Symfony\Component\Config\Definition\Exception\DuplicateKeyException;
016  use Symfony\Component\Config\Definition\Exception\UnsetKeyException;
017  use Symfony\Component\Config\Definition\Exception\Exception;
018   
019  /**
020   * Represents a prototyped Array node in the config tree.
021   *
022   * @author Johannes M. Schmitt <schmittjoh@gmail.com>
023   */
024  class PrototypedArrayNode extends ArrayNode
025  {
026      protected $prototype;
027      protected $keyAttribute;
028      protected $removeKeyAttribute;
029      protected $minNumberOfElements;
030      protected $defaultValue;
031      protected $defaultChildren;
032   
033      /**
034       * Constructor.
035       *
036       * @param string        $name   The Node's name
037       * @param NodeInterface $parent The node parent
038       */
039      public function __construct($name, NodeInterface $parent = null)
040      {
041          parent::__construct($name, $parent);
042   
043          $this->minNumberOfElements = 0;
044          $this->defaultValue = array();
045      }
046   
047      /**
048       * Sets the minimum number of elements that a prototype based node must
049       * contain. By default this is zero, meaning no elements.
050       *
051       * @param int     $number
052       */
053      public function setMinNumberOfElements($number)
054      {
055          $this->minNumberOfElements = $number;
056      }
057   
058      /**
059       * Sets the attribute which value is to be used as key.
060       *
061       * This is useful when you have an indexed array that should be an
062       * associative array. You can select an item from within the array
063       * to be the key of the particular item. For example, if "id" is the
064       * "key", then:
065       *
066       *     array(
067       *         array('id' => 'my_name', 'foo' => 'bar'),
068       *     );
069       *
070       *  becomes
071       *
072       *      array(
073       *          'my_name' => array('foo' => 'bar'),
074       *      );
075       *
076       * If you'd like "'id' => 'my_name'" to still be present in the resulting
077       * array, then you can set the second argument of this method to false.
078       *
079       * @param string  $attribute The name of the attribute which value is to be used as a key
080       * @param bool    $remove    Whether or not to remove the key
081       */
082      public function setKeyAttribute($attribute, $remove = true)
083      {
084          $this->keyAttribute = $attribute;
085          $this->removeKeyAttribute = $remove;
086      }
087   
088      /**
089       * Retrieves the name of the attribute which value should be used as key.
090       *
091       * @return string The name of the attribute
092       */
093      public function getKeyAttribute()
094      {
095          return $this->keyAttribute;
096      }
097   
098      /**
099       * 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 bool
118       */
119      public function hasDefaultValue()
120      {
121          return true;
122      }
123   
124      /**
125       * Adds default children when none are set.
126       *
127       * @param int|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