Passed
Pull Request — master (#135)
by Rustam
02:12
created

RouteCollection::injectItems()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3

Importance

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