Passed
Pull Request — master (#112)
by Sergei
03:02
created

RouteCollection::getRoutes()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1.037

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 4
ccs 2
cts 3
cp 0.6667
crap 1.037
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Router;
6
7
use InvalidArgumentException;
8
9
final class RouteCollection implements RouteCollectionInterface
10
{
11
    private RouteCollectorInterface $collector;
12
13
    private array $items = [];
14
15
    /**
16
     * All attached routes as Route instances
17
     *
18
     * @var Route[]
19
     */
20
    private array $routes = [];
21
22 6
    public function __construct(RouteCollectorInterface $collector)
23
    {
24 6
        $this->collector = $collector;
25 6
    }
26
27
    /**
28
     * @return Route[]
29
     */
30 1
    public function getRoutes(): array
31
    {
32 1
        $this->ensureItemsInjected();
33
        return $this->routes;
34
    }
35
36
    /**
37
     * @param string $name
38
     *
39
     * @return Route
40
     */
41 5
    public function getRoute(string $name): Route
42
    {
43 5
        $this->ensureItemsInjected();
44 5
        if (!array_key_exists($name, $this->routes)) {
45
            throw new RouteNotFoundException($name);
46
        }
47
48 5
        return $this->routes[$name];
49
    }
50
51
    /**
52
     * Returns routes tree array
53
     *
54
     * @param bool $routeAsString
55
     *
56
     * @return array
57
     */
58
    public function getRouteTree(bool $routeAsString = true): array
59
    {
60
        $this->ensureItemsInjected();
61
        return $this->buildTree($this->items, $routeAsString);
62
    }
63
64 6
    private function ensureItemsInjected(): void
65
    {
66 6
        if ($this->items === []) {
67 6
            $this->injectItems([$this->collector]);
68
        }
69 5
    }
70
71
    /**
72
     * Build routes array
73
     *
74
     * @param Group[]|Route[]|RouteCollectorInterface[] $items
75
     */
76 6
    private function injectItems(array $items): void
77
    {
78 6
        foreach ($items as $index => $item) {
79 6
            $this->injectItem($item);
80
        }
81 5
    }
82
83
    /**
84
     * Add an item into routes array
85
     *
86
     * @param Group|Route $route
87
     */
88 6
    private function injectItem($route): void
89
    {
90 6
        if ($route instanceof Group) {
91 6
            $this->injectGroup($route, $this->items);
92 5
            return;
93
        }
94
95
        $this->items[] = $route->getName();
96
        $routeName = $route->getName();
97
        if (isset($this->routes[$routeName]) && !$route->isOverride()) {
98
            throw new InvalidArgumentException("A route with name '$routeName' already exists.");
99
        }
100
        $this->routes[$routeName] = $route;
101
    }
102
103
    /**
104
     * Inject a Group instance into route and item arrays.
105
     */
106 6
    private function injectGroup(Group $group, array &$tree, string $prefix = ''): void
107
    {
108 6
        $prefix .= $group->getPrefix();
109 6
        $items = $group->getItems();
110 6
        foreach ($items as $item) {
111 6
            if ($item instanceof Group || $item->hasMiddlewares()) {
112 4
                $groupMiddlewares = $group->getMiddlewareDefinitions();
113 4
                foreach ($groupMiddlewares as $middleware) {
114 4
                    $item = $item->prependMiddleware($middleware);
115
                }
116
            }
117
118 6
            if ($item instanceof Group) {
119 3
                if (empty($item->getPrefix())) {
120
                    $this->injectGroup($item, $tree, $prefix);
121
                    continue;
122
                }
123 3
                $tree[$item->getPrefix()] = [];
124 3
                $this->injectGroup($item, $tree[$item->getPrefix()], $prefix);
125 3
                continue;
126
            }
127
128
            /** @var Route $modifiedItem */
129 6
            $modifiedItem = $item->pattern($prefix . $item->getPattern());
130
131 6
            if (empty($tree[$group->getPrefix()])) {
132 6
                $tree[] = $modifiedItem->getName();
133
            } else {
134
                $tree[$group->getPrefix()][] = $modifiedItem->getName();
135
            }
136
137 6
            $routeName = $modifiedItem->getName();
138 6
            if (isset($this->routes[$routeName]) && !$modifiedItem->isOverride()) {
139 1
                throw new InvalidArgumentException("A route with name '$routeName' already exists.");
140
            }
141 6
            $this->routes[$routeName] = $modifiedItem;
142
        }
143 5
    }
144
145
    /**
146
     * Builds route tree from items
147
     *
148
     * @param array $items
149
     * @param bool $routeAsString
150
     *
151
     * @return array
152
     */
153
    private function buildTree(array $items, bool $routeAsString): array
154
    {
155
        $tree = [];
156
        foreach ($items as $key => $item) {
157
            if (is_array($item)) {
158
                $tree[$key] = $this->buildTree($items[$key], $routeAsString);
159
            } else {
160
                $tree[] = $routeAsString ? (string)$this->getRoute($item) : $this->getRoute($item);
161
            }
162
        }
163
        return $tree;
164
    }
165
}
166