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

Group::routes()   B

Complexity

Conditions 9
Paths 7

Size

Total Lines 30
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 10.2655

Importance

Changes 0
Metric Value
cc 9
eloc 20
c 0
b 0
f 0
nc 7
nop 1
dl 0
loc 30
ccs 15
cts 20
cp 0.75
crap 10.2655
rs 8.0555
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Router;
6
7
use InvalidArgumentException;
8
use RuntimeException;
9
use Yiisoft\Middleware\Dispatcher\MiddlewareDispatcher;
10
use function get_class;
11
use function in_array;
12
use function is_array;
13
use function is_callable;
14
use function is_object;
15
16
final class Group implements RouteCollectorInterface
17
{
18
    /**
19
     * @var Group[]|Route[]
20
     */
21
    protected array $items = [];
22
    protected ?string $prefix;
23
    protected array $middlewareDefinitions = [];
24
25
    private bool $routesAdded = false;
26
    private bool $middlewareAdded = false;
27
    private array $disabledMiddlewareDefinitions = [];
28
    private ?MiddlewareDispatcher $dispatcher;
29
30 10
    private function __construct(?string $prefix = null, MiddlewareDispatcher $dispatcher = null)
31
    {
32 10
        $this->dispatcher = $dispatcher;
33 10
        $this->prefix = $prefix;
34 10
    }
35
36
    /**
37
     * Create a new group instance.
38
     *
39
     * @param string|null $prefix URL prefix to prepend to all routes of the group.
40
     * @param MiddlewareDispatcher|null $dispatcher Middleware dispatcher to use for the group.
41
     *
42
     * @return self
43
     */
44 10
    public static function create(?string $prefix = null, MiddlewareDispatcher $dispatcher = null): self
45
    {
46 10
        return new self($prefix, $dispatcher);
47
    }
48
49 6
    public function routes(...$routes): self
50
    {
51 6
        if ($this->middlewareAdded) {
52
            throw new RuntimeException('routes() can not be used after prependMiddleware().');
53
        }
54 6
        if (is_callable($routes)) {
55
            $callback = $routes;
56 6
        } elseif (is_array($routes)) {
0 ignored issues
show
introduced by
The condition is_array($routes) is always true.
Loading history...
57 6
            $callback = static function (self $group) use (&$routes) {
58 6
                foreach ($routes as $route) {
59 6
                    if ($route instanceof Route) {
60 6
                        $group->addRoute($route);
61 3
                    } elseif ($route instanceof self) {
62 3
                        $group->addGroup($route);
63
                    } else {
64
                        $type = is_object($route) ? get_class($route) : gettype($route);
65
                        throw new InvalidArgumentException(sprintf('Route should be either an instance of Route or Group, %s given.', $type));
66
                    }
67
                }
68 6
            };
69
        } else {
70
            $callback = null;
71
        }
72
73 6
        if ($callback !== null) {
0 ignored issues
show
introduced by
The condition $callback !== null is always true.
Loading history...
74 6
            $callback($this);
75
        }
76 6
        $this->routesAdded = true;
77
78 6
        return $this;
79
    }
80
81 2
    public function withDispatcher(MiddlewareDispatcher $dispatcher): self
82
    {
83 2
        $group = clone $this;
84 2
        $group->dispatcher = $dispatcher;
85 2
        foreach ($group->items as $index => $item) {
86 2
            if (!$item->hasDispatcher()) {
87 2
                $item = $item->withDispatcher($dispatcher);
88 2
                $group->items[$index] = $item;
89
            }
90
        }
91
92 2
        return $group;
93
    }
94
95 9
    public function hasDispatcher(): bool
96
    {
97 9
        return $this->dispatcher !== null;
98
    }
99
100 9
    public function addRoute(Route $route): self
101
    {
102 9
        if (!$route->hasDispatcher() && $this->hasDispatcher()) {
103 3
            $route->injectDispatcher($this->dispatcher);
104
        }
105 9
        $this->items[] = $route;
106 9
        return $this;
107
    }
108
109 5
    public function addGroup(self $group): self
110
    {
111 5
        if (!$group->hasDispatcher() && $this->hasDispatcher()) {
112 2
            $group = $group->withDispatcher($this->dispatcher);
113
        }
114 5
        $this->items[] = $group;
115
116
117 5
        return $this;
118
    }
119
120
    /**
121
     * Appends a handler middleware definition that should be invoked for a matched route.
122
     * First added handler will be executed first.
123
     *
124
     * @param mixed $middlewareDefinition
125
     *
126
     * @return self
127
     */
128 6
    public function middleware($middlewareDefinition): self
129
    {
130 6
        if ($this->routesAdded) {
131
            throw new RuntimeException('middleware() can not be used after routes().');
132
        }
133 6
        array_unshift($this->middlewareDefinitions, $middlewareDefinition);
134
135 6
        return $this;
136
    }
137
138
    /**
139
     * Prepends a handler middleware definition that should be invoked for a matched route.
140
     * First added handler will be executed last.
141
     *
142
     * @param mixed $middlewareDefinition
143
     *
144
     * @return $this
145
     */
146 1
    public function prependMiddleware($middlewareDefinition): self
147
    {
148 1
        $this->middlewareDefinitions[] = $middlewareDefinition;
149 1
        $this->middlewareAdded = true;
150 1
        return $this;
151
    }
152
153
    /**
154
     * Excludes middleware from being invoked when action is handled.
155
     * It is useful to avoid invoking one of the parent group middleware for
156
     * a certain route.
157
     *
158
     * @param mixed $middlewareDefinition
159
     *
160
     * @return $this
161
     */
162
    public function disableMiddleware($middlewareDefinition): self
163
    {
164
        $this->disabledMiddlewareDefinitions[] = $middlewareDefinition;
165
        return $this;
166
    }
167
168
    /**
169
     * @return Group[]|Route[]
170
     */
171 9
    public function getItems(): array
172
    {
173 9
        return $this->items;
174
    }
175
176 7
    public function getPrefix(): ?string
177
    {
178 7
        return $this->prefix;
179
    }
180
181 6
    public function getMiddlewareDefinitions(): array
182
    {
183 6
        foreach ($this->middlewareDefinitions as $index => $definition) {
184 6
            if (in_array($definition, $this->disabledMiddlewareDefinitions, true)) {
185
                unset($this->middlewareDefinitions[$index]);
186
            }
187
        }
188
189 6
        return $this->middlewareDefinitions;
190
    }
191
}
192