Passed
Pull Request — master (#182)
by Arman
12:44 queued 09:39
created

Route::assignMiddlewaresToRoute()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 6
nc 3
nop 2
dl 0
loc 9
rs 10
c 0
b 0
f 0
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.5
13
 */
14
15
namespace Quantum\Router;
16
17
use Quantum\Exceptions\DatabaseException;
18
use Quantum\Exceptions\SessionException;
19
use Quantum\Exceptions\ConfigException;
20
use Quantum\Exceptions\RouteException;
21
use Quantum\Exceptions\LangException;
22
use Quantum\Exceptions\DiException;
23
use ReflectionException;
24
use Closure;
25
26
/**
27
 * Route Class
28
 * @package Quantum\Router
29
 */
30
class Route
31
{
32
33
    /**
34
     * Current module name
35
     * @var string
36
     */
37
    private $moduleName;
38
39
    /**
40
     * Module options
41
     * @var array
42
     */
43
    private $moduleOptions = [];
44
45
    /**
46
     * Identifies the group middleware
47
     * @var bool
48
     */
49
    private $isGroupMiddlewares;
50
51
    /**
52
     * Identifies the group
53
     * @var boolean
54
     */
55
    private $isGroup = false;
56
57
    /**
58
     * Current group name
59
     * @var string
60
     */
61
    private $currentGroupName = null;
62
63
    /**
64
     * Current route
65
     * @var array
66
     */
67
    private $currentRoute = [];
68
69
    /**
70
     * Virtual routes
71
     * @var array
72
     */
73
    private $virtualRoutes = [];
74
75
    /**
76
     * @param array $module
77
     */
78
    public function __construct(array $module)
79
    {
80
        $this->virtualRoutes['*'] = [];
81
        $this->moduleName = key($module);
82
        $this->moduleOptions = $module[$this->moduleName];
83
    }
84
85
    /**
86
     * @param string $route
87
     * @param string $method
88
     * @param ...$params
89
     * @return $this
90
     */
91
    public function add(string $route, string $method, ...$params): Route
92
    {
93
        $this->currentRoute = [
94
            'route' => !empty($this->moduleOptions['prefix']) ? $this->moduleOptions['prefix'] . '/' . $route : $route,
95
            'prefix' => $this->moduleOptions['prefix'] ?? '',
96
            'method' => $method,
97
            'module' => $this->moduleName,
98
        ];
99
100
        if (isset($this->moduleOptions['cacheable'])) {
101
            $this->currentRoute['cache_settings']['shouldCache'] = (bool)$this->moduleOptions['cacheable'];
102
        }
103
104
        if (is_callable($params[0])) {
105
            $this->currentRoute['callback'] = $params[0];
106
        } else {
107
            $this->currentRoute['controller'] = $params[0];
108
            $this->currentRoute['action'] = $params[1];
109
        }
110
111
        if ($this->currentGroupName) {
112
            $this->currentRoute['group'] = $this->currentGroupName;
113
            $this->virtualRoutes[$this->currentGroupName][] = $this->currentRoute;
114
        } else {
115
            $this->isGroup = false;
116
            $this->isGroupMiddlewares = false;
117
            $this->virtualRoutes['*'][] = $this->currentRoute;
118
        }
119
120
        return $this;
121
    }
122
123
    /**
124
     * @param string $route
125
     * @param ...$params
126
     * @return $this
127
     */
128
    public function get(string $route, ...$params): Route
129
    {
130
        return $this->add($route, 'GET', ...$params);
131
    }
132
133
    /**
134
     * @param string $route
135
     * @param ...$params
136
     * @return $this
137
     */
138
    public function post(string $route, ...$params): Route
139
    {
140
        return $this->add($route, 'POST', ...$params);
141
    }
142
143
    /**
144
     * Starts a named group of routes
145
     * @param string $groupName
146
     * @param Closure $callback
147
     * @return Route
148
     */
149
    public function group(string $groupName, Closure $callback): Route
150
    {
151
        $this->currentGroupName = $groupName;
152
153
        $this->isGroup = true;
154
        $this->isGroupMiddlewares = false;
155
        $callback($this);
156
        $this->isGroupMiddlewares = true;
157
        $this->currentGroupName = null;
158
159
        return $this;
160
    }
161
162
    /**
163
     * Adds middlewares to routes and route groups
164
     * @param array $middlewares
165
     * @return Route
166
     */
167
    public function middlewares(array $middlewares = []): Route
168
    {
169
        if (!$this->isGroup) {
170
            end($this->virtualRoutes['*']);
171
            $lastKey = key($this->virtualRoutes['*']);
172
            $this->assignMiddlewaresToRoute($this->virtualRoutes['*'][$lastKey], $middlewares);
173
            return $this;
174
        }
175
176
        end($this->virtualRoutes);
177
        $lastKeyOfFirstRound = key($this->virtualRoutes);
178
179
        if (!$this->isGroupMiddlewares) {
180
            end($this->virtualRoutes[$lastKeyOfFirstRound]);
181
            $lastKeyOfSecondRound = key($this->virtualRoutes[$lastKeyOfFirstRound]);
182
            $this->assignMiddlewaresToRoute($this->virtualRoutes[$lastKeyOfFirstRound][$lastKeyOfSecondRound], $middlewares);
183
            return $this;
184
        }
185
186
        foreach ($this->virtualRoutes[$lastKeyOfFirstRound] as &$route) {
187
            $this->assignMiddlewaresToRoute($route, $middlewares);
188
        }
189
190
        return $this;
191
    }
192
193
    /**
194
     * @param bool $shouldCache
195
     * @param int|null $ttl
196
     * @return $this
197
     * @throws ConfigException
198
     * @throws DatabaseException
199
     * @throws DiException
200
     * @throws LangException
201
     * @throws ReflectionException
202
     * @throws SessionException
203
     */
204
    public function cacheable(bool $shouldCache, int $ttl = null): Route
205
    {
206
        if (empty(session()->getId())) {
207
            return $this;
208
        }
209
210
        if (!$this->isGroup) {
211
            end($this->virtualRoutes['*']);
212
            $lastKey = key($this->virtualRoutes['*']);
213
214
            $this->virtualRoutes['*'][$lastKey]['cache_settings']['shouldCache'] = $shouldCache;
215
216
            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...
217
                $this->virtualRoutes['*'][$lastKey]['cache_settings']['ttl'] = $ttl;
218
            }
219
220
            return $this;
221
        }
222
223
        end($this->virtualRoutes);
224
        $lastKeyOfFirstRound = key($this->virtualRoutes);
225
226
        foreach ($this->virtualRoutes[$lastKeyOfFirstRound] as &$route) {
227
            $route['cache_settings']['shouldCache'] = $shouldCache;
228
229
            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...
230
                $route['cache_settings']['ttl'] = $ttl;
231
            }
232
        }
233
234
        return $this;
235
    }
