UriHelpers   A
last analyzed

Complexity

Total Complexity 35

Size/Duplication

Total Lines 285
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 45
c 0
b 0
f 0
dl 0
loc 285
rs 9.6
wmc 35

17 Methods

Rating   Name   Duplication   Size   Complexity  
A isStandardPort() 0 11 6
A validatePort() 0 4 2
A filterPath() 0 11 2
A addPathToUri() 0 11 3
A isStandardSecurePort() 0 3 2
A filterFragment() 0 7 1
A validatePath() 0 8 3
A validateFragment() 0 2 1
A filterQuery() 0 7 1
A addQueryToUri() 0 7 2
A addAuthorityToUri() 0 7 2
A validateQuery() 0 5 2
A filterScheme() 0 6 1
A isStandardUnsecurePort() 0 3 2
A addSchemeToUri() 0 7 2
A addFragmentToUri() 0 7 2
A filterUserInfo() 0 5 1
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Valkyrja Framework package.
7
 *
8
 * (c) Melech Mizrachi <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Valkyrja\Http\Message\Uri;
15
16
use Valkyrja\Http\Message\Constant\Port;
0 ignored issues
show
Bug introduced by
The type Valkyrja\Http\Message\Constant\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...
17
use Valkyrja\Http\Message\Uri\Enum\Scheme;
18
use Valkyrja\Http\Message\Uri\Exception\InvalidPathException;
19
use Valkyrja\Http\Message\Uri\Exception\InvalidPortException;
20
use Valkyrja\Http\Message\Uri\Exception\InvalidQueryException;
21
22
use function ltrim;
23
use function preg_replace;
24
use function str_starts_with;
25
use function strtolower;
26
27
/**
28
 * Trait UriHelpers.
29
 *
30
 * @author Melech Mizrachi
31
 *
32
 * @property string   $host
33
 * @property int|null $port
34
 * @property Scheme   $scheme
35
 */
