Passed
Push — master ( 412c5f...ce13c3 )
by Divine Niiquaye
02:22
created

ResolveTrait::resolveUri()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 19
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 8
nc 8
nop 3
dl 0
loc 19
ccs 9
cts 9
cp 1
crap 4
rs 10
c 0
b 0
f 0
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 Closure;
21
use DivineNii\Invoker\Exceptions\NotCallableException;
22
use DivineNii\Invoker\Interfaces\InvokerInterface;
23
use Flight\Routing\Handlers\RouteHandler;
24
use Flight\Routing\Interfaces\RouteInterface;
25
use Psr\Http\Message\ResponseInterface;
26
use Psr\Http\Message\ServerRequestInterface;
27
use Psr\Http\Server\RequestHandlerInterface;
28
29
trait ResolveTrait
30
{
31
    use MiddlewareTrait;
32
33
    /** @var null|string */
34
    private $namespace;
35
36
    /** @var null|RouteInterface */
37
    private $route;
38
39
    /** @var InvokerInterface */
40
    private $resolver;
41
42
    /**
43
     * @param callable|object|string|string[] $controller
44
     *
45
     * @return mixed
46
     */
47 41
    protected function resolveNamespace($controller)
48
    {
49 41
        if ($controller instanceof Closure || null === $namespace = $this->namespace) {
50 37
            return $controller;
51
        }
52
53
        if (
54 4
            (\is_string($controller) && !\class_exists($controller)) &&
55 4
            !str_starts_with($controller, $namespace)
56
        ) {
57 3
            $controller = \is_callable($controller) ? $controller : $this->namespace . \ltrim($controller, '\\/');
58
        }
59
60 4
        if (\is_array($controller) && (!\is_object($controller[0]) && !\class_exists($controller[0]))) {
61 1
            $controller[0] = $this->namespace . \ltrim($controller[0], '\\/');
62
        }
63
64 4
        return $controller;
65
    }
66
67
    /**
68
     * @param ServerRequestInterface $request
69
     * @param RouteInterface         $route
70
     *
71
     * @throws NotCallableException
72
     *
73
     * @return callable|RequestHandlerInterface
74
     */
75 41
    protected function resolveController(ServerRequestInterface $request, RouteInterface $route)
76
    {
77 41
        $handler = $this->resolveNamespace($this->resolveRestFul($request, $route));
78
79
        // For a class that implements RequestHandlerInterface, we will call handle()
80
        // if no method has been specified explicitly
81 41
        if (\is_string($handler) && \is_a($handler, RequestHandlerInterface::class, true)) {
82 12
            $handler = [$handler, 'handle'];
83
        }
84
85
        // If controller is instance of RequestHandlerInterface
86 41
        if ($handler instanceof RequestHandlerInterface) {
87 10
            return $handler;
88
        }
89
90 31
        return $this->resolver->getCallableResolver()->resolve($handler);
91
    }
92
93
    /**
94
     * @param ServerRequestInterface $request
95
     * @param RouteInterface         $route
96
     *
97
     * @return mixed
98
     */
99 41
    protected function resolveRestFul(ServerRequestInterface $request, RouteInterface $route)
100
    {
101 41
        $controller = $route->getController();
102
103
        // Disable or enable HTTP request method prefix for action.
104 41
        if (str_ends_with($route->getName(), '__restful')) {
105
            switch (true) {
106 3
                case \is_array($controller):
107 2
                    $controller[1] = $this->getResourceMethod($request, $controller[1]);
108
109 2
                    break;
110
111 1
                case \is_string($controller) && \class_exists($controller):
112 1
                    $controller = [
113 1
                        $controller,
114 1
                        $this->getResourceMethod($request, \substr($route->getName(), -0, -9)),
115
                    ];
116
117 1
                    break;
118
            }
119
        }
120
121 41
        return $controller;
122
    }
123
124
    /**
125
     * @param RouteInterface $route
126
     *
127
     * @return RequestHandlerInterface
128
     */
129 38
    protected function resolveRoute(RouteInterface $route): RequestHandlerInterface
130
    {
131 38
        $handler = $route->getController();
132
133 38
        if (!$handler instanceof RequestHandlerInterface) {
134 29
            $handler = new RouteHandler(
135 29
                function (ServerRequestInterface $request, ResponseInterface $response) use ($route) {
136 28
                    $arguments = \array_merge(
137 28
                        $route->getArguments(),
138 28
                        [\get_class($request) => $request, \get_class($response) => $response]
139
                    );
140
141 28
                    return $this->resolver->call($route->getController(), $arguments);
142 29
                },
143 29
                $this->responseFactory
144
            );
145
        }
146
147 38
        return $handler;
148
    }
149
150
    /**
151
     * @param RouteInterface               $route
152
     * @param array<string,string>         $parameters
153
     * @param array<int|string,int|string> $queryParams
154
     *
155
     * @return string
156
     */
157 3
    protected function resolveUri(RouteInterface $route, array $parameters, array $queryParams): string
158
    {
159 3
        $prefix  = '.'; // Append missing "." at the beginning of the $uri.
160
161
        // Making routing on sub-folders easier
162 3
        if (\strpos($createdUri = $this->matcher->buildPath($route, $parameters), '/') !== 0) {
163 1
            $prefix .= '/';
164
        }
165
166
        // Incase query is added to uri.
167 3
        if (!empty($queryParams)) {
168 1
            $createdUri .= '?' . \http_build_query($queryParams);
169
        }
170
171 3
        if (\strpos($createdUri, '://') === false) {
172 2
            $createdUri = $prefix . $createdUri;
173
        }
174
175 3
        return \rtrim($createdUri, '/');
176
    }
177
178
    /**
179
     * @param RouteInterface $route
180
     *
181
     * @return array<int,mixed>
182
     */
183 38
    protected function resolveMiddlewares(RouteInterface $route): array
184
    {
185 38
        $middlewares = [];
186
187 38
        foreach ($route->getMiddlewares() as $middleware) {
188 9
            if (\is_string($middleware) && isset($this->nameMiddlewares[$middleware])) {
189 1
                $middlewares[] = $this->nameMiddlewares[$middleware];
190
191 1
                continue;
192
            }
193
194 8
            $middlewares[] = $middleware;
195
        }
196
197 38
        return $middlewares;
198
    }
199
200
    /**
201
     * @param ServerRequestInterface $request
202
     * @param string                 $name
203
     */
204 3
    private function getResourceMethod(ServerRequestInterface $request, string $name): string
205
    {
206 3
        return \strtolower($request->getMethod()) . \ucfirst($name);
207
    }
208
}
209