Passed
Pull Request — master (#254)
by
unknown
02:57
created

Route::delete()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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