Router   A
last analyzed

Complexity

Total Complexity 24

Size/Duplication

Total Lines 231
Duplicated Lines 0 %

Test Coverage

Coverage 56.72%

Importance

Changes 0
Metric Value
wmc 24
eloc 56
dl 0
loc 231
ccs 38
cts 67
cp 0.5672
rs 10
c 0
b 0
f 0

15 Methods

Rating   Name   Duplication   Size   Complexity  
A hash() 0 5 1
A asArray() 0 7 2
A addPattern() 0 9 1
A mount() 0 5 1
A find() 0 10 3
A group() 0 5 1
A bootRoutes() 0 11 3
A getRoute() 0 3 1
A loadingGroups() 0 4 2
A __construct() 0 4 1
A push() 0 3 1
A routes() 0 7 2
A loadingRoutes() 0 13 2
A route() 0 9 2
A getCurrentRoute() 0 3 1
1
<?php
2
3
namespace Bavix\Router;
4
5
use Bavix\Exceptions;
6
use Bavix\Router\Rules\PatternRule;
7
use Psr\Cache\CacheItemPoolInterface;
8
9
class Router
10
{
11
12
    /**
13
     * Router version
14
     */
15
    public const VERSION = '2.0.0';
16
17
    /**
18
     * @var Group[]
19
     */
20
    protected $groups = [];
21
22
    /**
23
     * @var PatternRule[]
24
     */
25
    protected $routes;
26
27
    /**
28
     * @var array
29
     */
30
    protected $config = [];
31
32
    /**
33
     * @var CacheItemPoolInterface
34
     */
35
    protected $pool;
36
37
    /**
38
     * Router constructor.
39
     *
40
     * @param iterable $data
41
     * @param CacheItemPoolInterface $pool
42
     */
43 7
    public function __construct($data, CacheItemPoolInterface $pool = null)
44
    {
45 7
        $this->addPattern($data);
46 7
        $this->pool = $pool;
47 7
    }
48
49
    /**
50
     * @param \Traversable|iterable $config
51
     * @return Router
52
     */
53 7
    protected function addPattern($config): self
54
    {
55 7
        $this->routes = null;
56 7
        $this->config = \array_merge(
57 7
            $this->config,
58 7
            $this->asArray($config)
59
        );
60
61 7
        return $this;
62
    }
63
64
    /**
65
     * @param array|\Traversable $data
66
     *
67
     * @return array
68
     */
69 7
    protected function asArray($data): array
70
    {
71 7
        if (!\is_array($data)) {
72 6
            return \iterator_to_array($data);
73
        }
74
75 1
        return $data;
76
    }
77
78
    /**
79
     * @param string $prefix
80
     * @param callable $callback
81
     *
82
     * @return Group
83
     */
84
    public function group(string $prefix, callable $callback): Group
85
    {
86
        $group = new Group($prefix, $callback);
87
        $this->mount($group);
88
        return $group;
89
    }
90
91
    /**
92
     * @param Group $group
93
     * @return Router
94
     */
95
    public function mount(Group $group): self
96
    {
97
        $this->routes = null;
98
        $this->groups[] = $group;
99
        return $this;
100
    }
101
102
    /**
103
     * @param Pattern $pattern
104
     * @return Router
105
     */
106
    public function push(Pattern $pattern): self
107
    {
108
        return $this->addPattern($pattern->toArray());
109
    }
110
111
    /**
112
     * @return Route
113
     *
114
     * @throws Exceptions\NotFound\Data
115
     * @throws Exceptions\NotFound\Path
116
     * @throws Exceptions\NotFound\Page
117
     */
118
    public function getCurrentRoute(): Route
119
    {
120
        return $this->getRoute(Server::sharedInstance()->path());
121
    }
122
123
    /**
124
     * @param string $path
125
     * @param string $host
126
     * @param string $protocol
127
     *
128
     * @return Route
129
     *
130
     * @throws Exceptions\NotFound\Data
131
     * @throws Exceptions\NotFound\Path
132
     * @throws Exceptions\NotFound\Page
133
     */
134 5
    public function getRoute(string $path, string $host = null, string $protocol = null): Route
135
    {
136 5
        return $this->find(Server::url($path, $host, $protocol));
137
    }
138
139
    /**
140
     * @param string $subject
141
     * @return Route
142
     * @throws Exceptions\NotFound\Page
143
     */
144 5
    protected function find(string $subject): Route
145
    {
146 5
        foreach ($this->routes() as $name => $patternRule) {
147 5
            $match = new Match($patternRule, $subject, Server::sharedInstance()->method());
148 5
            if ($match->isTest()) {
149 5
                return new Route($match);
150
            }
151
        }
152
153 1
        throw new Exceptions\NotFound\Page('Page `' . $subject . '` not found', 404);
154
    }
155
156
    /**
157
     * @return Route[]
158
     */
159 7
    public function routes(): array
160
    {
161 7
        if (empty($this->routes)) {
162 7
            $this->routes = $this->bootRoutes();
163
        }
164
165 5
        return $this->routes;
166
    }
167
168
    /**
169
     * @return array
170
     * @throws
171
     */
172 7
    protected function bootRoutes(): array
173
    {
174 7
        if ($this->pool) {
175
            $item = $this->pool->getItem($this->hash());
176
            $data = $item->get();
177
            if ($data) {
178
                return $data;
179
            }
180
        }
181
182 7
        return $this->loadingRoutes();
183
    }
184
185
    /**
186
     * @return string
187
     */
188
    protected function hash(): string
189
    {
190
        $config = \json_encode($this->config);
191
        $groups = \json_encode($this->groups);
192
        return \crc32(self::VERSION . $config . $groups);
193
    }
194
195
    /**
196
     * @return array
197
     * @throws
198
     */
199 7
    protected function loadingRoutes(): array
200
    {
201 7
        $this->loadingGroups();
202 7
        $loader = new Loader($this->config);
203 7
        $this->routes = $loader->simplify();
204
205 5
        if ($this->pool) {
206
            $item = $this->pool->getItem($this->hash());
207
            $item->set($this->routes);
208
            $this->pool->save($item);
209
        }
210
211 5
        return $this->routes;
212
    }
213
214
    /**
215
     * loading mounted groups
216
     */
217 7
    protected function loadingGroups(): void
218
    {
219 7
        foreach ($this->groups as $group) {
220
            $this->addPattern($group->toArray());
221
        }
222 7
    }
223
224
    /**
225
     * @param string $path
226
     *
227
     * @return Route
228
     *
229
     * @throws Exceptions\NotFound\Path
230
     */
231
    public function route(string $path): Route
232
    {
233
        $routes = $this->routes();
234
235
        if (empty($routes[$path])) {
236
            throw new Exceptions\NotFound\Path('Route `' . $path . '` not found');
237
        }
238
239
        return $routes[$path];
240
    }
241
242
}
243