Passed
Push — master ( a4ddd3...82bd79 )
by Alex
06:44
created

RoutesSet   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 234
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 27
eloc 81
c 0
b 0
f 0
dl 0
loc 234
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A addParamRoute() 0 25 3
A compileRegexpForBunch() 0 26 4
B getAllRoutesTrace() 0 34 7
A getRegExpAppendix() 0 9 2
A clearOtherData() 0 5 1
A compileRegexpForBunches() 0 10 4
A loadFromDisk() 0 3 1
A dumpOnDisk() 0 12 1
A paramRouteExists() 0 13 4
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, aeon.org
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
It seems like _getParameterNames() 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 ignore-call  annotation

58
                /** @scrutinizer ignore-call */ 
59
                $vars = $this->_getParameterNames($route['pattern']);
Loading history...
59
                $routeMatcher = $this->_getRouteMatcherRegExPattern($route['pattern']);
0 ignored issues
show
Bug introduced by
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 ignore-call  annotation

59
                /** @scrutinizer ignore-call */ 
60
                $routeMatcher = $this->_getRouteMatcherRegExPattern($route['pattern']);
Loading history...
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) . ')$~';
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 (SuppportedRequestMethods::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
Bug Best Practice introduced by
The property cachedRegExps does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
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
Bug Best Practice introduced by
The property cachedParameters does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
Bug Best Practice introduced by
The property cachedRegExps does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
205
    }
206
207
    /**
208
     * Method rturns all available routes
209
     *
210
     * @return string trace
211
     * @psalm-suppress PossiblyUndefinedArrayOffset
212
     */
213
    public function getAllRoutesTrace(): string
214
    {
215
        $fullTrace = [];
216
217
        foreach (SuppportedRequestMethods::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