Passed
Push — master ( 65b336...1323cd )
by Бабичев
44s
created

Router   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 231
Duplicated Lines 0 %

Test Coverage

Coverage 55.22%

Importance

Changes 0
Metric Value
wmc 24
dl 0
loc 231
ccs 37
cts 67
cp 0.5522
rs 10
c 0
b 0
f 0

15 Methods

Rating   Name   Duplication   Size   Complexity  
A mount() 0 5 1
A group() 0 5 1
A __construct() 0 4 1
A push() 0 3 1
A hash() 0 5 1
A asArray() 0 7 2
A addPattern() 0 9 1
A find() 0 10 3
A bootRoutes() 0 11 3
A getRoute() 0 3 1
A loadingGroups() 0 4 2
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\Router\Rules\PatternRule;
6
use Psr\Cache\CacheItemPoolInterface;
7
use Bavix\Exceptions;
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 iterable
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 5
    public function __construct($data, CacheItemPoolInterface $pool = null)
44
    {
45 5
        $this->addPattern($data);
46 5
        $this->pool = $pool;
47 5
    }
48
49
    /**
50
     * @param string   $prefix
51
     * @param callable $callback
52
     *
53
     * @return Group
54
     */
55
    public function group(string $prefix, callable $callback): Group
56
    {
57
        $group = new Group($prefix, $callback);
58
        $this->mount($group);
59
        return $group;
60
    }
61
62
    /**
63
     * @param Group $group
64
     * @return Router
65
     */
66
    public function mount(Group $group): self
67
    {
68
        $this->routes = null;
69
        $this->groups[] = $group;
70
        return $this;
71
    }
72
73
    /**
74
     * @param Pattern $pattern
75
     * @return Router
76
     */
77
    public function push(Pattern $pattern): self
78
    {
79
        return $this->addPattern($pattern->toArray());
80
    }
81
82
    /**
83
     * @param array|\Traversable $data
84
     *
85
     * @return array
86
     */
87 5
    protected function asArray($data): array
88
    {
89 5
        if (!\is_array($data)) {
90 5
            return \iterator_to_array($data);
91
        }
92
93
        return $data;
94
    }
95
96
    /**
97
     * @param \Traversable|iterable $config
98
     * @return Router
99
     */
100 5
    protected function addPattern($config): self
101
    {
102 5
        $this->routes = null;
103 5
        $this->config = \array_merge(
104 5
            $this->config,
0 ignored issues
show
Bug introduced by Babichev Maxim
$this->config of type iterable is incompatible with the type array expected by parameter $array1 of array_merge(). ( Ignorable by Annotation )

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

104
            /** @scrutinizer ignore-type */ $this->config,
Loading history...
105 5
            $this->asArray($config)
106
        );
107
108 5
        return $this;
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 3
    public function getRoute(string $path, string $host = null, string $protocol = null): Route
135
    {
136 3
        return $this->find(Server::url($path, $host, $protocol));
137
    }
138
139
    /**
140
     * @return string
141
     */
142
    protected function hash(): string
143
    {
144
        $config = \json_encode($this->config);
145
        $groups = \json_encode($this->groups);
146
        return \crc32(self::VERSION . $config . $groups);
147
    }
148
149
    /**
150
     * loading mounted groups
151
     */
152 5
    protected function loadingGroups(): void
153
    {
154 5
        foreach ($this->groups as $group) {
155
            $this->addPattern($group->toArray());
156
        }
157 5
    }
158
159
    /**
160
     * @return array
161
     * @throws
162
     */
163 5
    protected function loadingRoutes(): array
164
    {
165 5
        $this->loadingGroups();
166 5
        $loader = new Loader($this->config);
167 5
        $this->routes = $loader->simplify();
168
169 3
        if ($this->pool) {
170
            $item = $this->pool->getItem($this->hash());
171
            $item->set($this->routes);
172
            $this->pool->save($item);
173
        }
174
175 3
        return $this->routes;
176
    }
177
178
    /**
179
     * @return array
180
     * @throws
181
     */
182 5
    protected function bootRoutes(): array
183
    {
184 5
        if ($this->pool) {
185
            $item = $this->pool->getItem($this->hash());
186
            $data = $item->get();
187
            if ($data) {
188
                return $data;
189
            }
190
        }
191
192 5
        return $this->loadingRoutes();
193
    }
194
195
    /**
196
     * @return Route[]
197
     */
198 5
    public function routes(): array 
199
    {
200 5
        if (empty($this->routes)) {
201 5
            $this->routes = $this->bootRoutes();
202
        }
203
204 3
        return $this->routes;
205
    }
206
207
    /**
208
     * @param string $path
209
     *
210
     * @return Route
211
     *
212
     * @throws Exceptions\NotFound\Path
213
     */
214
    public function route(string $path): Route
215
    {
216
        $routes = $this->routes();
217
218
        if (empty($routes[$path])) {
219
            throw new Exceptions\NotFound\Path('Route `' . $path . '` not found');
220
        }
221
222
        return $routes[$path];
223
    }
224
225
    /**
226
     * @param string $subject
227
     * @return Route
228
     * @throws Exceptions\NotFound\Page
229
     */
230 3
    protected function find(string $subject): Route
231
    {
232 3
        foreach ($this->routes() as $name => $patternRule) {
233 3
            $match = new Match($patternRule, $subject, Server::sharedInstance()->method());
234 3
            if ($match->isTest()) {
235 3
                return new Route($match);
236
            }
237
        }
238
239 1
        throw new Exceptions\NotFound\Page('Page `' . $subject . '` not found', 404);
240
    }
241
242
}
243