Test Failed
Pull Request — master (#26)
by Divine Niiquaye
02:27
created

DataTrait::end()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 7
rs 10

1 Method

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