Test Failed
Push — master ( d45889...cddc62 )
by Divine Niiquaye
11:28 queued 08:59
created

ResolverTrait::resolveCache()   B

Complexity

Conditions 9
Paths 7

Size

Total Lines 38
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 9
eloc 19
nc 7
nop 3
dl 0
loc 38
rs 8.0555
c 1
b 0
f 0
1
<?php declare(strict_types=1);
2
3
/*
4
 * This file is part of Flight Routing.
5
 *
6
 * PHP version 7.4 and above required
7
 *
8
 * @author    Divine Niiquaye Ibok <[email protected]>
9
 * @copyright 2019 Biurad Group (https://biurad.com/)
10
 * @license   https://opensource.org/licenses/BSD-3-Clause License
11
 *
12
 * For the full copyright and license information, please view the LICENSE
13
 * file that was distributed with this source code.
14
 */
15
16
namespace Flight\Routing\Traits;
17
18
use Flight\Routing\Exceptions\{MethodNotAllowedException, UriHandlerException};
19
use Psr\Http\Message\UriInterface;
20
21
/**
22
 * The default implementation for route match.
23
 *
24
 * @author Divine Niiquaye Ibok <[email protected]>
25
 */
26
trait ResolverTrait
27
{
28
    /** @var array<int|string,mixed> */
29
    private array $optimized = [];
30
31
    /**
32
     * @param array<string,mixed>                  $route
33
     * @param array<int,array<string,bool|string>> $errors
34
     */
35
    protected function assertRoute(string $method, UriInterface $uri, array &$route, array &$errors): bool
36
    {
37
        if (!\array_key_exists($method, $route['methods'] ?? [])) {
38
            $errors[0] += $route['methods'] ?? [];
39
40
            return false;
41
        }
42
43
        if (\array_key_exists('hosts', $route)) {
44
            $hosts = \array_keys($route['hosts'], true, true);
45
            [$hostsRegex, $hostVar] = $this->compiler->compile(\implode('|', $hosts), $route['placeholders'] ?? []);
46
47
            if (!\preg_match($hostsRegex.'i', $errors[2] ??= \rtrim($uri->getHost().':'.$uri->getPort(), ':'), $matches, \PREG_UNMATCHED_AS_NULL)) {
0 ignored issues
show
Bug introduced by
It seems like AssignCoalesceNode can also be of type array<string,boolean|string>; however, parameter $subject of preg_match() 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

47
            if (!\preg_match($hostsRegex.'i', /** @scrutinizer ignore-type */ $errors[2] ??= \rtrim($uri->getHost().':'.$uri->getPort(), ':'), $matches, \PREG_UNMATCHED_AS_NULL)) {
Loading history...
48
                return false;
49
            }
50
51
            foreach ($hostVar as $key => $value) {
52
                $route['arguments'][$key] = $matches[$key] ?? $route['defaults'][$key] ?? $value;
53
            }
54
        }
55
56
        if (\array_key_exists('schemes', $route)) {
57
            $hasScheme = isset($route['schemes'][$uri->getScheme()]);
58
59
            if (!$hasScheme) {
60
                $errors[1] += $route['schemes'] ?? [];
61
62
                return false;
63
            }
64
        }
65
66
        return true;
67
    }
68
69
    /**
70
     * @return null|array<string,mixed>
71
     */
72
    protected function resolveRoute(string $path, string $method, UriInterface $uri): ?array
73
    {
74
        $errors = [[], []];
75
76
        foreach ($this->getCollection()->getRoutes() as $i => $r) {
0 ignored issues
show
Bug introduced by
It seems like getCollection() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

76
        foreach ($this->/** @scrutinizer ignore-call */ getCollection()->getRoutes() as $i => $r) {
Loading history...
77
            if (isset($r['prefix']) && !\str_starts_with($path, $r['prefix'])) {
78
                continue;
79
            }
80
            [$p, $v] = $this->optimized[$i] ??= $this->compiler->compile($r['path'], $r['placeholders'] ?? []);
81
82
            if (\preg_match($p, $path, $m, \PREG_UNMATCHED_AS_NULL)) {
83
                if (!$this->assertRoute($method, $uri, $r, $errors)) {
84
                    continue;
85
                }
86
87
                foreach ($v as $key => $value) {
88
                    $r['arguments'][$key] = $m[$key] ?? $r['defaults'][$key] ?? $value;
89
                }
90
91
                return $r;
92
            }
93
        }
94
95
        return $this->resolveError($errors, $method, $uri);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->resolveError($errors, $method, $uri) targeting Flight\Routing\Traits\Re...erTrait::resolveError() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
96
    }
97
98
    /**
99
     * @return null|array<string,mixed>
100
     */
101
    protected function resolveCache(string $path, string $method, UriInterface $uri): ?array
102
    {
103
        $errors = [[], []];
104
        $routes = $this->optimized[2] ?? $this->doCache();
0 ignored issues
show
Bug introduced by
It seems like doCache() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

104
        $routes = $this->optimized[2] ?? $this->/** @scrutinizer ignore-call */ doCache();
Loading history...
105
106
        foreach ($this->optimized[0][$path] ?? $this->optimized[1][0] ?? [] as $s => $h) {
107
            if (\is_int($s)) {
108
                $r = $routes[$h] ?? $routes->getRoutes()[$h];
109
110
                if (!$this->assertRoute($method, $uri, $r, $errors)) {
111
                    continue;
112
                }
113
114
                return $r;
115
            }
116
117
            if (!\str_starts_with($path, $s)) {
118
                continue;
119
            }
120
121
            foreach ($h as $p) {
122
                if (\preg_match($p, $path, $m, \PREG_UNMATCHED_AS_NULL)) {
123
                    $r = $routes[$o = (int) $m['MARK']] ?? $routes->getRoutes()[$o];
124
125
                    if ($this->assertRoute($method, $uri, $r, $errors)) {
126
                        $i = 0;
127
128
                        foreach ($this->optimized[1][1][$o] ?? [] as $key => $value) {
129
                            $r['arguments'][$key] = $m[++$i] ?? $r['defaults'][$key] ?? $value;
130
                        }
131
132
                        return $r;
133
                    }
134
                }
135
            }
136
        }
137
138
        return $this->resolveError($errors, $method, $uri);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->resolveError($errors, $method, $uri) targeting Flight\Routing\Traits\Re...erTrait::resolveError() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
139
    }
140
141
    /**
142
     * @param array<int,array<string,bool|string>> $errors
143
     */
144
    protected function resolveError(array $errors, string $method, UriInterface $uri)
145
    {
146
        if (!empty($errors[0])) {
147
            throw new MethodNotAllowedException(\array_keys($errors[0]), $uri->getPath(), $method);
148
        }
149
150
        if (!empty($errors[1])) {
151
            throw new UriHandlerException(
152
                \sprintf(
153
                    'Route with "%s" path requires request scheme(s) [%s], "%s" is invalid.',
154
                    $uri->getPath(),
155
                    \implode(', ', \array_keys($errors[1])),
156
                    $uri->getScheme(),
157
                ),
158
                400
159
            );
160
        }
161
162
        return null;
163
    }
164
}
165