Verzeichnisstruktur phpBB-3.2.0


Veröffentlicht
06.01.2017

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:56 - Dateigröße: 9.76 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 = false;
029      protected $minNumberOfElements = 0;
030      protected $defaultValue = array();
031      protected $defaultChildren;
032   
033      /**
034       * Sets the minimum number of elements that a prototype based node must
035       * contain. By default this is zero, meaning no elements.
036       *
037       * @param int $number
038       */
039      public function setMinNumberOfElements($number)
040      {
041          $this->minNumberOfElements = $number;
042      }
043   
044      /**
045       * Sets the attribute which value is to be used as key.
046       *
047       * This is useful when you have an indexed array that should be an
048       * associative array. You can select an item from within the array
049       * to be the key of the particular item. For example, if "id" is the
050       * "key", then:
051       *
052       *     array(
053       *         array('id' => 'my_name', 'foo' => 'bar'),
054       *     );
055       *
056       *  becomes
057       *
058       *      array(
059       *          'my_name' => array('foo' => 'bar'),
060       *      );
061       *
062       * If you'd like "'id' => 'my_name'" to still be present in the resulting
063       * array, then you can set the second argument of this method to false.
064       *
065       * @param string $attribute The name of the attribute which value is to be used as a key
066       * @param bool   $remove    Whether or not to remove the key
067       */
068      public function setKeyAttribute($attribute, $remove = true)
069      {
070          $this->keyAttribute = $attribute;
071          $this->removeKeyAttribute = $remove;
072      }
073   
074      /**
075       * Retrieves the name of the attribute which value should be used as key.
076       *
077       * @return string The name of the attribute
078       */
079      public function getKeyAttribute()
080      {
081          return $this->keyAttribute;
082      }
083   
084      /**
085       * Sets the default value of this node.
086       *
087       * @param string $value
088       *
089       * @throws \InvalidArgumentException if the default value is not an array
090       */
091      public function setDefaultValue($value)
092      {
093          if (!is_array($value)) {
094              throw new \InvalidArgumentException($this->getPath().': the default value of an array node has to be an array.');
095          }
096   
097          $this->defaultValue = $value;
098      }
099   
100      /**
101       * Checks if the node has a default value.
102       *
103       * @return bool
104       */
105      public function hasDefaultValue()
106      {
107          return true;
108      }
109   
110      /**
111       * Adds default children when none are set.
112       *
113       * @param int|string|array|null $children The number of children|The child name|The children names to be added
114       */
115      public function setAddChildrenIfNoneSet($children = array('defaults'))
116      {
117          if (null === $children) {
118              $this->defaultChildren = array('defaults');
119          } else {
120              $this->defaultChildren = is_int($children) && $children > 0 ? range(1, $children) : (array) $children;
121          }
122      }
123   
124      /**
125       * Retrieves the default value.
126       *
127       * The default value could be either explicited or derived from the prototype
128       * default value.
129       *
130       * @return array The default value
131       */
132      public function getDefaultValue()
133      {
134          if (null !== $this->defaultChildren) {
135              $default = $this->prototype->hasDefaultValue() ? $this->prototype->getDefaultValue() : array();
136              $defaults = array();
137              foreach (array_values($this->defaultChildren) as $i => $name) {
138                  $defaults[null === $this->keyAttribute ? $i : $name] = $default;
139              }
140   
141              return $defaults;
142          }
143   
144          return $this->defaultValue;
145      }
146   
147      /**
148       * Sets the node prototype.
149       *
150       * @param PrototypeNodeInterface $node
151       */
152      public function setPrototype(PrototypeNodeInterface $node)
153      {
154          $this->prototype = $node;
155      }
156   
157      /**
158       * Retrieves the prototype.
159       *
160       * @return PrototypeNodeInterface The prototype
161       */
162      public function getPrototype()
163      {
164          return $this->prototype;
165      }
166   
167      /**
168       * Disable adding concrete children for prototyped nodes.
169       *
170       * @param NodeInterface $node The child node to add
171       *
172       * @throws Exception
173       */
174      public function addChild(NodeInterface $node)
175      {
176          throw new Exception('A prototyped array node can not have concrete children.');
177      }
178   
179      /**
180       * Finalizes the value of this node.
181       *
182       * @param mixed $value
183       *
184       * @return mixed The finalized value
185       *
186       * @throws UnsetKeyException
187       * @throws InvalidConfigurationException if the node doesn't have enough children
188       */
189      protected function finalizeValue($value)
190      {
191          if (false === $value) {
192              $msg = sprintf('Unsetting key for path "%s", value: %s', $this->getPath(), json_encode($value));
193              throw new UnsetKeyException($msg);
194          }
195   
196          foreach ($value as $k => $v) {
197              $this->prototype->setName($k);
198              try {
199                  $value[$k] = $this->prototype->finalize($v);
200              } catch (UnsetKeyException $e) {
201                  unset($value[$k]);
202              }
203          }
204   
205          if (count($value) < $this->minNumberOfElements) {
206              $msg = sprintf('The path "%s" should have at least %d element(s) defined.', $this->getPath(), $this->minNumberOfElements);
207              $ex = new InvalidConfigurationException($msg);
208              $ex->setPath($this->getPath());
209   
210              throw $ex;
211          }
212   
213          return $value;
214      }
215   
216      /**
217       * Normalizes the value.
218       *
219       * @param mixed $value The value to normalize
220       *
221       * @return mixed The normalized value
222       *
223       * @throws InvalidConfigurationException
224       * @throws DuplicateKeyException
225       */
226      protected function normalizeValue($value)
227      {
228          if (false === $value) {
229              return $value;
230          }
231   
232          $value = $this->remapXml($value);
233   
234          $isAssoc = array_keys($value) !== range(0, count($value) - 1);
235          $normalized = array();
236          foreach ($value as $k => $v) {
237              if (null !== $this->keyAttribute && is_array($v)) {
238                  if (!isset($v[$this->keyAttribute]) && is_int($k) && !$isAssoc) {
239                      $msg = sprintf('The attribute "%s" must be set for path "%s".', $this->keyAttribute, $this->getPath());
240                      $ex = new InvalidConfigurationException($msg);
241                      $ex->setPath($this->getPath());
242   
243                      throw $ex;
244                  } elseif (isset($v[$this->keyAttribute])) {
245                      $k = $v[$this->keyAttribute];
246   
247                      // remove the key attribute when required
248                      if ($this->removeKeyAttribute) {
249                          unset($v[$this->keyAttribute]);
250                      }
251   
252                      // if only "value" is left
253                      if (1 == count($v) && isset($v['value'])) {
254                          $v = $v['value'];
255                      }
256                  }
257   
258                  if (array_key_exists($k, $normalized)) {
259                      $msg = sprintf('Duplicate key "%s" for path "%s".', $k, $this->getPath());
260                      $ex = new DuplicateKeyException($msg);
261                      $ex->setPath($this->getPath());
262   
263                      throw $ex;
264                  }
265              }
266   
267              $this->prototype->setName($k);
268              if (null !== $this->keyAttribute || $isAssoc) {
269                  $normalized[$k] = $this->prototype->normalize($v);
270              } else {
271                  $normalized[] = $this->prototype->normalize($v);
272              }
273          }
274   
275          return $normalized;
276      }
277   
278      /**
279       * Merges values together.
280       *
281       * @param mixed $leftSide  The left side to merge
282       * @param mixed $rightSide The right side to merge
283       *
284       * @return mixed The merged values
285       *
286       * @throws InvalidConfigurationException
287       * @throws \RuntimeException
288       */
289      protected function mergeValues($leftSide, $rightSide)
290      {
291          if (false === $rightSide) {
292              // if this is still false after the last config has been merged the
293              // finalization pass will take care of removing this key entirely
294              return false;
295          }
296   
297          if (false === $leftSide || !$this->performDeepMerging) {
298              return $rightSide;
299          }
300   
301          foreach ($rightSide as $k => $v) {
302              // prototype, and key is irrelevant, so simply append the element
303              if (null === $this->keyAttribute) {
304                  $leftSide[] = $v;
305                  continue;
306              }
307   
308              // no conflict
309              if (!array_key_exists($k, $leftSide)) {
310                  if (!$this->allowNewKeys) {
311                      $ex = new InvalidConfigurationException(sprintf(
312                          'You are not allowed to define new elements for path "%s". '.
313                          'Please define all elements for this path in one config file.',
314                          $this->getPath()
315                      ));
316                      $ex->setPath($this->getPath());
317   
318                      throw $ex;
319                  }
320   
321                  $leftSide[$k] = $v;
322                  continue;
323              }
324   
325              $this->prototype->setName($k);
326              $leftSide[$k] = $this->prototype->merge($leftSide[$k], $v);
327          }
328   
329          return $leftSide;
330      }
331  }
332