1 | <?php |
||||||
2 | declare(strict_types = 1); |
||||||
3 | namespace Mezon\Router; |
||||||
4 | |||||||
5 | /** |
||||||
6 | * Trait RouterSet |
||||||
7 | * |
||||||
8 | * @package Router |
||||||
9 | * @author Dodonov A.A. |
||||||
10 | * @version v.1.0 (2019/08/15) |
||||||
11 | * @copyright Copyright (c) 2019, http://aeon.su |
||||||
12 | */ |
||||||
13 | trait RoutesSet |
||||||
14 | { |
||||||
15 | |||||||
16 | use StaticRoutes, ParamRoutes, RoutesSetBase; |
||||||
17 | |||||||
18 | /** |
||||||
19 | * Bunch size |
||||||
20 | * |
||||||
21 | * @var integer |
||||||
22 | */ |
||||||
23 | private $bunchSize = 100; |
||||||
24 | |||||||
25 | /** |
||||||
26 | * Generating appendix for the RegExp |
||||||
27 | * |
||||||
28 | * @param int $i |
||||||
29 | * count of () |
||||||
30 | * @return string appendix |
||||||
31 | */ |
||||||
32 | private function getRegExpAppendix(int $i): string |
||||||
33 | { |
||||||
34 | $return = ''; |
||||||
35 | |||||||
36 | for ($n = 0; $n <= $i; $n ++) { |
||||||
37 | $return .= '()'; |
||||||
38 | } |
||||||
39 | |||||||
40 | return $return; |
||||||
41 | } |
||||||
42 | |||||||
43 | /** |
||||||
44 | * Method compiles regexp for the bunch of routes |
||||||
45 | * |
||||||
46 | * @param array $bunch |
||||||
47 | */ |
||||||
48 | private function compileRegexpForBunch(array &$bunch): void |
||||||
49 | { |
||||||
50 | if (! empty($bunch['bunch'])) { |
||||||
51 | $bunch['regexp'] = ''; |
||||||
52 | /** @var array<int, array{pattern: string}> $hashTable */ |
||||||
53 | $hashTable = []; |
||||||
54 | $items = []; |
||||||
55 | |||||||
56 | /** @var array{pattern: string} $route */ |
||||||
57 | foreach ($bunch['bunch'] as $route) { |
||||||
58 | $vars = $this->_getParameterNames($route['pattern']); |
||||||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||||
59 | $routeMatcher = $this->_getRouteMatcherRegExPattern($route['pattern']); |
||||||
0 ignored issues
–
show
It seems like
_getRouteMatcherRegExPattern() must be provided by classes using this trait. How about adding it as abstract method to this trait?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
60 | $currentIndex = count($vars) + 1; |
||||||
61 | if (isset($hashTable[$currentIndex])) { |
||||||
62 | $maxIndex = max(array_keys($hashTable)); |
||||||
63 | $items[] = $routeMatcher . $this->getRegExpAppendix($maxIndex - $currentIndex); |
||||||
64 | $currentIndex = $maxIndex + 1; |
||||||
65 | $hashTable[$currentIndex] = $route; |
||||||
66 | } else { |
||||||
67 | $items[] = $routeMatcher; |
||||||
68 | $hashTable[$currentIndex] = $route; |
||||||
69 | } |
||||||
70 | } |
||||||
71 | |||||||
72 | $bunch['regexp'] = '~^(?|' . implode('|', $items) . ')$~u'; |
||||||
73 | $bunch['bunch'] = $hashTable; |
||||||
74 | } |
||||||
75 | } |
||||||
76 | |||||||
77 | /** |
||||||
78 | * Were regexps compiled? |
||||||
79 | * |
||||||
80 | * @var bool |
||||||
81 | */ |
||||||
82 | private $regExpsWereCompiled = false; |
||||||
83 | |||||||
84 | /** |
||||||
85 | * Method compiles all regeps for all routes |
||||||
86 | */ |
||||||
87 | private function compileRegexpForBunches(): void |
||||||
88 | { |
||||||
89 | if (! $this->regExpsWereCompiled) { |
||||||
90 | foreach (SupportedRequestMethods::getListOfSupportedRequestMethods() as $requestMethod) { |
||||||
91 | foreach ($this->paramRoutes[$requestMethod] as &$bunch) { |
||||||
92 | $this->compileRegexpForBunch($bunch); |
||||||
93 | } |
||||||
94 | } |
||||||
95 | |||||||
96 | $this->regExpsWereCompiled = true; |
||||||
97 | } |
||||||
98 | } |
||||||
99 | |||||||
100 | /** |
||||||
101 | * Method adds param router |
||||||
102 | * |
||||||
103 | * @param string $requestMethod |
||||||
104 | * request method |
||||||
105 | * @param string $route |
||||||
106 | * route |
||||||
107 | * @param array{0: string, 1: string}|callable|string $callback |
||||||
108 | * callback method |
||||||
109 | * @psalm-suppress PossiblyUndefinedArrayOffset |
||||||
110 | */ |
||||||
111 | protected function addParamRoute(string $requestMethod, string $route, $callback): void |
||||||
112 | { |
||||||
113 | if (empty($this->paramRoutes[$requestMethod])) { |
||||||
114 | $this->paramRoutes[$requestMethod] = [ |
||||||
115 | [ |
||||||
116 | 'bunch' => [] |
||||||
117 | ] |
||||||
118 | ]; |
||||||
119 | } |
||||||
120 | |||||||
121 | $bunchCursor = count($this->paramRoutes[$requestMethod]) - 1; |
||||||
122 | |||||||
123 | $lastBunchSize = count($this->paramRoutes[$requestMethod][$bunchCursor]['bunch']); |
||||||
124 | |||||||
125 | if ($lastBunchSize == $this->bunchSize) { |
||||||
126 | $this->paramRoutes[$requestMethod][] = [ |
||||||
127 | 'bunch' => [] |
||||||
128 | ]; |
||||||
129 | $bunchCursor ++; |
||||||
130 | $lastBunchSize = 0; |
||||||
131 | } |
||||||
132 | |||||||
133 | $this->paramRoutes[$requestMethod][$bunchCursor]['bunch'][$lastBunchSize + 1] = [ |
||||||
134 | 'pattern' => $route, |
||||||
135 | 'callback' => $callback |
||||||
136 | ]; |
||||||
137 | } |
||||||
138 | |||||||
139 | /** |
||||||
140 | * Method clears other data |
||||||
141 | */ |
||||||
142 | protected function clearOtherData(): void |
||||||
143 | { |
||||||
144 | $this->cachedRegExps = []; |
||||||
0 ignored issues
–
show
|
|||||||
145 | |||||||
146 | $this->regExpsWereCompiled = false; |
||||||
147 | } |
||||||
148 | |||||||
149 | /** |
||||||
150 | * Method returns true if the param router exists |
||||||
151 | * |
||||||
152 | * @param string $route |
||||||
153 | * checking route |
||||||
154 | * @param string $requestMethod |
||||||
155 | * HTTP request method |
||||||
156 | * @return bool true if the param router exists, false otherwise |
||||||
157 | */ |
||||||
158 | protected function paramRouteExists(string $route, string $requestMethod): bool |
||||||
159 | { |
||||||
160 | /** @var array{bunch: array} $bunch */ |
||||||
161 | foreach ($this->paramRoutes[$requestMethod] as $bunch) { |
||||||
162 | /** @var array{pattern: string} $item */ |
||||||
163 | foreach ($bunch['bunch'] as $item) { |
||||||
164 | if ($item['pattern'] === $route) { |
||||||
165 | return true; |
||||||
166 | } |
||||||
167 | } |
||||||
168 | } |
||||||
169 | |||||||
170 | return false; |
||||||
171 | } |
||||||
172 | |||||||
173 | /** |
||||||
174 | * Method dumps all routes and their names on disk |
||||||
175 | * |
||||||
176 | * @param string $filePath |
||||||
177 | * file path to cache |
||||||
178 | * @codeCoverageIgnore |
||||||
179 | */ |
||||||
180 | public function dumpOnDisk(string $filePath = './cache/cache.php'): void |
||||||
181 | { |
||||||
182 | $this->compileRegexpForBunches(); |
||||||
183 | |||||||
184 | file_put_contents($filePath, '<?php return ' . var_export([ |
||||||
185 | 0 => $this->staticRoutes, |
||||||
186 | 1 => $this->paramRoutes, |
||||||
187 | 2 => $this->routeNames, |
||||||
188 | 3 => $this->cachedRegExps, |
||||||
189 | 4 => $this->cachedParameters, |
||||||
190 | 5 => $this->regExpsWereCompiled |
||||||
191 | ], true) . ';'); |
||||||
192 | } |
||||||
193 | |||||||
194 | /** |
||||||
195 | * Method loads routes from disk |
||||||
196 | * |
||||||
197 | * @param string $filePath |
||||||
198 | * file path to cache |
||||||
199 | * @codeCoverageIgnore |
||||||
200 | * @psalm-suppress UnresolvableInclude, MixedArrayAccess, MixedAssignment |
||||||
201 | */ |
||||||
202 | public function loadFromDisk(string $filePath = './cache/cache.php'): void |
||||||
203 | { |
||||||
204 | list ($this->staticRoutes, $this->paramRoutes, $this->routeNames, $this->cachedRegExps, $this->cachedParameters, $this->regExpsWereCompiled) = require ($filePath); |
||||||
0 ignored issues
–
show
|
|||||||
205 | } |
||||||
206 | |||||||
207 | /** |
||||||
208 | * Method rturns all available routes |
||||||
209 | * |
||||||
210 | * @return string trace |
||||||
211 | * @psalm-suppress PossiblyUndefinedArrayOffset |
||||||
212 | */ |
||||||
213 | protected function getAllRoutesTrace(): string |
||||||
214 | { |
||||||
215 | $fullTrace = []; |
||||||
216 | |||||||
217 | foreach (SupportedRequestMethods::getListOfSupportedRequestMethods() as $requestMethod) { |
||||||
218 | $trace = [ |
||||||
219 | $requestMethod . ' : ' |
||||||
220 | ]; |
||||||
221 | // TODO try to remove $hasRoutes flag |
||||||
222 | $hasRoutes = false; |
||||||
223 | if (! empty($this->staticRoutes[$requestMethod])) { |
||||||
224 | $trace[] = implode(', ', array_keys($this->staticRoutes[$requestMethod])); |
||||||
225 | $trace[] = ', '; |
||||||
226 | $hasRoutes = true; |
||||||
227 | } |
||||||
228 | if (! empty($this->paramRoutes[$requestMethod])) { |
||||||
229 | foreach ($this->paramRoutes[$requestMethod] as $bunch) { |
||||||
230 | $items = []; |
||||||
231 | foreach ($bunch['bunch'] as $item) { |
||||||
232 | $items[] = $item['pattern']; |
||||||
233 | $hasRoutes = true; |
||||||
234 | } |
||||||
235 | $trace[] = implode(', ', $items); |
||||||
236 | } |
||||||
237 | } |
||||||
238 | |||||||
239 | if (! $hasRoutes) { |
||||||
240 | $trace[] = '<none>'; |
||||||
241 | } |
||||||
242 | |||||||
243 | $fullTrace[] = implode('', $trace); |
||||||
244 | } |
||||||
245 | |||||||
246 | return implode('; ', $fullTrace); |
||||||
247 | } |
||||||
248 | } |
||||||
249 |