Passed
Pull Request — master (#178)
by
unknown
02:58
created

Route::cacheable()   B

Complexity

Conditions 9
Paths 11

Size

Total Lines 35
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

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