Test Failed
Push — master ( d750d9...412c5f )
by Divine Niiquaye
03:10
created

ResolveTrait   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 178
Duplicated Lines 0 %

Test Coverage

Coverage 96.55%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 58
dl 0
loc 178
ccs 56
cts 58
cp 0.9655
rs 10
c 2
b 0
f 0
wmc 30

7 Methods

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