Issues (480)

src/Url/Route/Generator.php (14 issues)

1
<?php
2
/**
3
 *
4
 */
5
6
namespace Mvc5\Url\Route;
7
8
use Closure;
9
use Mvc5\Http\HttpUri;
10
use Mvc5\Http\Uri;
11
use Mvc5\Route\Config;
12
use Mvc5\Route\Definition\Build;
13
use Mvc5\Route\Definition\Compiler;
14
use Mvc5\Route\Route;
15
use Throwable;
16
17
use function array_shift;
18
use function explode;
19
use function is_array;
20
21
use const Mvc5\{ DEFAULTS, HOST, PATH, PORT, SCHEME, SEPARATOR, TOKENS };
0 ignored issues
show
The type Mvc5\SCHEME was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
The type Mvc5\HOST was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
The type Mvc5\DEFAULTS was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
The type Mvc5\PATH was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
The type Mvc5\PORT was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
The type Mvc5\SEPARATOR was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
The type Mvc5\TOKENS was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
22
23
trait Generator
24
{
25
    /**
26
     *
27
     */
28
    use Build;
29
30
    /**
31
     * @var array
32
     */
33
    protected array $generated = [];
34
35
    /**
36
     * @var Route
37
     */
38
    protected Route $route;
39
40
    /**
41
     * @var Uri
42
     */
43
    protected Uri $uri;
44
45
    /**
46
     * @param array|Route $route
47
     * @param Uri|null $uri
48
     */
49 10
    function __construct($route, Uri $uri = null)
50
    {
51 10
        $this->route = is_array($route) ? new Config($route) : $route;
52 10
        $this->uri = $uri ?? new HttpUri;
53 10
    }
54
55
    /**
56
     * @param Route $parent
57
     * @param array|Route $route
58
     * @return Route|null
59
     * @throws Throwable
60 7
     */
61
    protected function child(Route $parent, $route) : ?Route
62 7
    {
63 7
        return $route ? $this->merge($parent, $this->route($route)) : null;
64
    }
65
66
    /**
67
     * @param string $name
68
     * @return array|Route|null
69
     */
70
    protected function config(string $name)
71
    {
72 3
        return $this->route[$name] ?? null;
73
    }
74 3
75
    /**
76
     * @param string $name
77
     * @return Route|null
78
     * @throws Throwable
79
     */
80
    protected function construct(string $name) : ?Route
81 8
    {
82
        return $this->generated[$name] ?? $this->generated[$name] = $this->generate(explode(SEPARATOR, $name));
83 8
    }
84
85
    /**
86
     * @param array $name
87
     * @param array $path
88
     * @param Route|null $parent
89
     * @return Route|null
90
     * @throws Throwable
91 8
     */
92
    protected function generate(array $name, array $path = [], Route $parent = null) : ?Route
93 8
    {
94
        return $this->resolve($this->match(array_shift($name), $parent), $name, $path);
95
    }
96
97
    /**
98
     * @param array|string|null $host
99
     * @param array $params
100
     * @return string|null
101
     * @throws Throwable
102
     */
103 8
    protected function hostname($host, array &$params) : ?string
104
    {
105 8
        return !is_array($host) ? $host : Compiler::compile($host[TOKENS], $params, $host[DEFAULTS] ?? []);
106
    }
107
108
    /**
109
     * @param string $name
110
     * @param Route|null $parent
111
     * @return Route|null
112
     * @throws Throwable
113
     */
114 7
    protected function match(string $name, Route $parent = null) : ?Route
115
    {
116 7
        return $parent ? $this->child($parent, $parent->child($name)) : $this->route($this->config($name));
117
    }
118
119
    /**
120
     * @param Route $parent
121
     * @param Route $child
122
     * @param array $config
123
     * @return Route
124
     */
125 8
    protected function merge(Route $parent, Route $child, array $config = []) : Route
126
    {
127 8
        !$child->scheme()
128
            && $config[SCHEME] = $parent->scheme();
129
130
        !$child->host()
131
            && $config[HOST] = $parent->host();
132
133
        !$child->port()
0 ignored issues
show
Bug Best Practice introduced by
The expression $child->port() of type integer|null is loosely compared to false; this is ambiguous if the integer can be 0. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
134
            && $config[PORT] = $parent->port();
135
136 3
        return $config ? $child->with($config) : $child;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $config ? $child->with($config) : $child could return the type Mvc5\Config\Model which includes types incompatible with the type-hinted return Mvc5\Route\Route. Consider adding an additional type-check to rule them out.
Loading history...
137
    }
138 3
139 3
    /**
140
     * @param Route $route
141 3
     * @param array $name
142 3
     * @param array $path
143
     * @return Route|null
144 3
     * @throws Throwable
145 3
     */
146
    protected function next(Route $route, array $name, array $path) : ?Route
147 3
    {
148
        return $name ? $this->generate($name, $path, $route) : $route->with(PATH, $path);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $name ? $this->ge...>with(Mvc5\PATH, $path) could return the type Mvc5\Config\Model which includes types incompatible with the type-hinted return Mvc5\Route\Route|null. Consider adding an additional type-check to rule them out.
Loading history...
149
    }
150
151
    /**
152
     * @param Route $route
153
     * @param array $params
154
     * @param array $options
155
     * @return array
156
     * @throws Throwable
157 7
     */
158
    protected function options(Route $route, array $params, array $options) : array
159 7
    {
160
        $options[SCHEME] ??= $route->scheme();
161
        $options[HOST] ??= $this->hostname($route->host(), $params);
162
        $options[PORT] ??= $route->port();
163
164
        $options[PATH] = $this->path($route->path(), $params);
0 ignored issues
show
It seems like $route->path() can also be of type null and string; however, parameter $segment of Mvc5\Url\Route\Generator::path() does only seem to accept array, 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

164
        $options[PATH] = $this->path(/** @scrutinizer ignore-type */ $route->path(), $params);
Loading history...
165
166
        return $options;
167
    }
168
169 7
    /**
170
     * @param array $segment
171 7
     * @param array $params
172 7
     * @param string $path
173 7
     * @return string
174
     * @throws Throwable
175 7
     */
176
    protected function path(array $segment, array $params, string $path = '') : string
177 7
    {
178
        /** @var Route $route */
179
        foreach($segment as $route) {
180
            $path .= Compiler::compile($route->tokens(), $params, $route->defaults(), $this->wildcard($route));
181
        }
182
183
        return $path;
184
    }
185
186
    /**
187 7
     * @param array|Route $route
188
     * @param array $name
189
     * @param array $path
190 7
     * @return Route|null
191 7
     * @throws Throwable
192
     */
193
    protected function resolve($route, array $name, array $path) : ?Route
194 7
    {
195
        return $route ? $this->next($route, $name, [...$path, $route]) : null;
0 ignored issues
show
It seems like $route can also be of type array; however, parameter $route of Mvc5\Url\Route\Generator::next() does only seem to accept Mvc5\Route\Route, 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

195
        return $route ? $this->next(/** @scrutinizer ignore-type */ $route, $name, [...$path, $route]) : null;
Loading history...
196
    }
197
198
    /**
199
     * @param array|Route $route
200
     * @return Route|null
201
     * @throws Throwable
202
     */
203
    protected function route($route) : ?Route
204 8
    {
205
        return !$route || $route instanceof Route ? $route : $this->build($route, false);
0 ignored issues
show
Bug Best Practice introduced by
The expression return ! $route || $rout...s->build($route, false) could return the type array which is incompatible with the type-hinted return Mvc5\Route\Route|null. Consider adding an additional type-check to rule them out.
Loading history...
206 8
    }
207
208
    /**
209
     * @param Route|null $route
210
     * @param array $params
211
     * @param array $options
212
     * @return Uri|null
213
     * @throws Throwable
214 8
     */
215
    protected function uri(Route $route = null, array $params = [], array $options = []) : ?Uri
216 8
    {
217
        return $route ? $this->uri->with($this->options($route, $params, $options)) : null;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $route ? $this->u...rams, $options)) : null could return the type Mvc5\Config\Model which includes types incompatible with the type-hinted return Mvc5\Http\Uri|null. Consider adding an additional type-check to rule them out.
Loading history...
218
    }
219
220
    /**
221
     * @param Route $route
222
     * @return Closure|null
223
     */
224
    protected function wildcard(Route $route) : ?Closure
225
    {
226 8
        return !$route->wildcard() ? null : function(string $path, array $params = []) {
227
            foreach($params as $key => $value) {
228 8
                null !== $value && $path .= SEPARATOR . $key . SEPARATOR . $value;
229
            }
230
231
            return $path;
232
        };
233
    }
234
235 7
    /**
236
     * @param string $name
237
     * @param array $params
238 2
     * @param array $options
239 2
     * @return Uri|null
240
     * @throws Throwable
241
     */
242 2
    function __invoke(string $name, array $params = [], array $options = []) : ?Uri
243 7
    {
244
        return $this->uri($this->construct($name), $params, $options);
245
    }
246
}
247