Uri::__construct()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 18
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

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

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php declare(strict_types=1);
2
3
namespace One;
4
5
use InvalidArgumentException;
6
use Psr\Http\Message\UriInterface;
7
8
/**
9
 * Uri class implementation to ease migration when using other framework vendor. Use psr-7 standard
10
 */
11
class Uri implements UriInterface
12
{
13
    /**
14
     * Uri scheme (without "://" suffix)
15
     *
16
     * @var string
17
     */
18
    protected $scheme = '';
19
20
    /**
21
     * Uri user
22
     *
23
     * @var string
24
     */
25
    protected $user = '';
26
27
    /**
28
     * Uri password
29
     *
30
     * @var string
31
     */
32
    protected $password = '';
33
34
    /**
35
     * Uri host
36
     *
37
     * @var string
38
     */
39
    protected $host = '';
40
41
    /**
42
     * Uri port number
43
     *
44
     * @var int|null
45
     */
46
    protected $port;
47
48
    /**
49
     * Uri path
50
     *
51
     * @var string
52
     */
53
    protected $path = '';
54
55
    /**
56
     * Uri query string (without "?" prefix)
57
     *
58
     * @var string
59
     */
60
    protected $query = '';
61
62
    /**
63
     * Uri fragment string (without "#" prefix)
64
     *
65
     * @var string
66
     */
67
    protected $fragment = '';
68
69
    /**
70
     * Instance new Uri.
71
     *
72
     * @param string $scheme   Uri scheme.
73
     * @param string $host     Uri host.
74
     * @param int    $port     Uri port number.
75
     * @param string $path     Uri path.
76
     * @param string $query    Uri query string.
77
     * @param string $fragment Uri fragment.
78
     * @param string $user     Uri user.
79
     * @param string $password Uri password.
80
     */
81
    public function __construct(
82
        string $scheme,
83
        string $host = '',
84
        ?int $port = null,
85
        string $path = '/',
86
        string $query = '',
87
        string $fragment = '',
88
        string $user = '',
89
        string $password = ''
90
    ) {
91
        $this->scheme = $this->filterScheme($scheme);
92
        $this->host = $host;
93
        $this->port = $this->filterPort($port);
94
        $this->path = empty($path) ? '/' : $this->filterPath($path);
95
        $this->query = $this->filterQuery($query);
96
        $this->fragment = $this->filterQuery($fragment);
97
        $this->user = $user;
98
        $this->password = $password;
99
    }
100
101
    /**
102
     * {@inheritdoc}
103
     */
104
    public function __toString()
105
    {
106
        $scheme = $this->getScheme();
107
        $authority = $this->getAuthority();
108
        $path = $this->getPath();
109
        $query = $this->getQuery();
110
        $fragment = $this->getFragment();
111
112
        return ($scheme ? $scheme . ':' : '')
113
            . ($authority ? '//' . $authority : '')
114
            . $path
115
            . ($query ? '?' . $query : '')
116
            . ($fragment ? '#' . $fragment : '');
117
    }
118
119
    /**
120
     * {@inheritdoc}
121
     */
122
    public function getScheme()
123
    {
124
        return $this->scheme;
125
    }
126
127
    /**
128
     * {@inheritdoc}
129
     */
130
    public function getAuthority()
131
    {
132
        $userInfo = $this->getUserInfo();
133
        $host = $this->getHost();
134
        $port = $this->getPort();
135
136
        return ($userInfo ? $userInfo . '@' : '') . $host . ($port !== null ? ':' . $port : '');
137
    }
138
139
    /**
140
     * {@inheritdoc}
141
     */
142
    public function getUserInfo()
143
    {
144
        return $this->user . ($this->password ? ':' . $this->password : '');
145
    }
146
147
    /**
148
     * {@inheritdoc}
149
     */
150
    public function getHost()
151
    {
152
        return $this->host;
153
    }
154
155
    /**
156
     * {@inheritdoc}
157
     */
158
    public function getPort()
159
    {
160
        return $this->port !== null && ! $this->hasStandardPort() ? $this->port : null;
161
    }
162
163
    /**
164
     * {@inheritdoc}
165
     */
166
    public function getPath()
167
    {
168
        return $this->path;
169
    }
170
171
    /**
172
     * {@inheritdoc}
173
     */
174
    public function getQuery()
175
    {
176
        return $this->query;
177
    }
178
179
    /**
180
     * {@inheritdoc}
181
     */
182
    public function getFragment()
183
    {
184
        return $this->fragment;
185
    }
186
187
    /**
188
     * {@inheritdoc}
189
     */
190
    public function withScheme($scheme)
191
    {
192
        $scheme = $this->filterScheme($scheme);
193
        $clone = clone $this;
194
        $clone->scheme = $scheme;
195
196
        return $clone;
197
    }
198
199
    /**
200
     * {@inheritdoc}
201
     */
202
    public function withUserInfo($user, $password = null)
203
    {
204
        $clone = clone $this;
205
        $clone->user = $user;
206
        $clone->password = $password ?: '';
207
208
        return $clone;
209
    }
210
211
    /**
212
     * {@inheritdoc}
213
     */
214
    public function withHost($host)
215
    {
216
        $clone = clone $this;
217
        $clone->host = $host;
218
219
        return $clone;
220
    }
221
222
    /**
223
     * {@inheritdoc}
224
     */
225
    public function withPort($port)
226
    {
227
        $port = $this->filterPort($port);
228
        $clone = clone $this;
229
        $clone->port = $port;
230
231
        return $clone;
232
    }
233
234
    /**
235
     * {@inheritdoc}
236
     */
237
    public function withPath($path)
238
    {
239
        $clone = clone $this;
240
        $clone->path = $this->filterPath($path);
241
242
        return $clone;
243
    }
244
245
    /**
246
     * {@inheritdoc}
247
     */
248
    public function withQuery($query)
249
    {
250
        return $this->withString($query);
251
    }
252
253
    /**
254
     * {@inheritdoc}
255
     */
256
    public function withFragment($fragment)
257
    {
258
        return $this->withString($fragment, 'fragment');
259
    }
260
261
    /**
262
     * get Base Url
263
     *
264
     * @access public
265
     */
266
    public function getBaseUrl(): string
267
    {
268
        $scheme = $this->getScheme();
269
        $authority = $this->getAuthority();
270
271
        return ($scheme ? $scheme . ':' : '')
272
            . ($authority ? '//' . $authority : '');
273
    }
274
275
    /**
276
     * withString function.
277
     *
278
     * @access protected
279
     * @param string $name (default: 'query')
280
     */
281
    protected function withString(string $string, string $name = 'query'): self
282
    {
283
        $string = ltrim((string) $string, '#');
284
        $clone = clone $this;
285
        $clone->{$name} = $this->filterQuery($string);
286
287
        return $clone;
288
    }
289
290
    /*
291
        END OF UriInterface Implementation
292
    */
293
294
    /**
295
     * filter scheme given to only allow certain scheme, no file:// or ftp:// or other scheme because its http message uri interface
296
     *
297
     * @access protected
298
     * @throws InvalidArgumentException if not corret scheme is present
299
     */
300
    protected function filterScheme(string $scheme): string
301
    {
302
        static $valid = [
303
            '' => true,
304
            'https' => true,
305
            'http' => true,
306
        ];
307
308
        $scheme = str_replace('://', '', strtolower($scheme));
309
        if (! isset($valid[$scheme])) {
310
            throw new InvalidArgumentException('Uri scheme must be one of: "", "https", "http"');
311
        }
312
313
        return $scheme;
314
    }
315
316
    /**
317
     * Filter allowable port to minimize risk
318
     *
319
     * @access protected
320
     * @throws InvalidArgumentException for incorrect port assigned
321
     */
322
    protected function filterPort(?int $port): ?int
323
    {
324
        if ((integer) $port >= 0 && (integer) $port <= 65535) {
325
            return $port;
326
        }
327
328
        throw new InvalidArgumentException('Uri port must be null or an integer between 1 and 65535 (inclusive)');
329
    }
330
331
    /**
332
     * Path allowed chars filter, no weird path on uri yes?.
333
     *
334
     * @access protected
335
     * @return string of cleared path
336
     */
337
    protected function filterPath(string $path): string
338
    {
339
        return preg_replace_callback(
340
            '/(?:[^a-zA-Z0-9_\-\.~:@&=\+\$,\(\)\/;%]+|%(?![A-Fa-f0-9]{2}))/',
341
            function ($match) {
342
                return rawurlencode($match[0]);
343
            },
344
            $path
345
        );
346
    }
347
348
    /**
349
     * replace query to clear not allowed chars
350
     *
351
     * @access protected
352
     * @return string of replaced query
353
     */
354
    protected function filterQuery(string $query): string
355
    {
356
        return preg_replace_callback(
357
            '/(?:[^a-zA-Z0-9_\-\.~!\$&\'\(\)\*\+,;=%:@\/\?]+|%(?![A-Fa-f0-9]{2}))/',
358
            function ($match) {
359
                return rawurlencode($match[0]);
360
            },
361
            $query
362
        );
363
    }
364
365
    /**
366
     * cek if current uri scheme use standard port
367
     *
368
     * @access protected
369
     */
370
    protected function hasStandardPort(): bool
371
    {
372
        return ($this->scheme === 'http' && $this->port === 80) || ($this->scheme === 'https' && $this->port === 443);
373
    }
374
}
375