HttpBuilder   A
last analyzed

Complexity

Total Complexity 34

Size/Duplication

Total Lines 377
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 82
dl 0
loc 377
rs 9.68
c 0
b 0
f 0
wmc 34

21 Methods

Rating   Name   Duplication   Size   Complexity  
A setFragment() 0 5 1
A setPassword() 0 7 1
A __construct() 0 14 3
A getHost() 0 3 1
A setUser() 0 7 1
A buildAuthority() 0 21 5
A encoded() 0 3 1
A getAuthority() 0 3 1
A setHost() 0 7 1
A setPort() 0 11 2
A getScheme() 0 3 1
A raw() 0 3 1
A getPassword() 0 3 1
A all() 0 12 2
A getQueryBag() 0 3 1
A getUser() 0 3 1
A getPathBag() 0 3 1
A build() 0 19 3
A populate() 0 8 3
A getFragment() 0 3 1
A getPort() 0 3 2
1
<?php
2
declare(strict_types=1);
3
4
namespace Keppler\Url\Builder\Schemes\Http;
5
6
use Keppler\Url\Builder\Schemes\Http\Bags\HttpMutablePath;
7
use Keppler\Url\Builder\Schemes\Http\Bags\HttpMutableQuery;
8
use Keppler\Url\Interfaces\Mutable\MutableSchemeInterface;
9
use Keppler\Url\Scheme\Schemes\Http\HttpImmutable;
10
11
/**
12
 * Class HttpBuilder
13
 *
14
 * @package Keppler\Url\Builder\Schemes\Https
15
 */
