Route   A
last analyzed

Complexity

Total Complexity 38

Size/Duplication

Total Lines 294
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 96
dl 0
loc 294
rs 9.36
c 2
b 0
f 0
wmc 38

13 Methods

Rating   Name   Duplication   Size   Complexity  
B name() 0 23 8
A getVirtualRoutes() 0 3 1
A getRuntimeRoutes() 0 9 3
A assignMiddlewaresToRoute() 0 9 3
A delete() 0 3 1
B cacheable() 0 31 8
A group() 0 11 1
A put() 0 3 1
A __construct() 0 5 1
A middlewares() 0 24 4
A get() 0 3 1
A add() 0 30 5
A post() 0 3 1
1
<?php
2
3
/**
4
 * Quantum PHP Framework
5
 *
6
 * An open source software development framework for PHP
7
 *
8
 * @package Quantum
9
 * @author Arman Ag. <[email protected]>
10
 * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org)
11
 * @link http://quantum.softberg.org/
12
 * @since 2.9.7
13
 */
14
15
namespace Quantum\Router;
16
17
use Quantum\Config\Exceptions\ConfigException;
18
use Quantum\Router\Exceptions\RouteException;
19
use Quantum\App\Exceptions\BaseException;
20
use Quantum\Di\Exceptions\DiException;
21
use ReflectionException;
22
use Closure;
23
24
/**
25
 * Route Class
26
 * @package Quantum\Router
27
 */
28
class Route
29
{
30
31
    /**
32
     * Current module name
33
     * @var string
34
     */
35
    private $moduleName;
36
37
    /**
38
     * Module options
39
     * @var array
40
     */
41
    private $moduleOptions;
42
43
    /**
44
     * Identifies the group middleware
45
     * @var bool
46
     */
47
    private $isGroupMiddlewares;
48
49
    /**
50
     * Identifies the group
51
     * @var boolean
52
     */
53
    private $isGroup = false;
54
55
    /**
56
     * Current group name
57
     * @var string
58
     */
59
    private $currentGroupName = null;
60
61
    /**
62
     * Current route
63
     * @var array
64
     */
65
    private $currentRoute = [];
66
67
    /**
68
     * Virtual routes
69
     * @var array
70
     */
71
    private $virtualRoutes = [];
72
73
    /**
74
     * @param array $module
75
     */
76
    public function __construct(array $module)
77
    {
78
        $this->virtualRoutes['*'] = [];
79
        $this->moduleName = key($module);
80
        $this->moduleOptions = $module[$this->moduleName];
81
    }
82
83
    /**
84
     * @param string $route
85
     * @param string $method
86
     * @param ...$params
87
     * @return $this
88
     */
89
    public function add(string $route, string $method, ...$params): Route
90
    {
91
        $this->currentRoute = [
92
            'route' => !empty($this->moduleOptions['prefix']) ? $this->moduleOptions['prefix'] . '/' . $route : $route,
93
            'prefix' => $this->moduleOptions['prefix'] ?? '',
94
            'method' => $method,
95
            'module' => $this->moduleName,
96
        ];
97
98
        if (isset($this->moduleOptions['cacheable'])) {
99
            $this->currentRoute['cache_settings']['shouldCache'] = (bool)$this->moduleOptions['cacheable'];
100
        }
101
102
        if (is_callable($params[0])) {
103
            $this->currentRoute['callback'] = $params[0];
104
        } else {
105
            $this->currentRoute['controller'] = $params[0];
106
            $this->currentRoute['action'] = $params[1];
107
        }
108
109
        if ($this->currentGroupName) {
110
            $this->currentRoute['group'] = $this->currentGroupName;
111
            $this->virtualRoutes[$this->currentGroupName][] = $this->currentRoute;
112
        } else {
113
            $this->isGroup = false;
114
            $this->isGroupMiddlewares = false;
115
            $this->virtualRoutes['*'][] = $this->currentRoute;
116
        }
117
118
        return $this;
119
    }
120
121
    /**
122
     * @param string $route
123
     * @param ...$params
124
     * @return $this
125
     */
126
    public function get(string $route, ...$params): Route
127
    {
128
        return $this->add($route, 'GET', ...$params);
129
    }
130
131
    /**
132
     * @param string $route
133
     * @param ...$params
134
     * @return $this
135
     */
136
    public function post(string $route, ...$params): Route
137
    {
138
        return $this->add($route, 'POST', ...$params);
139
    }
140
141
    /**
142
     * @param string $route
143
     * @param ...$params
144
     * @return $this
145
     */
146
    public function put(string $route, ...$params): Route
147
    {
148
        return $this->add($route, 'PUT', ...$params);
149
    }
150
151
    /**
152
     * @param string $route
153
     * @param ...$params
154
     * @return $this
155
     */
156
    public function delete(string $route, ...$params): Route
157
    {
158
        return $this->add($route, 'DELETE', ...$params);
159
    }
160
161
    /**
162
     * Starts a named group of routes
163
     * @param string $groupName
164
     * @param Closure $callback
165
     * @return Route
166
     */
167
    public function group(string $groupName, Closure $callback): Route
168
    {
169
        $this->currentGroupName = $groupName;
170
171
        $this->isGroup = true;
172
        $this->isGroupMiddlewares = false;
173
        $callback($this);
174
        $this->isGroupMiddlewares = true;
175
        $this->currentGroupName = null;
176
177
        return $this;
178
    }
179
180
    /**
181
     * Adds middlewares to routes and route groups
182
     * @param array $middlewares
183
     * @return Route
184
     */
185
    public function middlewares(array $middlewares = []): Route
186
    {
187
        if (!$this->isGroup) {
188
            end($this->virtualRoutes['*']);
189
            $lastKey = key($this->virtualRoutes['*']);
190
            $this->assignMiddlewaresToRoute($this->virtualRoutes['*'][$lastKey], $middlewares);
191
            return $this;
192
        }
193
194
        end($this->virtualRoutes);
195
        $lastKeyOfFirstRound = key($this->virtualRoutes);
196
197
        if (!$this->isGroupMiddlewares) {
198
            end($this->virtualRoutes[$lastKeyOfFirstRound]);
199
            $lastKeyOfSecondRound = key($this->virtualRoutes[$lastKeyOfFirstRound]);
200
            $this->assignMiddlewaresToRoute($this->virtualRoutes[$lastKeyOfFirstRound][$lastKeyOfSecondRound], $middlewares);
201
            return $this;
202
        }
203
204
        foreach ($this->virtualRoutes[$lastKeyOfFirstRound] as &$route) {
205
            $this->assignMiddlewaresToRoute($route, $middlewares);
206
        }
207
208
        return $this;
209
    }
210
211
    /**
212
     * @param bool $shouldCache
213
     * @param int|null $ttl
214
     * @return $this
215
     * @throws ConfigException
216
     * @throws DiException
217
     * @throws ReflectionException
218
     * @throws BaseException
219
     */
220
    public function cacheable(bool $shouldCache, ?int $ttl = null): Route
221
    {
222
        if (empty(session()->getId())) {
223
            return $this;
224
        }
225
226
        if (!$this->isGroup) {
227
            end($this->virtualRoutes['*']);
228
            $lastKey = key($this->virtualRoutes['*']);
229
230
            $this->virtualRoutes['*'][$lastKey]['cache_settings']['shouldCache'] = $shouldCache;
231
232
            if ($shouldCache && $ttl) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $ttl of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
233
                $this->virtualRoutes['*'][$lastKey]['cache_settings']['ttl'] = $ttl;
234
            }
235
236
            return $this;
237
        }
238
239
        end($this->virtualRoutes);
240
        $lastKeyOfFirstRound = key($this->virtualRoutes);
241
242
        foreach ($this->virtualRoutes[$lastKeyOfFirstRound] as &$route) {
243
            $route['cache_settings']['shouldCache'] = $shouldCache;
244
245
            if ($shouldCache && $ttl) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $ttl of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
246
                $route['cache_settings']['ttl'] = $ttl;
247
            }
248
        }