36
trait UriHelpers
37
{
38
    /**
39
     * Filter a scheme.
40
     *
41
     * @param string $scheme The scheme
42
     *
43
     * @return Scheme
44
     */
45
    protected static function filterScheme(string $scheme): Scheme
46
    {
47
        $scheme = strtolower($scheme);
48
        $scheme = (string) preg_replace('#:(//)?$#', '', $scheme);
49
50
        return Scheme::from($scheme);
51
    }
52
53
    /**
54
     * Retrieve the authority component of the URI.
55
     * If no authority information is present, this method MUST return an empty
56
     * string.
57
     * The authority syntax of the URI is:
58
     * <pre>
59
     * [user-info@]host[:port]
60
     * </pre>
61
     * If the port component is not set or is the standard port for the current
62
     * scheme, it SHOULD NOT be included.
63
     *
64
     * @see https://tools.ietf.org/html/rfc3986#section-3.2
65
     *
66
     * @return string The URI authority, in "[user-info@]host[:port]" format
67
     */
68
    abstract public function getAuthority(): string;
69
70
    /**
71
     * Validate a port.
72
     *
73
     * @param int|null $port The port
74
     *
75
     * @throws InvalidPortException
76
     *
77
     * @return void
78
     */
79
    protected function validatePort(int|null $port = null): void
80
    {
81
        if (! Port::isValid($port)) {
82
            throw new InvalidPortException("Invalid port `%$port` specified; must be a valid TCP/UDP port");
83
        }
84
    }
85
86
    /**
87
     * Filter user info.
88
     */
89
    protected function filterUserInfo(string $userInfo): string
90
    {
91
        // TODO: Filter user info
92
93
        return $userInfo;
94
    }
95
96
    /**
97
     * Filter a path.
98
     *
99
     * @param string $path The path
100
     *
101
     * @throws InvalidPathException
102
     *
103
     * @return string
104
     */
105
    protected function filterPath(string $path): string
106
    {
107
        $this->validatePath($path);
108
109
        // TODO: Filter path
110
111
        if (str_starts_with($path, '/')) {
112
            return '/' . ltrim($path, '/');
113
        }
114
115
        return $path;
116
    }
117
118
    /**
119
     * Validate a path.
120
     *
121
     * @param string $path The path
122
     *
123
     * @throws InvalidPathException
124
     *
125
     * @return void
126
     */
127
    protected function validatePath(string $path): void
128
    {
129
        if (str_contains($path, '?')) {
130
            throw new InvalidPathException("Invalid path of `$path` provided; must not contain a query string");
131
        }
132
133
        if (str_contains($path, '#')) {
134
            throw new InvalidPathException("Invalid path of `$path` provided; must not contain a URI fragment");
135
        }
136
    }
137
138
    /**
139
     * Filter a query.
140
     *
141
     * @param string $query The query
142
     *
143
     * @throws InvalidQueryException
144
     *
145
     * @return string
146
     */
147
    protected function filterQuery(string $query): string
148
    {
149
        $this->validateQuery($query);
150
151
        // TODO: Filter query
152
153
        return ltrim($query, '?');
154
    }
155
156
    /**
157
     * Validate a query.
158
     *
159
     * @param string $query The query
160
     *
161
     * @throws InvalidQueryException
162
     *
163
     * @return void
164
     */
165
    protected function validateQuery(string $query): void
166
    {
167
        if (str_contains($query, '#')) {
168
            throw new InvalidQueryException(
169
                "Invalid query string of `$query` provided; must not contain a URI fragment"
170
            );
171
        }
172
    }
173
174
    /**
175
     * Filter a fragment.
176
     *
177
     * @param string $fragment The fragment
178
     *
179
     * @return string
180
     */
181
    protected function filterFragment(string $fragment): string
182
    {
183
        $this->validateFragment($fragment);
184
185
        // TODO: Filter fragment
186
187
        return ltrim($fragment, '#');
188
    }
189
190
    /**
191
     * Validate a fragment.
192
     *
193
     * @param string $fragment The fragment
194
     *
195
     * @return void
196
     */
197
    protected function validateFragment(string $fragment): void
0 ignored issues
show
Unused Code introduced by
The parameter $fragment is not used and could be removed. ( Ignorable by Annotation )

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

197
    protected function validateFragment(/** @scrutinizer ignore-unused */ string $fragment): void

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
198
    {
199
    }
200
201
    /**
202
     * Determine whether this uri is on a standard port for the scheme.
203
     *
204
     * @return bool
205
     */
206
    protected function isStandardPort(): bool
207
    {
208
        if ($this->scheme === Scheme::EMPTY) {
209
            return $this->host && $this->port === null;
210
        }
211
212
        if (! $this->host || $this->port === null) {
213
            return true;
214
        }
215
216
        return $this->isStandardUnsecurePort() || $this->isStandardSecurePort();
217
    }
218
219
    /**
220
     * Is standard HTTP port.
221
     *
222
     * @return bool
223
     */
224
    protected function isStandardUnsecurePort(): bool
225
    {
226
        return $this->scheme === Scheme::HTTP && $this->port === Port::HTTP;
227
    }
228
229
    /**
230
     * Is standard HTTPS port.
231
     *
232
     * @return bool
233
     */
234
    protected function isStandardSecurePort(): bool
235
    {
236
        return $this->scheme === Scheme::HTTPS && $this->port === Port::HTTPS;
237
    }
238
239
    /**
240
     * Add scheme to uri.
241
     *
242
     * @param string $uri The uri
243
     *
244
     * @return string
245
     */
246
    protected function addSchemeToUri(string $uri): string
247
    {
248
        if (($scheme = $this->scheme) !== Scheme::EMPTY) {
249
            $uri .= $scheme->value . ':';
250
        }
251
252
        return $uri;
253
    }
254
255
    /**
256
     * Add authority to uri.
257
     *
258
     * @param string $uri The uri
259
     *
260
     * @return string
261
     */
262
    protected function addAuthorityToUri(string $uri): string
263
    {
264
        if ($authority = $this->getAuthority()) {
265
            $uri .= '//' . $authority;
266
        }
267
268
        return $uri;
269
    }
270
271
    /**
272
     * Add path to uri.
273
     *
274
     * @param string $uri The uri
275
     *
276
     * @return string
277
     */
278
    protected function addPathToUri(string $uri): string
279
    {
280
        if ($path = $this->path) {
281
            if ($path[0] !== '/') {
282
                $path = '/' . $path;
283
            }
284
285
            $uri .= $path;
286
        }
287
288
        return $uri;
289
    }
290
291
    /**
292
     * Add query to uri.
293
     *
294
     * @param string $uri The uri
295
     *
296
     * @return string
297
     */
298
    protected function addQueryToUri(string $uri): string
299
    {
300
        if ($query = $this->query) {
301
            $uri .= '?' . $query;
302
        }
303
304
        return $uri;
305
    }
306
307
    /**
308
     * Add fragment to uri.
309
     *
310
     * @param string $uri The uri
311
     *
312
     * @return string
313
     */
314
    protected function addFragmentToUri(string $uri): string
315
    {
316
        if ($fragment = $this->fragment) {
317
            $uri .= '#' . $fragment;
318
        }
319
320
        return $uri;
321
    }
322
}
323