Passed
Branch master (d5e0ae)
by Divine Niiquaye
02:40
created

DataTrait::hasMethod()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of Flight Routing.
7
 *
8
 * PHP version 7.4 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 Flight\Routing\Exceptions\{InvalidControllerException, UriHandlerException};
21
use Flight\Routing\Route;
22
use Flight\Routing\Handlers\ResourceHandler;
23
24
trait DataTrait
25
{
26
    /** @var array<string,mixed> */
27
    protected array $data;
28
29
    /**
30
     * Sets the route path prefix.
31
     *
32
     * @return $this
33
     */
34 26
    public function prefix(string $path)
35
    {
36 26
        if (!empty($path)) {
37 23
            $uri = $this->data['path'] ?? '/';
38
39 23
            if (\strlen($uri) > 1 && isset(Route::URL_PREFIX_SLASHES[$uri[1]])) {
40 2
                $uri = \substr($uri, 1);
41
            }
42
43 23
            if (isset(Route::URL_PREFIX_SLASHES[$path[-1]])) {
44 3
                $uri = \substr($uri, 1);
45
            }
46
47 23
            \preg_match(Route::PRIORITY_REGEX, $this->data['path'] = ('/' . \ltrim($path, '/')) . $uri, $pM);
48 23
            $this->data['prefix'] = !empty($pM[1] ?? null) ? $pM[1] : null;
49
        }
50
51 26
        return $this;
52
    }
53
54
    /**
55
     * Sets the route path pattern.
56
     *
57
     * @return $this
58
     */
59 212
    public function path(string $pattern)
60
    {
61 212
        if (\preg_match(Route::RCA_PATTERN, $pattern, $matches, \PREG_UNMATCHED_AS_NULL)) {
62 212
            if (null !== $matches[1]) {
63 6
                $this->data['schemes'][$matches[1]] = true;
64
            }
65
66 212
            if (null !== $matches[2]) {
67 13
                $this->data['hosts'][$matches[2]] = true;
68
            }
69
70 212
            if (null !== $matches[5]) {
71 6
                $handler = $matches[4] ?? $this->data['handler'] ?? null;
72 6
                $this->data['handler'] = !empty($handler) ? [$handler, $matches[5]] : $matches[5];
73
            }
74
75 212
            if (empty($matches[3])) {
76 3
                throw new UriHandlerException(\sprintf('The route pattern "%s" is invalid as route path must be present in pattern.', $pattern));
77
            }
78
79 209
            \preg_match(Route::PRIORITY_REGEX, $this->data['path'] = '/' . \ltrim($matches[3], '/'), $pM);
80 209
            $this->data['prefix'] = !empty($pM[1] ?? null) ? $pM[1] : null;
81
        }
82
83 209
        return $this;
84
    }
85
86
    /**
87
     * Sets the requirement for the HTTP method.
88
     *
89
     * @param string $methods the HTTP method(s) name
90
     *
91
     * @return $this
92
     */
93 12
    public function method(string ...$methods)
94
    {
95 12
        foreach ($methods as $method) {
96 11
            $this->data['methods'][\strtoupper($method)] = true;
97
        }
98
99 12
        return $this;
100
    }
101
102
    /**
103
     * Sets the requirement of host on this Route.
104
     *
105
     * @param string $hosts The host for which this route should be enabled
106
     *
107
     * @return $this
108
     */
109 21
    public function domain(string ...$hosts)
110
    {
111 21
        foreach ($hosts as $host) {
112 20
            \preg_match(Route::URL_PATTERN, $host, $matches, \PREG_UNMATCHED_AS_NULL);
113
114 20
            if (isset($matches[1])) {
115 13
                $this->data['schemes'][$matches[1]] = true;
116
            }
117
118 20
            if (isset($matches[2])) {
119 20
                $this->data['hosts'][$matches[2]] = true;
120
            }
121
        }
122
123 21
        return $this;
124
    }
125
126
    /**
127
     * Sets the requirement of domain scheme on this Route.
128
     *
129
     * @param string ...$schemes
130
     *
131
     * @return $this
132
     */
133 16
    public function scheme(string ...$schemes)
134
    {
135 16
        foreach ($schemes as $scheme) {
136 15
            $this->data['schemes'][$scheme] = true;
137
        }
138
139 16
        return $this;
140
    }
141
142
    /**
143
     * Sets the route name.
144
     *
145
     * @return $this
146
     */
147 37
    public function bind(string $routeName)
148
    {
149 37
        $this->data['name'] = $routeName;
150
151 37
        return $this;
152
    }
153
154
    /**
155
     * Sets the parameter value for a route handler.
156
     *
157
     * @param mixed $value The parameter value
158
     *
159
     * @return $this
160
     */
161 32
    public function argument(string $parameter, $value)
162
    {
163 32
        if (\is_numeric($value)) {
164 10
            $value = (int) $value;
165 27
        } elseif (\is_string($value)) {
166 17
            $value = \rawurldecode($value);
167
        }
168
169 32
        $this->data['arguments'][$parameter] = $value;
170
171 32
        return $this;
172
    }
173
174
    /**
175
     * Sets the parameter values for a route handler.
176
     *
177
     * @param array<int|string> $parameters The route handler parameters
178
     *
179
     * @return $this
180
     */
181 8
    public function arguments(array $parameters)
182
    {
183 8
        foreach ($parameters as $variable => $value) {
184 2
            $this->argument($variable, $value);
185
        }
186
187 8
        return $this;
188
    }
189
190
    /**
191
     * Sets the route code that should be executed when matched.
192
     *
193
     * @param mixed $to PHP class, object or callable that returns the response when matched
194
     *
195
     * @return $this
196
     */
197 4
    public function run($to)
198
    {
199 4
        if (isset($this->data['namespace'])) {
200 2
            $to = $this->resolveNamespace($this->data['namespace'], $to);
201 2
            unset($this->data['namespace']); // No longer needed.
202
        }
203
204 4
        $this->data['handler'] = $to;
205
206 4
        return $this;
207
    }
208
209
    /**
210
     * Sets the missing namespace on route's handler.
211
     *
212
     * @throws InvalidControllerException if $namespace is invalid
213
     *
214
     * @return $this
215
     */
216 6
    public function namespace(string $namespace)
217
    {
218 6
        if (!empty($namespace)) {
219 6
            if ('\\' === $namespace[-1]) {
220 1
                throw new InvalidControllerException(\sprintf('Namespace "%s" provided for routes must not end with a "\\".', $namespace));
221
            }
222
223 6
            if (isset($this->data['handler'])) {
224 5
                $this->data['handler'] = $this->resolveNamespace($namespace, $this->data['handler']);
225
            } else {
226 2
                $this->data['namespace'] = ($this->data['namespace'] ?? '') . $namespace;
227
            }
228
        }
229
230 6
        return $this;
231
    }
232
233
    /**
234
     * Attach a named middleware group(s) to route.
235
     *
236
     * @return $this
237
     */
238 6
    public function piped(string ...$to)
239
    {
240 6
        foreach ($to as $namedMiddleware) {
241 6
            $this->data['middlewares'][$namedMiddleware] = true;
242
        }
243
244 6
        return $this;
245
    }
246
247
    /**
248
     * Sets the requirement for a route variable.
249
     *
250
     * @param string|string[] $regexp The regexp to apply
251
     *
252
     * @return $this
253
     */
254 16
    public function assert(string $variable, $regexp)
255
    {
256 16
        $this->data['patterns'][$variable] = $regexp;
257
258 16
        return $this;
259
    }
260
261
    /**
262
     * Sets the requirements for a route variable.
263
     *
264
     * @param array<string,string|string[]> $regexps The regexps to apply
265
     *
266
     * @return $this
267
     */
268 7
    public function asserts(array $regexps)
269
    {
270 7
        foreach ($regexps as $variable => $regexp) {
271 3
            $this->assert($variable, $regexp);
272
        }
273
274 7
        return $this;
275
    }
276
277
    /**
278
     * Sets the default value for a route variable.
279
     *
280
     * @param mixed $default The default value
281
     *
282
     * @return $this
283
     */
284 8
    public function default(string $variable, $default)
285
    {
286 8
        $this->data['defaults'][$variable] = $default;
287
288 8
        return $this;
289
    }
290
291
    /**
292
     * Sets the default values for a route variables.
293
     *
294
     * @param array<string,mixed> $values
295
     *
296
     * @return $this
297
     */
298 7
    public function defaults(array $values)
299
    {
300 7
        foreach ($values as $variable => $default) {
301 3
            $this->default($variable, $default);
302
        }
303
304 7
        return $this;
305
    }
306
307 87
    public function hasMethod(string $method): bool
308
    {
309 87
        return isset($this->data['methods'][$method]);
310
    }
311
312 82
    public function hasScheme(string $scheme): bool
313
    {
314 82
        return empty($s = $this->data['schemes'] ?? []) || isset($s[$scheme]);
315
    }
316
317 43
    public function getName(): ?string
318
    {
319 43
        return $this->data['name'] ?? null;
320
    }
321
322 180
    public function getPath(): string
323
    {
324 180
        return $this->data['path'] ?? '/';
325
    }
326
327
    /**
328
     * @return array<int,string>
329
     */
330 54
    public function getMethods(): array
331
    {
332 54
        return \array_keys($this->data['methods'] ?? []);
333
    }
334
335
    /**
336
     * @return array<int,string>
337
     */
338 30
    public function getSchemes(): array
339
    {
340 30
        return \array_keys($this->data['schemes'] ?? []);
341
    }
342
343
    /**
344
     * @return array<int,string>
345
     */
346 136
    public function getHosts(): array
347
    {
348 136
        return \array_keys($this->data['hosts'] ?? []);
349
    }
350
351
    /**
352
     * @return array<int|string,mixed>
353
     */
354 78
    public function getArguments(): array
355
    {
356 78
        return $this->data['arguments'] ?? [];
357
    }
358
359
    /**
360
     * @return mixed
361
     */
362 77
    public function getHandler()
363
    {
364 77
        return $this->data['handler'] ?? null;
365
    }
366
367
    /**
368
     * @return array<int|string,mixed>
369
     */
370 53
    public function getDefaults(): array
371
    {
372 53
        return $this->data['defaults'] ?? [];
373
    }
374
375
    /**
376
     * @return array<string,string|string[]>
377
     */
378 134
    public function getPatterns(): array
379
    {
380 134
        return $this->data['patterns'] ?? [];
381
    }
382
383
    /**
384
     * Return the list of attached grouped middlewares.
385
     *
386
     * @return array<int,string>
387
     */
388 52
    public function getPiped(): array
389
    {
390 52
        return \array_keys($this->data['middlewares'] ?? []);
391
    }
392
393
    /**
394
     * Return's the static prefixed portion of the route path else null.
395
     *
396
     * @see Flight\Routing\RouteCollection::getRoutes()
397
     */
398 119
    public function getStaticPrefix(): ?string
399
    {
400 119
        return $this->data['prefix'] ?? null;
401
    }
402
403
    /**
404
     * @internal skip throwing an exception and return existing $controller
405
     *
406
     * @param callable|object|string|string[] $controller
407
     *
408
     * @return mixed
409
     */
410 6
    protected function resolveNamespace(string $namespace, $controller)
411
    {
412 6
        if ($controller instanceof ResourceHandler) {
413 1
            return $controller->namespace($namespace);
414
        }
415
416 6
        if (\is_string($controller) && '\\' === $controller[0]) {
417 6
            $controller = $namespace . $controller;
418 2
        } elseif ((\is_array($controller) && 2 == \count($controller, \COUNT_RECURSIVE)) && \is_string($controller[0])) {
419 1
            $controller[0] = $this->resolveNamespace($namespace, $controller[0]);
420
        }
421
422 6
        return $controller;
423
    }
424
}
425