16
class HttpBuilder implements MutableSchemeInterface
17
{
18
    /**
19
     * The default scheme for this class
20
     *
21
     * @var string
22
     */
23
    const SCHEME = 'http';
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 HttpMutableQuery
98
     */
99
    private $queryBag;
100
101
    /**
102
     * @var HttpMutablePath
103
     */
104
    private $pathBag;
105
106
    /**
107
     * HttpBuilder constructor.
108
     *
109
     * @param HttpImmutable $http
110
     */
111
    public function __construct(HttpImmutable $http = null)
112
    {
113
        $this->pathBag = new HttpMutablePath();
114
        $this->queryBag = new HttpMutableQuery();
115
116
        if (null !== $http) {
117
            $this->populate($http);
118
119
            $this->authority = $http->getAuthority();
120
            $this->user = $http->getUser();
121
            $this->password = $http->getPassword();
122
            $this->host = $http->getHost();
123
            $this->port = null === $http->getPort() ? -1 : $http->getPort();
124
            $this->fragment = $http->getFragment();
125
        }
126
    }
127
128
    ///////////////////////////
129
    /// PRIVATE FUNCTIONS  ///
130
    /////////////////////////
131
    /**
132
     * @param HttpImmutable $http
133
     */
134
    private function populate(HttpImmutable $http): void
135
    {
136
        foreach ($http->getPathBag()->all() as $key => $value) {
137
            $this->pathBag->set($key, $value);
138
        }
139
140
        foreach ($http->getQueryBag()->all() as $key => $value) {
141
            $this->queryBag->set($key, $value);
142
        }
143
    }
144
145
    /**
146
     * Recreate the authority
147
     */
148
    private function buildAuthority(): void
149
    {
150
        $authority = '';
151
152
        if (!empty($this->user)) {
153
            $authority .= $this->user;
154
        }
155
156
        if (!empty($this->password)) {
157
            $authority .= ':'.$this->password;
158
        }
159
160
        if (!empty($this->host)) {
161
            $authority .= '@'.$this->host;
162
        }
163
164
        if (-1 !== $this->port) {
165
            $authority .= ':'.$this->port;
166
        }
167
168
        $this->authority = $authority;
169
    }
170
171
    //////////////////////////
172
    /// GETTER FUNCTIONS  ///
173
    ////////////////////////
174
175
    /**
176
     * @return string
177
     */
178
    public function getAuthority(): string
179
    {
180
        return $this->authority;
181
    }
182
183
    /**
184
     * @return string
185
     */
186
    public function getUser(): string
187
    {
188
        return $this->user;
189
    }
190
191
    /**
192
     * @return string
193
     */
194
    public function getPassword(): string
195
    {
196
        return $this->password;
197
    }
198
199
    /**
200
     * @return string
201
     */
202
    public function getHost(): string
203
    {
204
        return $this->host;
205
    }
206
207
    /**
208
     * @return int|null
209
     */
210
    public function getPort(): ?int
211
    {
212
        return -1 === $this->port ? null : $this->port;
213
    }
214
215
    /**
216
     * @return string
217
     */
218
    public function getFragment(): string
219
    {
220
        return $this->fragment;
221
    }
222
223
    /**
224
     * @return HttpMutableQuery
225
     */
226
    public function getQueryBag(): HttpMutableQuery
227
    {
228
        return $this->queryBag;
229
    }
230
231
    /**
232
     * @return HttpMutablePath
233
     */
234
    public function getPathBag(): HttpMutablePath
235
    {
236
        return $this->pathBag;
237
    }
238
239
    //////////////////////////
240
    /// SETTER FUNCTIONS  ///
241
    ////////////////////////
242
243
    /**
244
     * @param string $user
245
     *
246
     * @return HttpBuilder
247
     */
248
    public function setUser(string $user): self
249
    {
250
        $this->user = $user;
251
        // Rebuild the authority
252
        $this->buildAuthority();
253
254
        return $this;
255
    }
256
257
    /**
258
     * @param string $password
259
     *
260
     * @return HttpBuilder
261
     */
262
    public function setPassword(string $password): self
263
    {
264
        $this->password = $password;
265
        // Rebuild the authority
266
        $this->buildAuthority();
267
268
        return $this;
269
    }
270
271
    /**
272
     * @param string $host
273
     *
274
     * @return HttpBuilder
275
     */
276
    public function setHost(string $host): self
277
    {
278
        $this->host = $host;
279
        // Rebuild the authority
280
        $this->buildAuthority();
281
282
        return $this;
283
    }
284
285
    /**
286
     * @param int $port
287
     *
288
     * @return HttpBuilder
289
     * @throws \LogicException
290
     */
291
    public function setPort(int $port): self
292
    {
293
        if (abs($port) !== $port) {
294
            throw new \LogicException('Ports cannot be negative');
295
        }
296
297
        $this->port = $port;
298
        // Rebuild the authority
299
        $this->buildAuthority();
300
301
        return $this;
302
    }
303
304
    /**
305
     * @param string $fragment
306
     *
307
     * @return HttpBuilder
308
     */
309
    public function setFragment(string $fragment): self
310
    {
311
        $this->fragment = $fragment;
312
313
        return $this;
314
    }
315
316
    /////////////////////////////////
317
    /// INTERFACE IMPLEMENTATION  ///
318
    /////////////////////////////////
319
320
    /**
321
     * @param bool $urlEncode
322
     *
323
     * @return string
324
     */
325
    public function build(bool $urlEncode = false): string
326
    {
327
        $url = self::SCHEME.'://';
328
329
        $url .= $this->authority;
330
331
        if ($urlEncode) {
332
            $url .= $this->pathBag->encoded();
333
            $url .= $this->queryBag->encoded();
334
        } else {
335
            $url .= $this->pathBag->raw();
336
            $url .= $this->queryBag->raw();
337
        }
338
339
        if (!empty($this->fragment)) {
340
            $url .= '#'.$this->fragment;
341
        }
342
343
        return $url;
344
    }
345
346
    /**
347
     * Returns all the components of the scheme including
348
     *  any bags in the form of an array
349
     *
350
     * @return array
351
     */
352
    public function all(): array
353
    {
354
        return [
355
            'scheme'    => self::SCHEME,
356
            'authority' => $this->authority,
357
            'user'      => $this->user,
358
            'password'  => $this->password,
359
            'host'      => $this->host,
360
            'port'      => -1 === $this->port ? null : $this->port,
361
            'query'     => $this->queryBag->all(),
362
            'path'      => $this->pathBag->all(),
363
            'fragment'  => $this->fragment,
364
        ];
365
    }
366
367
    /**
368
     * Return the raw unaltered url
369
     *
370
     * @return string
371
     */
372
    public function raw(): string
373
    {
374
        return $this->build(false);
375
    }
376
377
    /**
378
     * @return string
379
     */
380
    public function encoded(): string
381
    {
382
        return $this->build(true);
383
    }
384
385
    /**
386
     * Returns the scheme associated with the class
387
     *
388
     * @return string
389
     */
390
    public function getScheme(): string
391
    {
392
        return self::SCHEME;
393
    }
394
}