Issues (6)

src/Router/Route.php (2 issues)

Labels
Severity
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * Micro
7
 *
8
 * @author      Raffael Sahli <[email protected]>
9
 * @copyright   Copryright (c) 2015-2018 gyselroth GmbH (https://gyselroth.com)
10
 * @license     MIT https://opensource.org/licenses/MIT
11
 */
12
13
namespace Micro\Http\Router;
14
15
use Micro\Http\Router;
16
use Psr\Container\ContainerInterface;
17
18
class Route
19
{
20
    /**
21
     * Router.
22
     *
23
     * @var Router
24
     */
25
    protected $router;
26
27
    /**
28
     * Continue propagation if match.
29
     *
30
     * @var bool
31
     */
32
    protected $continue_propagation = false;
33
34
    /**
35
     * Route path.
36
     *
37
     * @var string
38
     */
39
    protected $path;
40
41
    /**
42
     * Class to be instanced if route match was found.
43
     *
44
     * @var object|string
45
     */
46
    protected $class;
47
48
    /**
49
     * Method to be executed if route match was found.
50
     *
51
     * @var string
52
     */
53
    protected $method;
54
55
    /**
56
     * Found request parameters.
57
     *
58
     * @var array
59
     */
60
    protected $params = [];
61
62
    /**
63
     * Instance route.
64
     *
65
     * @param string $path
66
     * @param string $class
67
     * @param string $method
68
     * @param array  $params
69
     */
70
    public function __construct(string $path, $class, ? string $method = null, array $params = [])
71
    {
72
        $this->setPath($path);
73
        $this->setClass($class);
74
        $this->setMethod($method);
75
        $this->setParams($params);
76
    }
77
78
    /**
79
     * Check if route does match the current http request.
80
     *
81
     * @return bool
82
     */
83
    public function match(): bool
84
    {
85
        $regex = preg_replace_callback('#({([A-Z0-9a-z]+)\:\#(.+?)\#})|\{(.+?)\}#', function ($match) {
86
            if (4 === count($match)) {
87
                return '(?<'.$match[2].'>'.$match[3].'+)';
88
            }
89
90
            return '(?<'.end($match).'>\w+)';
91
        }, $this->path);
92
93
        if (preg_match('#^'.$regex.'#', $this->router->getPath(), $matches)) {
94
            foreach ($matches as $key => $value) {
95
                if (!is_int($key)) {
96
                    $this->params[$key] = $value;
97
                }
98
            }
99
100
            return true;
101
        }
102
103
        return false;
104
    }
105
106
    /**
107
     * Get callable.
108
     *
109
     * @param ContainerInterface $container
110
     *
111
     * @return array
112
     */
113
    public function getCallable(?ContainerInterface $container = null): array
114
    {
115
        if (is_object($this->class)) {
116
            $instance = $this->class;
117
        } else {
118
            if (null === $container) {
119
                $instance = new $this->class();
120
            } else {
121
                $instance = $container->get($this->class);
122
            }
123
        }
124
125
        if (null !== $this->method) {
126
            return [&$instance, $this->method];
127
        }
128
129
        return [&$instance, $this->getMethod()];
130
    }
131
132
    /**
133
     * Get http router.
134
     *
135
     * @return Router
136
     */
137
    public function getRouter(): Router
138
    {
139
        return $this->router;
140
    }
141
142
    /**
143
     * Set http router.
144
     *
145
     * @param Router $router
146
     *
147
     * @return Route
148
     */
149
    public function setRouter(Router $router): self
150
    {
151
        $this->router = $router;
152
153
        return $this;
154
    }
155
156
    /**
157
     * Get path.
158
     *
159
     * @return string
160
     */
161
    public function getPath(): string
162
    {
163
        return $this->path;
164
    }
165
166
    /**
167
     * Set path.
168
     *
169
     * @param string $path
170
     *
171
     * @return Route
172
     */
173
    public function setPath(string $path): self
174
    {
175
        $this->path = (string) $path;
176
177
        return $this;
178
    }
179
180
    /**
181
     * Get class.
182
     *
183
     * @return string
184
     */
185
    public function getClass(): string
186
    {
187
        if (is_object($this->class)) {
188
            return get_class($this->class);
189
        }
190
191
        return $this->class;
192
    }
193
194
    /**
195
     * Set clas.
196
     *
197
     * @param object|string $class
198
     *
199
     * @return Route
200
     */
201
    public function setClass($class): self
202
    {
203
        $this->class = $class;
204
205
        return $this;
206
    }
207
208
    /**
209
     * Get method.
210
     *
211
     * @return string
212
     */
213
    public function getMethod(): string
214
    {
215
        if ('$' === substr($this->path, -1)) {
216
            return $this->router->getVerb();
217
        }
218
219
        $path = $this->router->getPath();
220
        $action = substr($path, strrpos($path, '/') + 1);
221
222
        if (!in_array($action, $this->params, true)) {
223
            $this->method = $action;
224
        }
225
226
        $short = $this->camelCase2Dashes(substr($this->class, strrpos($this->class, '\\') + 1));
0 ignored issues
show
It seems like $this->class can also be of type object; however, parameter $haystack of strrpos() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

226
        $short = $this->camelCase2Dashes(substr($this->class, strrpos(/** @scrutinizer ignore-type */ $this->class, '\\') + 1));
Loading history...
It seems like $this->class can also be of type object; however, parameter $string of substr() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

226
        $short = $this->camelCase2Dashes(substr(/** @scrutinizer ignore-type */ $this->class, strrpos($this->class, '\\') + 1));
Loading history...
227
228
        if ($this->camelCase2Dashes($short) === $action) {
229
            $this->method = '';
230
        }
231
232
        return $this->buildMethodName($this->method);
233
    }
234
235
    /**
236
     * Set method.
237
     *
238
     * @param string $method
239
     *
240
     * @return Route
241
     */
242
    public function setMethod(? string $method): self
243
    {
244
        $this->method = $method;
245
246
        return $this;
247
    }
248
249
    /**
250
     * Set params.
251
     *
252
     * @param array $params
253
     *
254
     * @return Route
255
     */
256
    public function setParams(array $params): self
257
    {
258
        $this->params = $params;
259
260
        return $this;
261
    }
262
263
    /**
264
     * Get translated regex variable values.
265
     *
266
     * @return array
267
     */
268
    public function getParams(): array
269
    {
270
        return $this->params;
271
    }
272
273
    /**
274
     * Continue propagation after match.
275
     *
276
     * @return bool
277
     */
278
    public function continueAfterMatch(): bool
279
    {
280
        return $this->continue_propagation;
281
    }
282
283
    /**
284
     * Halt propagation after match.
285
     *
286
     * @param bool $next
287
     *
288
     * @return Route
289
     */
290
    public function continuePropagation($next = true): self
291
    {
292
        $this->continue_propagation = (bool) $next;
293
294
        return $this;
295
    }
296
297
    /**
298
     * Build method name.
299
     *
300
     * @param string $name
301
     *
302
     * @return string
303
     */
304
    protected function buildMethodName(? string $name): string
305
    {
306
        $result = $this->router->getVerb();
307
308
        if (null !== $name) {
309
            $split = explode('-', $name);
310
            foreach ($split as $part) {
311
                $result .= ucfirst($part);
312
            }
313
        }
314
315
        return $result;
316
    }
317
318
    /**
319
     * Convert camelCase to dashes.
320
     *
321
     * @param string $value
322
     *
323
     * @return string
324
     */
325
    protected function camelCase2Dashes(string $value): string
326
    {
327
        return strtolower(preg_replace('/([a-z])([A-Z])/', '$1-$2', $value));
328
    }
329
}
330