Test Failed
Push — master ( d3660e...c7a4a9 )
by Divine Niiquaye
10:08
created

RouteResolver   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 110
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 22
eloc 35
c 1
b 0
f 0
dl 0
loc 110
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
B resolveNamespace() 0 14 7
A __construct() 0 3 1
A __invoke() 0 12 2
A setNamespace() 0 3 1
A getContainer() 0 3 1
B resolveResponse() 0 36 10
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;
19
20
use DivineNii\Invoker\Interfaces\InvokerInterface;
21
use Flight\Routing\Exceptions\InvalidControllerException;
22
use Psr\Container\ContainerInterface;
23
use Psr\Http\Message\ResponseInterface;
24
use Psr\Http\Message\ServerRequestInterface;
25
use Psr\Http\Server\RequestHandlerInterface;
26
27
class RouteResolver
28
{
29
    /** @var InvokerInterface */
30
    private $invoker;
31
32
    /** @var string */
33
    private $namespace;
34
35
    public function __construct(InvokerInterface $invoker)
36
    {
37
        $this->invoker = $invoker;
38
    }
39
40
    /**
41
     * @return mixed
42
     */
43
    public function __invoke(ServerRequestInterface $request, ResponseInterface $response, Route $route)
44
    {
45
        $route   = $request->getAttribute(Route::class, $route);
46
        $handler = $this->resolveResponse($request, $route);
47
48
        if ($handler instanceof ResponseInterface) {
49
            return $handler;
50
        }
51
52
        $arguments = [\get_class($request) => $request, \get_class($response) => $response];
53
54
        return $this->invoker->call($handler, \array_merge($arguments, $route->getArguments()));
55
    }
56
57
    /**
58
     * Set Namespace for route handlers/controllers
59
     *
60
     * @param string $namespace
61
     */
62
    public function setNamespace(string $namespace): void
63
    {
64
        $this->namespace = \rtrim($namespace, '\\/') . '\\';
65
    }
66
67
    /**
68
     * Gets the PSR-11 container instance
69
     *
70
     * @return null|ContainerInterface
71
     */
72
    public function getContainer(): ?ContainerInterface
73
    {
74
        return $this->invoker->getContainer();
75
    }
76
77
    /**
78
     * @return mixed
79
     */
80
    private function resolveResponse(ServerRequestInterface $request, Route $route)
81
    {
82
        $handler = $route->getController();
83
84
        if ($handler instanceof RequestHandlerInterface) {
85
            return $handler->handle($request);
86
        }
87
88
        if ($handler instanceof ResponseInterface) {
89
            return $handler;
90
        }
91
92
        if (null !== $this->namespace) {
93
            $handler = $this->resolveNamespace($handler);
94
        }
95
96
        // For a class that implements RequestHandlerInterface, we will call handle()
97
        // if no method has been specified explicitly
98
        if (\is_string($handler) && \is_a($handler, RequestHandlerInterface::class, true)) {
99
            return $this->invoker->call([$handler, 'handle'], [$request]);
100
        }
101
102
        // Disable or enable HTTP request method prefix for action.
103
        if (null !== $isRestFul = $route->getDefaults()['_api'] ?? null) {
104
            $method = \strtolower($request->getMethod());
105
106
            if (!\is_object($handler) || (\is_string($handler) && \class_exists($handler))) {
107
                throw new InvalidControllerException(
108
                    'Resource handler type should be a class string or class object, and not otherwise'
109
                );
110
            }
111
112
            return [$handler, $method . $isRestFul];
113
        }
114
115
        return $handler;
116
    }
117
118
    /**
119
     * @param callable|object|string|string[] $controller
120
     *
121
     * @return mixed
122
     */
123
    private function resolveNamespace($controller)
124
    {
125
        if (
126
            (\is_string($controller) && !\class_exists($controller)) &&
127
            !str_starts_with($controller, $this->namespace)
128
        ) {
129
            $controller = $this->namespace . \ltrim($controller, '\\/');
130
        }
131
132
        if (\is_array($controller) && (!\is_object($controller[0]) && !\class_exists($controller[0]))) {
133
            $controller[0] = $this->namespace . \ltrim($controller[0], '\\/');
134
        }
135
136
        return $controller;
137
    }
138
}
139