Passed
Push — master ( 56c5da...22541f )
by Divine Niiquaye
03:34
created

ResolveTrait::resolveHandler()   A

Complexity

Conditions 5
Paths 2

Size

Total Lines 31
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 5

Importance

Changes 0
Metric Value
cc 5
eloc 15
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 31
ccs 17
cts 17
cp 1
crap 5
rs 9.4555
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of Flight Routing.
7
 *
8
 * PHP version 7.1 and above required
9
 *
10
 * @author    Divine Niiquaye Ibok <[email protected]>
11
 * @copyright 2019 Biurad Group (https://biurad.com/)
12
 * @license   https://opensource.org/licenses/BSD-3-Clause License
13
 *
14
 * For the full copyright and license information, please view the LICENSE
15
 * file that was distributed with this source code.
16
 */
17
18
namespace Flight\Routing\Traits;
19
20
use DivineNii\Invoker\Exceptions\NotCallableException;
21
use DivineNii\Invoker\Interfaces\InvokerInterface;
22
use Flight\Routing\Handlers\RouteHandler;
23
use Flight\Routing\Interfaces\RouteInterface;
24
use Psr\Http\Message\ResponseInterface;
25
use Psr\Http\Message\ServerRequestInterface;
26
use Psr\Http\Server\RequestHandlerInterface;
27
28
trait ResolveTrait
29
{
30
    use MiddlewareTrait;
31
32
    /** @var null|string */
33
    private $namespace;
34
35
    /** @var null|RouteInterface */
36
    private $route;
37
38
    /** @var InvokerInterface */
39
    private $resolver;
40
41
    /**
42
     * @param callable|object|string|string[] $controller
43
     *
44
     * @return mixed
45
     */
46 28
    protected function resolveNamespace($controller)
47
    {
48 28
        if (\is_callable($controller) || null === $namespace = $this->namespace) {
49 24
            return $controller;
50
        }
51
52
        if (
53 4
            (\is_string($controller) && !\class_exists($controller)) &&
54 4
            !str_starts_with($controller, $namespace)
55
        ) {
56 3
            $controller = $this->namespace . \ltrim($controller, '\\/');
57
        }
58
59 4
        if (\is_array($controller) && (!\is_object($controller[0]) && !\class_exists($controller[0]))) {
60 1
            $controller[0] = $this->namespace . \ltrim($controller[0], '\\/');
61
        }
62
63 4
        return $controller;
64
    }
65
66
    /**
67
     * @param ServerRequestInterface $request
68
     * @param RouteInterface         $route
69
     *
70
     * @return mixed
71
     */
72 28
    protected function resolveRestFul(ServerRequestInterface $request, RouteInterface $route)
73
    {
74 28
        $controller = $route->getController();
75
76
        // Disable or enable HTTP request method prefix for action.
77 28
        if (str_ends_with($route->getName(), '__restful')) {
78
            switch (true) {
79 3
                case \is_array($controller):
80 2
                    $controller[1] = $this->getResourceMethod($request, $controller[1]);
81
82 2
                    break;
83
84 1
                case \is_string($controller) && \class_exists($controller):
85 1
                    $controller = [
86 1
                        $controller,
87 1
                        $this->getResourceMethod($request, \substr($route->getName(), -0, -9)),
88
                    ];
89
90 1
                    break;
91
            }
92
        }
93
94 28
        return $controller;
95
    }
96
97
    /**
98
     * @param RouteInterface $route
99
     *
100
     * @throws NotCallableException
101
     *
102
     * @return RequestHandlerInterface
103
     */
104 38
    protected function resolveHandler(RouteInterface $route): RequestHandlerInterface
105
    {
106 38
        $handler = $route->getController();
107
108 38
        if (!$handler instanceof RequestHandlerInterface) {
109 29
            $handler = new RouteHandler(
110 29
                function (ServerRequestInterface $request, ResponseInterface $response) use ($route) {
111 28
                    $handler  = $this->resolveNamespace($this->resolveRestFul($request, $route));
112 28
                    $resolver = $this->resolver;
113
114
                    // For a class that implements RequestHandlerInterface, we will call handle()
115
                    // if no method has been specified explicitly
116 28
                    if (\is_string($handler) && \is_a($handler, RequestHandlerInterface::class, true)) {
117 11
                        $handler = [$handler, 'handle'];
118
                    }
119
120 28
                    $route->setController($resolver->getCallableResolver()->resolve($handler));
121 28
                    $route->setArguments([\get_class($request) => $request, \get_class($response) => $response]);
122
123 28
                    foreach ($this->listeners as $listener) {
124 1
                        $listener->onRoute($request, $route);
125
                    }
126
127 28
                    return $resolver->call($route->getController(), $route->getArguments());
128 29
                },
129 29
                $this->responseFactory
130
            );
131
        }
132
133
        // If controller is instance of RequestHandlerInterface
134 38
        return $handler;
135
    }
136
137
    /**
138
     * @param RouteInterface               $route
139
     * @param array<string,string>         $parameters
140
     * @param array<int|string,int|string> $queryParams
141
     *
142
     * @return string
143
     */
144 3
    protected function resolveUri(RouteInterface $route, array $parameters, array $queryParams): string
145
    {
146 3
        $prefix  = '.'; // Append missing "." at the beginning of the $uri.
147
148
        // Making routing on sub-folders easier
149 3
        if (\strpos($createdUri = $this->getMatcher()->buildPath($route, $parameters), '/') !== 0) {
0 ignored issues
show
Bug introduced by
It seems like getMatcher() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

149
        if (\strpos($createdUri = $this->/** @scrutinizer ignore-call */ getMatcher()->buildPath($route, $parameters), '/') !== 0) {
Loading history...
150 1
            $prefix .= '/';
151
        }
152
153
        // Incase query is added to uri.
154 3
        if (!empty($queryParams)) {
155 1
            $createdUri .= '?' . \http_build_query($queryParams);
156
        }
157
158 3
        if (\strpos($createdUri, '://') === false) {
159 2
            $createdUri = $prefix . $createdUri;
160
        }
161
162 3
        return \rtrim($createdUri, '/');
163
    }
164
165
    /**
166
     * @param RouteInterface $route
167
     *
168
     * @return array<int,mixed>
169
     */
170 38
    protected function resolveMiddlewares(RouteInterface $route): array
171
    {
172 38
        $middlewares = [];
173
174 38
        foreach ($route->getMiddlewares() as $middleware) {
175 9
            if (\is_string($middleware) && isset($this->nameMiddlewares[$middleware])) {
176 1
                $middlewares[] = $this->nameMiddlewares[$middleware];
177
178 1
                continue;
179
            }
180
181 8
            $middlewares[] = $middleware;
182
        }
183
184 38
        return $middlewares;
185
    }
186
187
    /**
188
     * @param ServerRequestInterface $request
189
     * @param string                 $name
190
     */
191 3
    private function getResourceMethod(ServerRequestInterface $request, string $name): string
192
    {
193 3
        return \strtolower($request->getMethod()) . \ucfirst($name);
194
    }
195
}
196