HttpsBuilder::buildAuthority()   A
last analyzed

Complexity

Conditions 5
Paths 16

Size

Total Lines 21
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 10
nc 16
nop 0
dl 0
loc 21
rs 9.6111
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace Keppler\Url\Builder\Schemes\Https;
5
6
use Keppler\Url\Builder\Schemes\Https\Bags\HttpsMutablePath;
7
use Keppler\Url\Builder\Schemes\Https\Bags\HttpsMutableQuery;
8
use Keppler\Url\Interfaces\Mutable\MutableSchemeInterface;
9
use Keppler\Url\Scheme\Schemes\Https\HttpsImmutable;
10
11
/**
12
 * Class HttpsBuilder
13
 *
14
 * @package Keppler\Url\Builder\Schemes\Https
15
 */
16
class HttpsBuilder implements MutableSchemeInterface
17
{
18
    /**
19
     * The default scheme for this class
20
     *
21
     * @var string
22
     */
23
    const SCHEME = 'https';
24
25
    /**
26
     * authority = [ userinfo "@" ] host [ ":" port ]
27
     *
28
     * -- An optional authority component preceded by two slashes (//),
29
     * comprising:
30
     *
31
     *   - An optional userinfo subcomponent that may consist of a user name
32
     *   and an optional password preceded by a colon (:), followed by an at
33
     *   symbol (@). Use of the format username:password in the userinfo
34
     *   subcomponent is deprecated for security reasons. Applications should
35
     *   not render as clear text any data after the first colon (:) found
36
     *   within a userinfo subcomponent unless the data after the colon is the
37
     *   empty string (indicating no password).
38
     *
39
     *  - An optional host subcomponent, consisting of either a registered name
40
     *  (including but not limited to a hostname), or an IP address. IPv4
41
     *  addresses must be in dot-decimal notation, and IPv6 addresses must be
42
     *  enclosed in brackets ([]).[10][c]
43
     *
44
     *   - An optional port subcomponent preceded by a colon (:).
45
     *
46
     * @var string
47
     */
48
    private $authority = '';
49
50
    /**
51
     * userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
52
     *
53
     * @var string
54
     */
55
    private $user = '';
56
57
    /**
58
     * Usage is highly discouraged
59
     *
60
     * @var string
61
     */
62
    private $password = '';
63
64
    /**
65
     * host = IP-literal / IPv4address / reg-name
66
     *
67
     * @var string
68
     */
69
    private $host = '';
70
71
    /**
72
     * port = *DIGIT
73
     *
74
     * Ports can't be negative, -1 should be considered the default value and
75
     * ignored
76
     *
77
     * INVALID-PORT
78
     *  Either the local or foreign port was improperly
79
     *  specified.  This should be returned if either or
80
     *  both of the port ids were out of range (TCP port
81
     *  numbers are from 1-65535), negative integers, reals or
82
     *  in any fashion not recognized as a non-negative integer.
83
     *
84
     * @see https://www.ietf.org/rfc/rfc1413.txt
85
     * @var int
86
     */
87
    private $port = -1;
88
89
    /**
90
     * fragment = *( pchar / "/" / "?" )
91
     *
92
     * @var string
93
     */
94
    private $fragment = '';
95
96
    /**
97
     * @var HttpsMutableQuery
98
     */
99
    private $queryBag;
100
101
    /**
102
     * @var HttpsMutablePath
103
     */
104
    private $pathBag;
105
106
    /**
107
     * HttpsBuilder constructor.
108
     *
109
     * @param HttpsImmutable|null $https
110
     */
111
    public function __construct(HttpsImmutable $https = null)
112
    {
113
        $this->pathBag = new HttpsMutablePath();
114
        $this->queryBag = new HttpsMutableQuery();
115
        if (null !== $https) {
116
            $this->populate($https);
117
118
            $this->authority = $https->getAuthority();
119
            $this->user = $https->getUser();
120
            $this->password = $https->getPassword();
121
            $this->host = $https->getHost();
122
            $this->port = null === $https->getPort() ? -1 : $https->getPort();
123
            $this->fragment = $https->getFragment();
124
        }
125
    }
126
127
    ///////////////////////////
128
    /// PRIVATE FUNCTIONS  ///
129
    /////////////////////////
130
    /**
131
     * @param HttpsImmutable $https
132
     */
133
    private function populate(HttpsImmutable $https): void
134
    {
135
        foreach ($https->getPathBag()->all() as $key => $value) {
136
            $this->pathBag->set($key, $value);
137
        }
138
139
        foreach ($https->getQueryBag()->all() as $key => $value) {
140
            $this->queryBag->set($key, $value);
141
        }
142
    }
143
144
    /**
145
     * Recreate the authority
146
     */
147
    private function buildAuthority(): void
148
    {
149
        $authority = '';
150
151
        if (!empty($this->user)) {
152
            $authority .= $this->user;
153
        }
154
155
        if (!empty($this->password)) {
156
            $authority .= ':'.$this->password;
157
        }
158
159
        if (!empty($this->host)) {
160
            $authority .= '@'.$this->host;
161
        }
162
163
        if (-1 !== $this->port) {
164
            $authority .= ':'.$this->port;
165
        }
166
167
        $this->authority = $authority;
168
    }
169
170
    //////////////////////////
171
    /// GETTER FUNCTIONS  ///
172
    ////////////////////////
173
174
    /**
175
     * @return string
176
     */
177
    public function getAuthority(): string
178
    {
179
        return $this->authority;
180
    }
181
182
    /**
183
     * @return string
184
     */
185
    public function getUser(): string
186
    {
187
        return $this->user;
188
    }
189
190
    /**
191
     * @return string
192
     */
193
    public function getPassword(): string
194
    {
195
        return $this->password;
196
    }
197
198
    /**
199
     * @return string
200
     */
201
    public function getHost(): string
202
    {
203
        return $this->host;
204
    }
205
206
    /**
207
     * @return int|null
208
     */
209
    public function getPort(): ?int
210
    {
211
        return -1 === $this->port ? null : $this->port;
212
    }
213
214
    /**
215
     * @return string
216
     */
217
    public function getFragment(): string
218
    {
219
        return $this->fragment;
220
    }
221
222
    /**
223
     * @return HttpsMutableQuery
224
     */
225
    public function getQueryBag(): HttpsMutableQuery
226
    {
227
        return $this->queryBag;
228
    }
229
230
    /**
231
     * @return HttpsMutablePath
232
     */
233
    public function getPathBag(): HttpsMutablePath
234
    {
235
        return $this->pathBag;
236
    }
237
238
    //////////////////////////
239
    /// SETTER FUNCTIONS  ///
240
    ////////////////////////
241
242
    /**
243
     * @param string $user
244
     *
245
     * @return HttpsBuilder
246
     */
247
    public function setUser(string $user): self
248
    {
249
        $this->user = $user;
250
        // Rebuild the authority
251
        $this->buildAuthority();
252
253
        return $this;
254
    }
255
256
    /**
257
     * @param string $password
258
     *
259
     * @return HttpsBuilder
260
     */
261
    public function setPassword(string $password): self
262
    {
263
        $this->password = $password;
264
        // Rebuild the authority
265
        $this->buildAuthority();
266
267
        return $this;
268
    }
269
270
    /**
271
     * @param string $host
272
     *
273
     * @return HttpsBuilder
274
     */
275
    public function setHost(string $host): self
276
    {
277
        $this->host = $host;
278
        // Rebuild the authority
279
        $this->buildAuthority();
280
281
        return $this;
282
    }
283
284
    /**
285
     * @param int $port
286
     *
287
     * @return HttpsBuilder
288
     * @throws \LogicException
289
     */
290
    public function setPort(int $port): self
291
    {
292
        if (abs($port) !== $port) {
293
            throw new \LogicException('Ports cannot be negative');
294
        }
295
296
        $this->port = $port;
297
        // Rebuild the authority
298
        $this->buildAuthority();
299
300
        return $this;
301
    }
302
303
    /**
304
     * @param string $fragment
305
     *
306
     * @return HttpsBuilder
307
     */
308
    public function setFragment(string $fragment): self
309
    {
310
        $this->fragment = $fragment;
311
312
        return $this;
313
    }
314
315
    /////////////////////////////////
316
    /// INTERFACE IMPLEMENTATION  ///
317
    /////////////////////////////////
318
319
    /**
320
     * @param bool $urlEncode
321
     *
322
     * @return string
323
     */
324
    public function build(bool $urlEncode = false): string
325
    {
326
        $url = self::SCHEME.'://';
327
328
        $url .= $this->authority;
329
330
        if ($urlEncode) {
331
            $url .= $this->pathBag->encoded();
332
            $url .= $this->queryBag->encoded();
333
        } else {
334
            $url .= $this->pathBag->raw();
335
            $url .= $this->queryBag->raw();
336
        }
337
338
        if (!empty($this->fragment)) {
339
            $url .= '#'.$this->fragment;
340
        }
341
342
        return $url;
343
    }
344
345
    /**
346
     * Returns all the components of the scheme including
347
     *  any bags in the form of an array
348
     *
349
     * @return array
350
     */
351
    public function all(): array
352
    {
353
        return [
354
            'scheme'    => self::SCHEME,
355
            'authority' => $this->authority,
356
            'user'      => $this->user,
357
            'password'  => $this->password,
358
            'host'      => $this->host,
359
            'port'      => -1 === $this->port ? null : $this->port,
360
            'query'     => $this->queryBag->all(),
361
            'path'      => $this->pathBag->all(),
362
            'fragment'  => $this->fragment,
363
        ];
364
    }
365
366
    /**
367
     * Return the raw unaltered url
368
     *
369
     * @return string
370
     */
371
    public function raw(): string
372
    {
373
        return $this->build(false);
374
    }
375
376
    /**
377
     * @return string
378
     */
379
    public function encoded(): string
380
    {
381
        return $this->build(true);
382
    }
383
384
    /**
385
     * Returns the scheme associated with the class
386
     *
387
     * @return string
388
     */
389
    public function getScheme(): string
390
    {
391
        return self::SCHEME;
392
    }
393
}