Completed
Push — master ( 2f6f54...c29b50 )
by Arman
16s queued 15s
created

Route::add()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 22
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 14
nc 4
nop 3
dl 0
loc 22
rs 9.7998
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->virtualRoutes[$this->currentGroupName][] = $this->currentRoute;
98
        } else {
99
            $this->virtualRoutes['*'][] = $this->currentRoute;
100
        }
101
102
        return $this;
103
    }
104
105
    /**
106
     * Adds new get route entry to routes
107
     * @param string $route
108
     * @param array $params
109
     * @return $this
110
     */
111
    public function get(string $route, ...$params): self
112
    {
113
        return $this->add($route, 'GET', ...$params);
114
    }
115
116
    /**
117
     * Adds new post route entry to routes
118
     * @param string $route
119
     * @param array $params
120
     * @return $this
121
     */
122
    public function post(string $route, ...$params): self
123
    {
124
        return $this->add($route, 'POST', ...$params);
125
    }
126
127
    /**
128
     * Starts a named group of routes
129
     * @param string $groupName
130
     * @param Closure $callback
131
     * @return $this
132
     */
133
    public function group(string $groupName, Closure $callback): self
134
    {
135
        $this->currentGroupName = $groupName;
136
137
        $this->isGroup = true;
138
        $this->isGroupMiddlewares = false;
139
        $callback($this);
140
        $this->isGroupMiddlewares = true;
141
        $this->currentGroupName = null;
142
143
        return $this;
144
    }
145
146
    /**
147
     * Adds middlewares to routes and route groups
148
     * @param array $middlewares
149
     * @return $this
150
     */
151
    public function middlewares(array $middlewares = []): self
152
    {
153
        if (!$this->isGroup) {
154
            end($this->virtualRoutes['*']);
155
            $lastKey = key($this->virtualRoutes['*']);
156
            $this->virtualRoutes['*'][$lastKey]['middlewares'] = $middlewares;
157
        } else {
158
            end($this->virtualRoutes);
159
            $lastKeyOfFirstRound = key($this->virtualRoutes);
160
161
            if (!$this->isGroupMiddlewares) {
162
                end($this->virtualRoutes[$lastKeyOfFirstRound]);
163
                $lastKeyOfSecondRound = key($this->virtualRoutes[$lastKeyOfFirstRound]);
164
                $this->virtualRoutes[$lastKeyOfFirstRound][$lastKeyOfSecondRound]['middlewares'] = $middlewares;
165
            } else {
166
                $this->isGroup = false;
167
                foreach ($this->virtualRoutes[$lastKeyOfFirstRound] as &$route) {
168
                    if (!key_exists('middlewares', $route)) {
169
                        $route['middlewares'] = $middlewares;
170
                    } else {
171
                        $reversedMiddlewares = array_reverse($middlewares);
172
                        foreach ($reversedMiddlewares as $middleware) {
173
                            array_unshift($route['middlewares'], $middleware);
174
                        }
175
                    }
176
                }
177
            }
178
        }
179
180
        return $this;
181
    }
182
183
    /**
184
     * Sets a unique name for a route
185
     * @param string $name
186
     * @return $this
187
     * @throws \Quantum\Exceptions\RouteException
188
     */
189
    public function name(string $name): self
190
    {
191
        if (empty($this->currentRoute)) {
192
            throw RouteException::nameBeforeDefinition();
193
        }
194
195
        if ($this->isGroupMiddlewares) {
196
            throw RouteException::nameOnGroup();
197
        }
198
199
        foreach ($this->virtualRoutes as &$virtualRoute) {
200
            foreach ($virtualRoute as &$route) {
201
                if (isset($route['name']) && $route['name'] == $name) {
202
                    throw RouteException::nonUniqueName();
203
                }
204
205
                if ($route['route'] == $this->currentRoute['route']) {
206
                    $route['name'] = $name;
207
                }
208
            }
209
        }
210
211
        return $this;
212
    }
213
214
    /**
215
     * Gets the run-time routes
216
     * @return array
217
     */
218
    public function getRuntimeRoutes(): array
219
    {
220
        $runtimeRoutes = [];
221
        foreach ($this->virtualRoutes as $virtualRoute) {
222
            foreach ($virtualRoute as $route) {
223
                $runtimeRoutes[] = $route;
224
            }
225
        }
226
        return $runtimeRoutes;
227
    }
228
229
    /**
230
     * Gets the virtual routes
231
     * @return array
232
     */
233
    public function getVirtualRoutes(): array
234
    {
235
        return $this->virtualRoutes;
236
    }
237
238
}
239