Passed
Pull Request — master (#831)
by Maxim
06:01
created

RouteGroup::addMiddleware()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 2
c 1
b 0
f 0
dl 0
loc 5
ccs 3
cts 3
cp 1
rs 10
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Spiral\Router;
6
7
use Psr\Container\ContainerInterface;
8
use Psr\Http\Server\MiddlewareInterface;
9
use Spiral\Core\BinderInterface;
10
use Spiral\Core\Container\Autowire;
11
use Spiral\Core\CoreInterface;
12
use Spiral\Http\Pipeline;
13
use Spiral\Router\Target\AbstractTarget;
14
15
/**
16
 * RouteGroup provides the ability to configure multiple routes to controller/actions using same presets.
17
 */
18
final class RouteGroup
19
{
20
    private string $prefix = '';
21
    private string $namePrefix = '';
22
23
    /** @var string[] */
24
    private array $routes = [];
25
26
    /** @var array<class-string<MiddlewareInterface>|MiddlewareInterface|Autowire> */
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<class-string<Middl...wareInterface|Autowire> at position 2 could not be parsed: Unknown type name 'class-string' at position 2 in array<class-string<MiddlewareInterface>|MiddlewareInterface|Autowire>.
Loading history...
27
    private array $middleware = [];
28
29
    private ?CoreInterface $core = null;
30
31 285
    public function __construct(
32
        private readonly ContainerInterface $container,
33
        private readonly RouterInterface $router,
34
        private readonly UriHandler $handler,
35
        private readonly ?string $name = null
36
    ) {
37 285
        $this->bindMiddlewares();
38
    }
39
40
    /**
41
     * Check if group has a route with given name
42
     */
43 4
    public function hasRoute(string $name): bool
44
    {
45 4
        return \in_array($name, $this->routes);
46
    }
47
48
    /**
49
     * Prefix added to all the routes.
50
     */
51 267
    public function setPrefix(string $prefix): self
52
    {
53 267
        $this->prefix = $prefix;
54
55
        // update routes
56 267
        $this->flushRoutes();
57
58 267
        return $this;
59
    }
60
61
    /**
62
     * Route name prefix added to all routes.
63
     */
64 1
    public function setNamePrefix(string $prefix): self
65
    {
66 1
        $this->namePrefix = $prefix;
67
68
        // update routes
69 1
        $this->flushRoutes();
70
71 1
        return $this;
72
    }
73
74 2
    public function setCore(Autowire|CoreInterface|string $core): self
75
    {
76 2
        if (!$core instanceof CoreInterface) {
77 1
            $core = $this->container->get($core);
0 ignored issues
show
Bug introduced by
It seems like $core can also be of type Spiral\Core\Container\Autowire; however, parameter $id of Psr\Container\ContainerInterface::get() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

77
            $core = $this->container->get(/** @scrutinizer ignore-type */ $core);
Loading history...
78
        }
79 2
        $this->core = $core;
80
81
        // update routes
82 2
        $this->flushRoutes();
83
84 2
        return $this;
85
    }
86
87
    /**
88
     * @param MiddlewareInterface|Autowire|class-string<MiddlewareInterface>|non-empty-string $middleware
0 ignored issues
show
Documentation Bug introduced by
The doc comment MiddlewareInterface|Auto...rface>|non-empty-string at position 4 could not be parsed: Unknown type name 'class-string' at position 4 in MiddlewareInterface|Autowire|class-string<MiddlewareInterface>|non-empty-string.
Loading history...
89
     */
90 271
    public function addMiddleware(MiddlewareInterface|Autowire|string $middleware): self
91
    {
92 271
        $this->middleware[] = $middleware;
93
94 271
        return $this;
95
    }
96
97
    /**
98
     * Push routes to router.
99
     *
100
     * @internal
101
     */
102 270
    public function flushRoutes(): void
103
    {
104 270
        foreach ($this->routes as $name) {
105 267
            $this->router->setRoute($name, $this->applyGroupParams($this->router->getRoute($name)));
106
        }
107
    }
108
109
    /**
110
     * Add a route to a route group.
111
     */
112 284
    public function addRoute(string $name, Route $route): self
113
    {
114 284
        if ($this->name !== null && $this->middleware !== []) {
115 271
            $route = $route->withMiddleware('middleware:' . $this->name);
0 ignored issues
show
Bug introduced by
'middleware:' . $this->name of type string is incompatible with the type Spiral\Router\Traits\MiddlewareType|array expected by parameter $middleware of Spiral\Router\Route::withMiddleware(). ( Ignorable by Annotation )

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

115
            $route = $route->withMiddleware(/** @scrutinizer ignore-type */ 'middleware:' . $this->name);
Loading history...
116
        }
117
118 284
        $this->routes[] = $this->namePrefix . $name;
119
120 284
        $this->router->setRoute($this->namePrefix . $name, $this->applyGroupParams($route));
121
122 284
        return $this;
123
    }
124
125 284
    private function applyGroupParams(Route $route): Route
126
    {
127 284
        if ($this->core !== null) {
128 2
            $target = $route->getTarget();
129
130 2
            if ($target instanceof AbstractTarget) {
131 2
                $route = $route->withTarget($target->withCore($this->core));
132
            }
133
        }
134
135
        try {
136 284
            $uriHandler = $route->getUriHandler();
137 284
        } catch (\Throwable) {
138 284
            $uriHandler = $this->handler;
139
        }
140
141 284
        return $route->withUriHandler($uriHandler->withPrefix($this->prefix));
142
    }
143
144 285
    private function bindMiddlewares(): void
145
    {
146 285
        if ($this->container instanceof BinderInterface && $this->name !== null) {
147 285
            $this->container->bind(
0 ignored issues
show
Bug introduced by
The method bind() does not exist on Psr\Container\ContainerInterface. It seems like you code against a sub-type of Psr\Container\ContainerInterface such as Spiral\Core\Container. ( Ignorable by Annotation )

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

147
            $this->container->/** @scrutinizer ignore-call */ 
148
                              bind(
Loading history...
148 285
                'middleware:' . $this->name,
149 285
                function (PipelineFactory $factory): Pipeline {
150 271
                    return $factory->createWithMiddleware($this->middleware);
151
                }
152
            );
153
        }
154
    }
155
}
156