Passed
Pull Request — master (#178)
by
unknown
03:09
created

Route::cacheable()   B

Complexity

Conditions 9
Paths 8

Size

Total Lines 33
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 19
c 0
b 0
f 0
nc 8
nop 2
dl 0
loc 33
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\Exceptions\RouteException;
18
use Closure;
19
use Quantum\Loader\Setup;
20
21
/**
22
 * Route Class
23
 * @package Quantum\Router
24
 */
25
class Route
26
{
27
28
    /**
29
     * Current module name
30
     * @var string
31
     */
32
    private $moduleName;
33
34
    /**
35
     * Module options
36
     * @var array
37
     */
38
    private $moduleOptions = [];
39
40
    /**
41
     * Identifies the group middleware
42
     * @var bool
43
     */
44
    private $isGroupMiddlewares;
45
46
    /**
47
     * Identifies the group
48
     * @var boolean
49
     */
50
    private $isGroup = false;
51
52
    /**
53
     * Current group name
54
     * @var string
55
     */
56
    private $currentGroupName = null;
57
58
    /**
59
     * Current route
60
     * @var array
61
     */
62
    private $currentRoute = [];
63
64
    /**
65
     * Virtual routes
66
     * @var array
67
     */
68
    private $virtualRoutes = [];
69
70
    /**
71
     * Class constructor
72
     * @param array $module
73
     */
74
    public function __construct(array $module)
75
    {
76
        $this->virtualRoutes['*'] = [];
77
        $this->moduleName = key($module);
78
        $this->moduleOptions = $module[key($module)];
79
80
		if (config()->has('resource_cache') && !config()->has('view_cache')){
81
			config()->import(new Setup('config', 'view_cache'));
82
		}
83
    }
84
85
    /**
86
     * Adds new route entry to routes
87
     * @param string $route
88
     * @param string $method
89
     * @param array $params
90
     * @return Route
91
     */
92
    public function add(string $route, string $method, ...$params): Route
93
    {
94
        $this->currentRoute = [
95
            'route' => !empty($this->moduleOptions['prefix']) ? $this->moduleOptions['prefix'] . '/' . $route : $route,
96
            'prefix' => $this->moduleOptions['prefix'],
97
            'method' => $method,
98
            'module' => $this->moduleName
99
        ];
100
101
	    if ($this->canSetCacheToCurrentRoute()){
102
		    $this->currentRoute['cache'] = [
103
			    'shouldCache' => true,
104
			    'ttl' => config()->get('view_cache.ttl', 300),
105
		    ];
106
	    }
107
108
        if (is_callable($params[0])) {
109
            $this->currentRoute['callback'] = $params[0];
110
        } else {
111
            $this->currentRoute['controller'] = $params[0];
112
            $this->currentRoute['action'] = $params[1];
113
        }
114
115
        if ($this->currentGroupName) {
116
            $this->currentRoute['group'] = $this->currentGroupName;
117
            $this->virtualRoutes[$this->currentGroupName][] = $this->currentRoute;
118
        } else {
119
            $this->isGroup = false;
120
            $this->isGroupMiddlewares = false;
121
            $this->virtualRoutes['*'][] = $this->currentRoute;
122
        }
123
124
        return $this;
125
    }
126
127
    /**
128
     * Adds new get route entry to routes
129
     * @param string $route
130
     * @param array $params
131
     * @return Route
132
     */
133
    public function get(string $route, ...$params): Route
134
    {
135
        return $this->add($route, 'GET', ...$params);
136
    }
137
138
    /**
139
     * Adds new post route entry to routes
140
     * @param string $route
141
     * @param array $params
142
     * @return Route
143
     */
144
    public function post(string $route, ...$params): Route
145
    {
146
        return $this->add($route, 'POST', ...$params);
147
    }
148
149
    /**
150
     * Starts a named group of routes
151
     * @param string $groupName
152
     * @param Closure $callback
153
     * @return Route
154
     */
155
    public function group(string $groupName, Closure $callback): Route
156
    {
157
        $this->currentGroupName = $groupName;
158
159
        $this->isGroup = true;
160
        $this->isGroupMiddlewares = false;
161
        $callback($this);
162
        $this->isGroupMiddlewares = true;
163
        $this->currentGroupName = null;
164
165
        return $this;
166
    }
167
168
    /**
169
     * Adds middlewares to routes and route groups
170
     * @param array $middlewares
171
     * @return Route
172
     */
173
    public function middlewares(array $middlewares = []): Route
174
    {
175
        if (!$this->isGroup) {
176
            end($this->virtualRoutes['*']);
177
            $lastKey = key($this->virtualRoutes['*']);
178
            $this->assignMiddlewaresToRoute($this->virtualRoutes['*'][$lastKey], $middlewares);
179
            return $this;
180
        }
181
182
        end($this->virtualRoutes);
183
        $lastKeyOfFirstRound = key($this->virtualRoutes);
184
185
        if (!$this->isGroupMiddlewares) {
186
            end($this->virtualRoutes[$lastKeyOfFirstRound]);
187
            $lastKeyOfSecondRound = key($this->virtualRoutes[$lastKeyOfFirstRound]);
188
            $this->assignMiddlewaresToRoute($this->virtualRoutes[$lastKeyOfFirstRound][$lastKeyOfSecondRound], $middlewares);
189
            return $this;
190
        }
191
192
        foreach ($this->virtualRoutes[$lastKeyOfFirstRound] as &$route) {
193
            $this->assignMiddlewaresToRoute($route, $middlewares);
194
        }
195
196
        return $this;
197
    }
198
199
	public function cacheable(bool $shouldCache, int $ttl = null): Route
200
	{
201
		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...
202
			$ttl = config()->get('view_cache.ttl', 300);
203
		}
204
205
		if (isset($_COOKIE['PHPSESSID'])){
206
			if (!$this->isGroup){
207
				end($this->virtualRoutes['*']);
208
				$lastKey = key($this->virtualRoutes['*']);
209
210
				if (!$shouldCache && key_exists('cache', $this->virtualRoutes['*'][$lastKey])) {
211
					unset($this->virtualRoutes['*'][$lastKey]['cache']);
212
				}else{
213
					$this->assignCacheToCurrentRoute($this->virtualRoutes['*'][$lastKey], $shouldCache, $ttl);
0 ignored issues
show
Bug introduced by
It seems like $ttl can also be of type null; however, parameter $ttl of Quantum\Router\Route::assignCacheToCurrentRoute() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

213
					$this->assignCacheToCurrentRoute($this->virtualRoutes['*'][$lastKey], $shouldCache, /** @scrutinizer ignore-type */ $ttl);
Loading history...
214
				}
215
216
				return $this;
217
			}
218
219
			end($this->virtualRoutes);
220
			$lastKeyOfFirstRound = key($this->virtualRoutes);
221
222
			foreach ($this->virtualRoutes[$lastKeyOfFirstRound] as &$route) {
223
				if (!$shouldCache && key_exists('cache', $route)) {
224
					unset($route['cache']);
225
				}else{
226
					$this->assignCacheToCurrentRoute($route, $shouldCache, $ttl);
227
				}
228
			}
229
		}
230
231
		return $this;
232
	}
233
234
    /**
235
     * Sets a unique name for a route
236
     * @param string $name
237
     * @return Route
238
     * @throws RouteException
239
     */
240
    public function name(string $name): Route
241
    {
242
        if (empty($this->currentRoute)) {
243
            throw RouteException::nameBeforeDefinition();
244
        }
245
246
        if ($this->isGroupMiddlewares) {
247
            throw RouteException::nameOnGroup();
248
        }
249
250
        foreach ($this->virtualRoutes as &$virtualRoute) {
251
            foreach ($virtualRoute as &$route) {
252
                if (isset($route['name']) && $route['name'] == $name) {
253
                    throw RouteException::nonUniqueName();
254
                }
255
256
                if ($route['route'] == $this->currentRoute['route']) {
257
                    $route['name'] = $name;
258
                }
259
            }
260
        }
261
262
        return $this;
263
    }
264
265
    /**
266
     * Gets the run-time routes
267
     * @return array
268
     */
269
    public function getRuntimeRoutes(): array
270
    {
271
        $runtimeRoutes = [];
272
        foreach ($this->virtualRoutes as $virtualRoute) {
273
            foreach ($virtualRoute as $route) {
274
                $runtimeRoutes[] = $route;
275
            }
276
        }
277
        return $runtimeRoutes;
278
    }
279
280
    /**
281
     * Gets the virtual routes
282
     * @return array
283
     */
284
    public function getVirtualRoutes(): array
285
    {
286
        return $this->virtualRoutes;
287
    }
288
289
    /**
290
     * Assigns middlewares to the route
291
     * @param array $route
292
     * @param array $middlewares
293
     */
294
    private function assignMiddlewaresToRoute(array &$route, array $middlewares)
295
    {
296
        if (!key_exists('middlewares', $route)) {
297
            $route['middlewares'] = $middlewares;
298
        } else {
299
            $middlewares = array_reverse($middlewares);
300
301
            foreach ($middlewares as $middleware) {
302
                array_unshift($route['middlewares'], $middleware);
303
            }
304
        }
305
    }
306
307
	private function assignCacheToCurrentRoute(array &$route, bool $shouldCache, int $ttl)
308
	{
309
		$route['cache'] = [
310
			'shouldCache' => $shouldCache,
311
			'ttl' => $ttl,
312
		];
313
	}
314
315
	private function canSetCacheToCurrentRoute(): bool
316
	{
317
		return isset($_COOKIE['PHPSESSID']) &&
318
			config()->has('resource_cache') &&
319
			config()->get('resource_cache') &&
320
			!empty($this->moduleOptions) &&
321
			isset($this->moduleOptions['cacheable']) &&
322
			$this->moduleOptions['cacheable'];
323
	}
324
325
}
326