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.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

StaticPrefixCollection.php

Zuletzt modifiziert: 02.04.2025, 15:03 - Dateigröße: 6.18 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\Routing\Matcher\Dumper;
013   
014  /**
015   * Prefix tree of routes preserving routes order.
016   *
017   * @author Frank de Jonge <info@frankdejonge.nl>
018   *
019   * @internal
020   */
021  class StaticPrefixCollection
022  {
023      /**
024       * @var string
025       */
026      private $prefix;
027   
028      /**
029       * @var array[]|StaticPrefixCollection[]
030       */
031      private $items = [];
032   
033      /**
034       * @var int
035       */
036      private $matchStart = 0;
037   
038      public function __construct($prefix = '')
039      {
040          $this->prefix = $prefix;
041      }
042   
043      public function getPrefix()
044      {
045          return $this->prefix;
046      }
047   
048      /**
049       * @return mixed[]|StaticPrefixCollection[]
050       */
051      public function getItems()
052      {
053          return $this->items;
054      }
055   
056      /**
057       * Adds a route to a group.
058       *
059       * @param string $prefix
060       * @param mixed  $route
061       */
062      public function addRoute($prefix, $route)
063      {
064          $prefix = '/' === $prefix ? $prefix : rtrim($prefix, '/');
065          $this->guardAgainstAddingNotAcceptedRoutes($prefix);
066   
067          if ($this->prefix === $prefix) {
068              // When a prefix is exactly the same as the base we move up the match start position.
069              // This is needed because otherwise routes that come afterwards have higher precedence
070              // than a possible regular expression, which goes against the input order sorting.
071              $this->items[] = [$prefix, $route];
072              $this->matchStart = \count($this->items);
073   
074              return;
075          }
076   
077          foreach ($this->items as $i => $item) {
078              if ($i < $this->matchStart) {
079                  continue;
080              }
081   
082              if ($item instanceof self && $item->accepts($prefix)) {
083                  $item->addRoute($prefix, $route);
084   
085                  return;
086              }
087   
088              $group = $this->groupWithItem($item, $prefix, $route);
089   
090              if ($group instanceof self) {
091                  $this->items[$i] = $group;
092   
093                  return;
094              }
095          }
096   
097          // No optimised case was found, in this case we simple add the route for possible
098          // grouping when new routes are added.
099          $this->items[] = [$prefix, $route];
100      }
101   
102      /**
103       * Tries to combine a route with another route or group.
104       *
105       * @param StaticPrefixCollection|array $item
106       * @param string                       $prefix
107       * @param mixed                        $route
108       *
109       * @return StaticPrefixCollection|null
110       */
111      private function groupWithItem($item, $prefix, $route)
112      {
113          $itemPrefix = $item instanceof self ? $item->prefix : $item[0];
114          $commonPrefix = $this->detectCommonPrefix($prefix, $itemPrefix);
115   
116          if (!$commonPrefix) {
117              return null;
118          }
119   
120          $child = new self($commonPrefix);
121   
122          if ($item instanceof self) {
123              $child->items = [$item];
124          } else {
125              $child->addRoute($item[0], $item[1]);
126          }
127   
128          $child->addRoute($prefix, $route);
129   
130          return $child;
131      }
132   
133      /**
134       * Checks whether a prefix can be contained within the group.
135       *
136       * @param string $prefix
137       *
138       * @return bool Whether a prefix could belong in a given group
139       */
140      private function accepts($prefix)
141      {
142          return '' === $this->prefix || 0 === strpos($prefix, $this->prefix);
143      }
144   
145      /**
146       * Detects whether there's a common prefix relative to the group prefix and returns it.
147       *
148       * @param string $prefix
149       * @param string $anotherPrefix
150       *
151       * @return false|string A common prefix, longer than the base/group prefix, or false when none available
152       */
153      private function detectCommonPrefix($prefix, $anotherPrefix)
154      {
155          $baseLength = \strlen($this->prefix);
156          $commonLength = $baseLength;
157          $end = min(\strlen($prefix), \strlen($anotherPrefix));
158   
159          for ($i = $baseLength; $i <= $end; ++$i) {
160              if (substr($prefix, 0, $i) !== substr($anotherPrefix, 0, $i)) {
161                  break;
162              }
163   
164              $commonLength = $i;
165          }
166   
167          $commonPrefix = rtrim(substr($prefix, 0, $commonLength), '/');
168   
169          if (\strlen($commonPrefix) > $baseLength) {
170              return $commonPrefix;
171          }
172   
173          return false;
174      }
175   
176      /**
177       * Optimizes the tree by inlining items from groups with less than 3 items.
178       */
179      public function optimizeGroups()
180      {
181          $index = -1;
182   
183          while (isset($this->items[++$index])) {
184              $item = $this->items[$index];
185   
186              if ($item instanceof self) {
187                  $item->optimizeGroups();
188   
189                  // When a group contains only two items there's no reason to optimize because at minimum
190                  // the amount of prefix check is 2. In this case inline the group.
191                  if ($item->shouldBeInlined()) {
192                      array_splice($this->items, $index, 1, $item->items);
193   
194                      // Lower index to pass through the same index again after optimizing.
195                      // The first item of the replacements might be a group needing optimization.
196                      --$index;
197                  }
198              }
199          }
200      }
201   
202      private function shouldBeInlined()
203      {
204          if (\count($this->items) >= 3) {
205              return false;
206          }
207   
208          foreach ($this->items as $item) {
209              if ($item instanceof self) {
210                  return true;
211              }
212          }
213   
214          foreach ($this->items as $item) {
215              if (\is_array($item) && $item[0] === $this->prefix) {
216                  return false;
217              }
218          }
219   
220          return true;
221      }
222   
223      /**
224       * Guards against adding incompatible prefixes in a group.
225       *
226       * @param string $prefix
227       *
228       * @throws \LogicException when a prefix does not belong in a group
229       */
230      private function guardAgainstAddingNotAcceptedRoutes($prefix)
231      {
232          if (!$this->accepts($prefix)) {
233              $message = sprintf('Could not add route with prefix %s to collection with prefix %s', $prefix, $this->prefix);
234   
235              throw new \LogicException($message);
236          }
237      }
238  }
239