‪TYPO3CMS  10.4
RouteSorter.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
25 {
26  protected const ‪EARLIER = -1;
27  protected const ‪LATER = 1;
28 
32  protected ‪$routes = [];
33 
37  protected $originalParameters = [];
38 
42  public function getRoutes(): array
43  {
44  return ‪$this->routes;
45  }
46 
47  public function ‪withRoutes(array ‪$routes): self
48  {
49  $target = clone $this;
50  $target->routes = ‪$routes;
51  return $target;
52  }
53 
54  public function ‪withOriginalParameters(array $originalParameters): self
55  {
56  $target = clone $this;
57  $target->originalParameters = $originalParameters;
58  return $target;
59  }
60 
61  public function ‪sortRoutesForGeneration(): self
62  {
63  \uasort($this->‪routes, [$this, 'compareForGeneration']);
64  return $this;
65  }
66 
67  protected function ‪compareForGeneration(‪Route $self, ‪Route $other): int
68  {
69  // default routes (e.g `/my-page`) -> process later
70  return $this->‪compareDefaultRoutes($self, $other, self::LATER)
71  // no variables (e.g. `/my-page/list`) -> process later
72  ?? $this->‪compareStaticRoutes($self, $other, self::LATER)
73  // all variables complete -> process earlier
74  ?? $this->‪compareAllVariablesPresence($self, $other, self::EARLIER)
75  // mandatory variables complete -> process earlier
76  ?? $this->‪compareMandatoryVariablesPresence($self, $other, self::EARLIER)
77  // more missing variable defaults -> process later
78  ?? $this->‪compareMissingDefaultsAmount($self, $other, self::LATER)
79  // more variable defaults -> process later
80  ?? $this->‪compareDefaultsAmount($self, $other, self::LATER)
81  // hm, dunno -> keep position
82  ?? 0;
83  }
84 
85  protected function ‪compareDefaultRoutes(‪Route $self, ‪Route $other, int $action = self::LATER): ?int
86  {
87  $selfIsDefaultRoute = (bool)$self->getOption('_isDefault');
88  $otherIsDefaultRoute = (bool)$other->getOption('_isDefault');
89  // both are default routes, keep order
90  if ($selfIsDefaultRoute && $otherIsDefaultRoute) {
91  return 0;
92  }
93  // $self is default route, sort $self after $other
94  if ($selfIsDefaultRoute && !$otherIsDefaultRoute) {
95  return $action;
96  }
97  // $other is default route, sort $self before $other
98  if (!$selfIsDefaultRoute && $otherIsDefaultRoute) {
99  return -$action;
100  }
101  return null;
102  }
103 
104  protected function ‪compareStaticRoutes(‪Route $self, ‪Route $other, int $action = self::LATER): ?int
105  {
106  $selfVariableNames = $self->compile()->getPathVariables();
107  $otherVariableNames = $other->compile()->getPathVariables();
108  if ($selfVariableNames === [] && $otherVariableNames === []) {
109  return 0;
110  }
111  if ($selfVariableNames === [] && $otherVariableNames !== []) {
112  return $action;
113  }
114  if ($selfVariableNames !== [] && $otherVariableNames === []) {
115  return -$action;
116  }
117  return null;
118  }
119 
120  protected function ‪compareAllVariablesPresence(‪Route $self, ‪Route $other, int $action = self::EARLIER): ?int
121  {
122  $selfVariables = $this->getAllRouteVariables($self);
123  $otherVariables = $this->getAllRouteVariables($other);
124  $missingSelfVariables = \array_diff_key(
125  $selfVariables,
126  $this->getRouteParameters($self)
127  );
128  $missingOtherVariables = \array_diff_key(
129  $otherVariables,
130  $this->getRouteParameters($other)
131  );
132  if ($missingSelfVariables === [] && $missingOtherVariables === []) {
133  $difference = \count($selfVariables) - \count($otherVariables);
134  return $difference * $action;
135  }
136  if ($missingSelfVariables === [] && $missingOtherVariables !== []) {
137  return $action;
138  }
139  if ($missingSelfVariables !== [] && $missingOtherVariables === []) {
140  return -$action;
141  }
142  return null;
143  }
144 
145  protected function ‪compareMandatoryVariablesPresence(‪Route $self, ‪Route $other, int $action = self::EARLIER): ?int
146  {
147  $missingSelfVariables = \array_diff_key(
148  $this->getMandatoryRouteVariables($self),
149  $this->getRouteParameters($self)
150  );
151  $missingOtherVariables = \array_diff_key(
152  $this->getMandatoryRouteVariables($other),
153  $this->getRouteParameters($other)
154  );
155  if ($missingSelfVariables === [] && $missingOtherVariables !== []) {
156  return $action;
157  }
158  if ($missingSelfVariables !== [] && $missingOtherVariables === []) {
159  return -$action;
160  }
161  return null;
162  }
163 
164  protected function ‪compareMissingDefaultsAmount(‪Route $self, ‪Route $other, int $action = self::LATER): ?int
165  {
166  $missingSelfDefaults = \array_diff_key(
167  $this->getActualRouteDefaults($self),
168  $this->getRouteParameters($self)
169  );
170  $missingOtherDefaults = \array_diff_key(
171  $this->getActualRouteDefaults($other),
172  $this->getRouteParameters($other)
173  );
174  $difference = \count($missingSelfDefaults) - \count($missingOtherDefaults);
175  // return `null` in case of equality (`0`)
176  return $difference === 0 ? null : $difference * $action;
177  }
178 
179  protected function ‪compareDefaultsAmount(‪Route $self, ‪Route $other, int $action = self::LATER): ?int
180  {
181  $selfDefaults = $this->getActualRouteDefaults($self);
182  $otherDefaults = $this->getActualRouteDefaults($other);
183  $difference = \count($selfDefaults) - \count($otherDefaults);
184  // return `null` in case of equality (`0`)
185  return $difference === 0 ? null : $difference * $action;
186  }
187 
194  protected function getActualRouteDefaults(Route $route): array
195  {
196  return array_intersect_key(
197  $route->getDefaults(),
198  array_flip($route->compile()->getPathVariables())
199  );
200  }
201 
206  protected function getAllRouteVariables(Route $route): array
207  {
208  return array_flip($route->compile()->getPathVariables());
209  }
210 
215  protected function getMandatoryRouteVariables(Route $route): array
216  {
217  return \array_diff_key(
218  $this->getAllRouteVariables($route),
219  $route->getDefaults()
220  );
221  }
222 
227  protected function getRouteParameters(Route $route): array
228  {
229  // $originalParameters is used used as fallback
230  // (custom enhancers should have processed and deflated parameters)
231  return $route->getOption('deflatedParameters') ?? $this->originalParameters;
232  }
233 }
‪TYPO3\CMS\Core\Routing\RouteSorter\LATER
‪const LATER
Definition: RouteSorter.php:27
‪TYPO3\CMS\Core\Routing\RouteSorter\$routes
‪Route[] $routes
Definition: RouteSorter.php:31
‪TYPO3\CMS\Core\Routing\RouteSorter\sortRoutesForGeneration
‪sortRoutesForGeneration()
Definition: RouteSorter.php:59
‪TYPO3\CMS\Core\Routing\RouteSorter\withRoutes
‪withRoutes(array $routes)
Definition: RouteSorter.php:45
‪TYPO3\CMS\Core\Routing\RouteSorter\withOriginalParameters
‪withOriginalParameters(array $originalParameters)
Definition: RouteSorter.php:52
‪TYPO3\CMS\Core\Routing\RouteSorter\routes
‪array< string, $originalParameters=array();public Route[] function getRoutes():array { return $this-> routes
Definition: RouteSorter.php:42
‪TYPO3\CMS\Core\Routing\RouteSorter\compareForGeneration
‪compareForGeneration(Route $self, Route $other)
Definition: RouteSorter.php:65
‪TYPO3\CMS\Core\Routing\RouteSorter\compareMandatoryVariablesPresence
‪compareMandatoryVariablesPresence(Route $self, Route $other, int $action=self::EARLIER)
Definition: RouteSorter.php:143
‪TYPO3\CMS\Core\Routing
‪TYPO3\CMS\Core\Routing\RouteSorter\compareStaticRoutes
‪compareStaticRoutes(Route $self, Route $other, int $action=self::LATER)
Definition: RouteSorter.php:102
‪TYPO3\CMS\Core\Routing\RouteSorter\compareAllVariablesPresence
‪compareAllVariablesPresence(Route $self, Route $other, int $action=self::EARLIER)
Definition: RouteSorter.php:118
‪TYPO3\CMS\Core\Routing\RouteSorter\compareMissingDefaultsAmount
‪compareMissingDefaultsAmount(Route $self, Route $other, int $action=self::LATER)
Definition: RouteSorter.php:162
‪TYPO3\CMS\Core\Routing\RouteSorter\compareDefaultRoutes
‪compareDefaultRoutes(Route $self, Route $other, int $action=self::LATER)
Definition: RouteSorter.php:83
‪TYPO3\CMS\Core\Routing\RouteSorter\EARLIER
‪const EARLIER
Definition: RouteSorter.php:26
‪TYPO3\CMS\Core\Routing\Route
Definition: Route.php:32
‪TYPO3\CMS\Core\Routing\RouteSorter\compareDefaultsAmount
‪compareDefaultsAmount(Route $self, Route $other, int $action=self::LATER)
Definition: RouteSorter.php:177
‪TYPO3\CMS\Core\Routing\RouteSorter
Definition: RouteSorter.php:25