236
237
    /**
238
     * Sets a unique name for a route
239
     * @param string $name
240
     * @return Route
241
     * @throws RouteException
242
     */
243
    public function name(string $name): Route
244
    {
245
        if (empty($this->currentRoute)) {
246
            throw RouteException::nameBeforeDefinition();
247
        }
248
249
        if ($this->isGroupMiddlewares) {
250
            throw RouteException::nameOnGroup();
251
        }
252
253
        foreach ($this->virtualRoutes as &$virtualRoute) {
254
            foreach ($virtualRoute as &$route) {
255
                if (isset($route['name']) && $route['name'] == $name) {
256
                    throw RouteException::nonUniqueName();
257
                }
258
259
                if ($route['route'] == $this->currentRoute['route']) {
260
                    $route['name'] = $name;
261
                }
262
            }
263
        }
264
265
        return $this;
266
    }
267
268
    /**
269
     * Gets the run-time routes
270
     * @return array
271
     */
272
    public function getRuntimeRoutes(): array
273
    {
274
        $runtimeRoutes = [];
275
        foreach ($this->virtualRoutes as $virtualRoute) {
276
            foreach ($virtualRoute as $route) {
277
                $runtimeRoutes[] = $route;
278
            }
279
        }
280
        return $runtimeRoutes;
281
    }
282
283
    /**
284
     * Gets the virtual routes
285
     * @return array
286
     */
287
    public function getVirtualRoutes(): array
288
    {
289
        return $this->virtualRoutes;
290
    }
291
292
    /**
293
     * Assigns middlewares to the route
294
     * @param array $route
295
     * @param array $middlewares
296
     */
297
    private function assignMiddlewaresToRoute(array &$route, array $middlewares)
298
    {
299
        if (!key_exists('middlewares', $route)) {
300
            $route['middlewares'] = $middlewares;
301
        } else {
302
            $middlewares = array_reverse($middlewares);
303
304
            foreach ($middlewares as $middleware) {
305
                array_unshift($route['middlewares'], $middleware);
306
            }
307
        }
308
    }
309
}
310