249
250
        return $this;
251
    }
252
253
    /**
254
     * Sets a unique name for a route
255
     * @param string $name
256
     * @return Route
257
     * @throws RouteException
258
     */
259
    public function name(string $name): Route
260
    {
261
        if (empty($this->currentRoute)) {
262
            throw RouteException::nameBeforeDefinition();
263
        }
264
265
        if ($this->isGroupMiddlewares) {
266
            throw RouteException::nameOnGroup();
267
        }
268
269
        foreach ($this->virtualRoutes as &$virtualRoute) {
270
            foreach ($virtualRoute as &$route) {
271
                if (isset($route['name']) && $route['name'] == $name) {
272
                    throw RouteException::nonUniqueName();
273
                }
274
275
                if ($route['route'] == $this->currentRoute['route']) {
276
                    $route['name'] = $name;
277
                }
278
            }
279
        }
280
281
        return $this;
282
    }
283
284
    /**
285
     * Gets the run-time routes
286
     * @return array
287
     */
288
    public function getRuntimeRoutes(): array
289
    {
290
        $runtimeRoutes = [];
291
        foreach ($this->virtualRoutes as $virtualRoute) {
292
            foreach ($virtualRoute as $route) {
293
                $runtimeRoutes[] = $route;
294
            }
295
        }
296
        return $runtimeRoutes;
297
    }
298
299
    /**
300
     * Gets the virtual routes
301
     * @return array
302
     */
303
    public function getVirtualRoutes(): array
304
    {
305
        return $this->virtualRoutes;
306
    }
307
308
    /**
309
     * Assigns middlewares to the route
310
     * @param array $route
311
     * @param array $middlewares
312
     */
313
    private function assignMiddlewaresToRoute(array &$route, array $middlewares)
314
    {
315
        if (!key_exists('middlewares', $route)) {
316
            $route['middlewares'] = $middlewares;
317
        } else {
318
            $middlewares = array_reverse($middlewares);
319
320
            foreach ($middlewares as $middleware) {
321
                array_unshift($route['middlewares'], $middleware);
322
            }
323
        }
324
    }
325
}