Passed
Push — master ( 389897...3439fb )
by Florian
05:20
created

Dispatcher::setClassTemplate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 2
b 0
f 0
nc 1
nop 1
dl 0
loc 5
ccs 0
cts 3
cp 0
crap 2
rs 10
1
<?php
2
3
/**
4
 * Copyright (c) Florian Krämer (https://florian-kraemer.net)
5
 * Licensed under The MIT License
6
 * For full copyright and license information, please see the LICENSE.txt
7
 * Redistributions of files must retain the above copyright notice.
8
 *
9
 * @copyright Copyright (c) Florian Krämer (https://florian-kraemer.net)
10
 * @author    Florian Krämer
11
 * @link      https://github.com/Phauthentic
12
 * @license   https://opensource.org/licenses/MIT MIT License
13
 */
14
15
declare(strict_types=1);
16
17
namespace Phauthentic\Infrastructure\Http\Dispatcher;
18
19
use Psr\Container\ContainerInterface;
20
use Psr\Http\Message\ResponseInterface;
21
use Psr\Http\Message\ServerRequestInterface;
22
use Psr\Http\Server\RequestHandlerInterface;
23
24
/**
25
 * A simple controller dispatcher middleware
26
 *
27
 * It will check if there is route in the request attributes. If there is a
28
 * route it will take the handler and check if it is a string and tries to
29
 * resolve it against the DI container.
30
 */
31
class Dispatcher implements DispatcherInterface
32
{
33
    /**
34
     * @var string
35
     */
36
    protected $defaultNamespace = '';
37
38
    /**
39
     * @var string
40
     */
41
    protected $methodSeparator = '@';
42
43
    /**
44
     * @var string
45
     */
46
    protected $namespaceSeparator = '.';
47
48
    /**
49
     * @var string
50
     */
51
    protected $classTemplate = '{namespace}{className}';
52
53
    /**
54
     * @var array
55
     */
56
    protected $classParts = [];
57
58
    /**
59
     * @var \Psr\Container\ContainerInterface;
60
     */
61
    protected $container;
62
63
    /**
64
     * @param \Psr\Container\ContainerInterface $container PSR Container
65
     */
66 4
    public function __construct(
67
        ContainerInterface $container
68
    ) {
69 4
        $this->container = $container;
70 4
    }
71
72
    /**
73
     * @param string $namespace Namespace
74
     * @return $this
75
     */
76
    public function setDefaultNamespace(string $namespace): DispatcherInterface
77
    {
78
        $this->defaultNamespace = $namespace;
79
80
        return $this;
81
    }
82
83
    /**
84
     * @param array $classParts Class Template Vars
85
     * @return $this
86
     */
87
    public function setClassParts(array $classParts): DispatcherInterface
88
    {
89
        $this->classParts = $classParts;
90
91
        return $this;
92
    }
93
94
    /**
95
     * @param string $template Template String
96
     * @return $this
97
     */
98
    public function setClassTemplate(string $template): DispatcherInterface
99
    {
100
        $this->classTemplate = $template;
101
102
        return $this;
103
    }
104
105
    /**
106
     * @param string $separator Separator
107
     * @return $this
108
     */
109
    public function setMethodSeparator(string $separator): DispatcherInterface
110
    {
111
        $this->methodSeparator = $separator;
112
113
        return $this;
114
    }
115
116
    /**
117
     * @param string $separator Separator
118
     * @return $this
119
     */
120
    public function setNamespaceSeparator(string $separator): DispatcherInterface
121
    {
122
        $this->namespaceSeparator = $separator;
123
124
        return $this;
125
    }
126
127
    /**
128
     * @inheritDoc
129
     */
130 4
    public function dispatch(
131
        ServerRequestInterface $request,
132
        $handler
133
    ): ?ResponseInterface {
134 4
        if (is_string($handler)) {
135 2
            $handler = $this->stringHandler($handler, $request);
136
        }
137
138 4
        if ($handler instanceof ResponseInterface) {
139 2
            return $handler;
140
        }
141
142 2
        if ($handler instanceof RequestHandlerInterface) {
143
            return $handler->handle($request);
144
        }
145
146 2
        if (is_callable($handler)) {
147 2
            return $handler($request);
148
        }
149
150
        return null;
151
    }
152
153
    /**
154
     * @param string $handler Handler String
155
     * @param \Psr\Http\Message\ServerRequestInterface $request
156
     * @return mixed
157
     */
158 2
    protected function stringHandler(
159
        string $handler,
160
        ServerRequestInterface $request
161
    ) {
162 2
        $result = $this->parseString($handler);
163
164 2
        if (!$this->container->has($result['className'])) {
165
            return null;
166
        }
167
168 2
        $handler = $this->container->get($result['className']);
169
170 2
        if ($result['method'] === null) {
171
            return $handler;
172
        }
173
174 2
        return $handler->{$result['method']}($request);
175
    }
176
177
    /**
178
     * @param string $handler Handler String
179
     * @return array
180
     */
181 2
    protected function parseString(string $handler): array
182
    {
183 2
        $namespace = $this->defaultNamespace;
184 2
        $method = null;
185
186
        // Determine the namespace
187 2
        $position = strpos($handler, $this->namespaceSeparator);
188 2
        if ($position) {
189
            $namespace = strstr($handler, '.', true);
190
            $handler = substr($handler, $position + 1);
191
        }
192
193
        // Determine if there is an action besides a class
194 2
        $position = strpos($handler, $this->methodSeparator);
195 2
        if ($position) {
196 2
            $method = substr($handler, $position + 1);
197 2
            $handler = substr($handler, 0, $position);
198
        }
199
200 2
        $fqcn = $this->classTemplate;
201 2
        $this->classParts['className'] = $handler;
202 2
        $this->classParts['namespace'] = $namespace;
203
204 2
        foreach ($this->classParts as $placeholder => $var) {
205 2
            $fqcn = str_replace(
206 2
                '{' . (string)$placeholder . '}',
207 2
                (string)$var,
208
                $fqcn
209
            );
210
        }
211
212
        return [
213 2
            'className' => $fqcn,
214 2
            'method' => $method
215
        ];
216
    }
217
}
218