Passed
Pull Request — master (#97)
by Arman
06:04 queued 02:07
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.8.0
13
 */
14
15
namespace Quantum\Router;
16
17
use Quantum\Exceptions\RouteException;
18
use Closure;
19
20
/**
21
 * Route Class
22
 * Route class allows to add new route entries
23
 * @package Quantum\Router
24
 */
25
class Route
26
{
27
28
    /**
29
     * Current module
30
     * @var string
31
     */
32
    private $module;
33
34
    /**
35
     * Identifies the group middleware
36
     * @var bool
37
     */
38
    private $isGroupMiddlewares;
39
40
    /**
41
     * Identifies the group
42
     * @var boolean
43
     */
44
    private $isGroup = false;
45
46
    /**
47
     * Current group name
48
     * @var string
49
     */
50
    private $currentGroupName = null;
51
52
    /**
53
     * Current route
54
     * @var array
55
     */
56
    private $currentRoute = [];
57
58
    /**
59
     * Virtual routes
60
     * @var array
61
     */
62
    private $virtualRoutes = [];
63
64
    /**
65
     * Class constructor
66
     * @param string $module
67
     */
68
    public function __construct(string $module)
69
    {
70
        $this->virtualRoutes['*'] = [];
71
        $this->module = $module;
72
    }
73
74
    /**
75
     * Adds new route entry to routes
76
     * @param string $route
77
     * @param string $method
78
     * @param array $params
79
     * @return $this
80
     */
81
    public function add(string $route, string $method, ...$params): self
82
    {
83
        $this->currentRoute = [
84
            'route' => $route,
85
            'method' => $method,
86
            'module' => $this->module
87
        ];
88
89
        if (is_callable($params[0])) {
90
            $this->currentRoute['callback'] = $params[0];
91
        } else {
92
            $this->currentRoute['controller'] = $params[0];
93
            $this->currentRoute['action'] = $params[1];
94
        }
95
96
        if ($this->currentGroupName) {
97
            $this->currentRoute['group'] = $this->currentGroupName;
98
            $this->virtualRoutes[$this->currentGroupName][] = $this->currentRoute;
99
        } else {
100
            $this->isGroup = false;
101
            $this->isGroupMiddlewares = false;
102
            $this->virtualRoutes['*'][] = $this->currentRoute;
103
        }
104
105
        return $this;
106
    }
107
108
    /**
109
     * Adds new get route entry to routes
110
     * @param string $route
111
     * @param array $params
112
     * @return $this
113
     */
114
    public function get(string $route, ...$params): self
115
    {
116
        return $this->add($route, 'GET', ...$params);
117
    }
118
119
    /**
120
     * Adds new post route entry to routes
121
     * @param string $route
122
     * @param array $params
123
     * @return $this
124
     */
125
    public function post(string $route, ...$params): self
126
    {
127
        return $this->add($route, 'POST', ...$params);
128
    }
129
130
    /**
131
     * Starts a named group of routes
132
     * @param string $groupName
133
     * @param Closure $callback
134
     * @return $this
135
     */
136
    public function group(string $groupName, Closure $callback): self
137
    {
138
        $this->currentGroupName = $groupName;
139
140
        $this->isGroup = true;
141
        $this->isGroupMiddlewares = false;
142
        $callback($this);
143
        $this->isGroupMiddlewares = true;
144
        $this->currentGroupName = null;
145
146
        return $this;
147
    }
148
149
    /**
150
     * Adds middlewares to routes and route groups
151
     * @param array $middlewares
152
     * @return $this
153
     */
154
    public function middlewares(array $middlewares = []): self
155
    {
156
        if (!$this->isGroup) {
157
            end($this->virtualRoutes['*']);
158
            $lastKey = key($this->virtualRoutes['*']);
159
            $this->assignMiddlewaresToRoute($this->virtualRoutes['*'][$lastKey], $middlewares);
160
            return $this;
161
        }
162
163
        end($this->virtualRoutes);
164
        $lastKeyOfFirstRound = key($this->virtualRoutes);
165
166
        if (!$this->isGroupMiddlewares) {
167
            end($this->virtualRoutes[$lastKeyOfFirstRound]);
168
            $lastKeyOfSecondRound = key($this->virtualRoutes[$lastKeyOfFirstRound]);
169
            $this->assignMiddlewaresToRoute($this->virtualRoutes[$lastKeyOfFirstRound][$lastKeyOfSecondRound], $middlewares);
170
            return $this;
171
        }
172
173
        foreach ($this->virtualRoutes[$lastKeyOfFirstRound] as &$route) {
174
            $this->assignMiddlewaresToRoute($route, $middlewares);
175
        }
176
177
        return $this;
178
    }
179
180
    /**
181
     * Sets a unique name for a route
182
     * @param string $name
183
     * @return $this
184
     * @throws \Quantum\Exceptions\RouteException
185
     */
186
    public function name(string $name): self
187
    {
188
        if (empty($this->currentRoute)) {
189
            throw RouteException::nameBeforeDefinition();
190
        }
191
192
        if ($this->isGroupMiddlewares) {
193
            throw RouteException::nameOnGroup();
194
        }
195
196
        foreach ($this->virtualRoutes as &$virtualRoute) {
197
            foreach ($virtualRoute as &$route) {
198
                if (isset($route['name']) && $route['name'] == $name) {
199
                    throw RouteException::nonUniqueName();
200
                }
201
202
                if ($route['route'] == $this->currentRoute['route']) {
203
                    $route['name'] = $name;
204
                }
205
            }
206
        }
207
208
        return $this;
209
    }
210
211
    /**
212
     * Gets the run-time routes
213
     * @return array
214
     */
215
    public function getRuntimeRoutes(): array
216
    {
217
        $runtimeRoutes = [];
218
        foreach ($this->virtualRoutes as $virtualRoute) {
219
            foreach ($virtualRoute as $route) {
220
                $runtimeRoutes[] = $route;
221
            }
222
        }
223
        return $runtimeRoutes;
224
    }
225
226
    /**
227
     * Gets the virtual routes
228
     * @return array
229
     */
230
    public function getVirtualRoutes(): array
231
    {
232
        return $this->virtualRoutes;
233
    }
234
235
    /**
236
     * Assigns middlewares to the route
237
     * @param array $route
238
     * @param array $middlewares
239
     */
240
    private function assignMiddlewaresToRoute(array &$route, array $middlewares)
241
    {
242
        if (!key_exists('middlewares', $route)) {
243
            $route['middlewares'] = $middlewares;
244
        } else {
245
            $middlewares = array_reverse($middlewares);
246
247
            foreach ($middlewares as $middleware) {
248
                array_unshift($route['middlewares'], $middleware);
249
            }
250
        }
251
    }
252
253
}
254