Test Failed
Branch v0.2 (3b8de8)
by Freddie
02:14
created

DispatchController   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 122
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 122
rs 10
c 0
b 0
f 0
wmc 18

9 Methods

Rating   Name   Duplication   Size   Complexity  
A invokeController() 0 17 2
B resolveArgs() 0 25 4
A __invoke() 0 23 1
B injectControllerDependencies() 0 15 5
A getControllerAction() 0 3 1
A getController() 0 3 1
A getControllerClass() 0 3 1
A parameterIsOfType() 0 3 2
A __construct() 0 4 1
1
<?php declare(strict_types=1);
2
3
/**
4
 * This file is part of the Simplex package.
5
 *
6
 * (c) Freddie Frantzen <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
namespace Simplex\HttpMiddleware;
12
13
use Psr\Container\ContainerInterface;
14
use Psr\Http\Message\ResponseInterface;
15
use Psr\Http\Message\ServerRequestInterface;
16
use Simplex\ContainerKeys;
17
use Simplex\Controller;
18
use Simplex\Routing\RouteParamsRegistry;
19
20
class DispatchController
21
{
22
    /** @var RouteParamsRegistry */
23
    private $routeParamsRegistry;
24
25
    /** @var ContainerInterface */
26
    private $container;
27
28
    public function __construct(RouteParamsRegistry $routeParamsRegistry, ContainerInterface $container)
29
    {
30
        $this->routeParamsRegistry = $routeParamsRegistry;
31
        $this->container = $container;
32
    }
33
34
    public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
35
    {
36
        $controllerRouteParam = $this->routeParamsRegistry->getParameter(RouteParamsRegistry::CONTROLLER_KEY);
37
38
        $controller = $this->getController($this->getControllerClass($controllerRouteParam));
39
40
        $this->injectControllerDependencies($controller);
41
42
        $controller->setResponse($response);
43
44
        $args = $this->resolveArgs(
45
            $request,
46
            $this->getControllerClass($controllerRouteParam),
47
            $this->getControllerAction($controllerRouteParam)
48
        );
49
50
        $response = $this->invokeController(
51
            $controller,
52
            $this->getControllerAction($controllerRouteParam),
53
            $args
54
        );
55
56
        return $next($request, $response);
57
    }
58
59
    private function getControllerClass(string $controllerRouteParam): string
60
    {
61
        return explode('::', $controllerRouteParam)[0];
62
    }
63
64
    private function getControllerAction(string $controllerRouteParam): string
65
    {
66
        return explode('::', $controllerRouteParam)[1];
67
    }
68
69
    private function getController(string $controllerClass): Controller
70
    {
71
        return $this->container->get($controllerClass);
72
    }
73
74
    private function injectControllerDependencies($controller): void
75
    {
76
        if (!$this->container->has(ContainerKeys::CONTROLLER_DEPENDENCIES)) {
77
            return;
78
        }
79
80
        $map = $this->container->get(ContainerKeys::CONTROLLER_DEPENDENCIES);
81
82
        foreach ($map as $controllerClass => $dependencies) {
83
            if (!$controller instanceof $controllerClass) {
84
                continue;
85
            }
86
87
            foreach ($dependencies as $setterName => $object) {
88
                $controller->{'set' . ucfirst($setterName)}($object);
89
            }
90
        }
91
    }
92
93
    private function resolveArgs(
94
        ServerRequestInterface $request,
95
        string $controllerClass,
96
        string $controllerMethod): array
97
    {
98
        $method = new \ReflectionMethod($controllerClass, $controllerMethod);
99
100
        $args = [];
101
102
        $methodParameters = $method->getParameters();
103
104
        $routeParameters = $this->routeParamsRegistry->getRouteParams();
105
106
        foreach ($methodParameters as $parameter) {
107
108
            if ($this->parameterIsOfType($parameter,ServerRequestInterface::class)) {
109
                $args[] = $request;
110
            }
111
112
            if (array_key_exists($parameter->getName(), $routeParameters)) {
113
                $args[] = $routeParameters[$parameter->getName()];
114
            }
115
        }
116
117
        return $args;
118
    }
119
120
    private function parameterIsOfType(\ReflectionParameter $parameter, string $class): bool
121
    {
122
        return ($parameter->getClass() !== null) && $parameter->getClass()->getName() === $class;
123
    }
124
125
    private function invokeController(Controller $controller, string $action, array $args): ResponseInterface
126
    {
127
        $response = call_user_func_array(
128
            [
129
                $controller,
130
                $action,
131
            ],
132
            $args
133
        );
134
135
        if (!$response instanceof ResponseInterface) {
136
            throw new \LogicException(
137
                get_class($controller) . ' must return an instance of ' . ResponseInterface::class
138
            );
139
        }
140
141
        return $response;
142
    }
143
}
144