Cookie::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 18
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 8
c 1
b 0
f 0
nc 1
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
2
3
/**
4
 * Platine Cookie
5
 *
6
 * Platine Cookie is the cookie management in accordance with the RFC 6265 specification
7
 *
8
 * This content is released under the MIT License (MIT)
9
 *
10
 * Copyright (c) 2020 Platine Cookie
11
 * Copyright (c) 2020 Evgeniy Zyubin
12
 *
13
 * Permission is hereby granted, free of charge, to any person obtaining a copy
14
 * of this software and associated documentation files (the "Software"), to deal
15
 * in the Software without restriction, including without limitation the rights
16
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
 * copies of the Software, and to permit persons to whom the Software is
18
 * furnished to do so, subject to the following conditions:
19
 *
20
 * The above copyright notice and this permission notice shall be included in all
21
 * copies or substantial portions of the Software.
22
 *
23
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
 * SOFTWARE.
30
 */
31
32
/**
33
 *  @file Cookie.php
34
 *
35
 *  The Cookie class
36
 *
37
 *  @package    Platine\Cookie
38
 *  @author Platine Developers Team
39
 *  @copyright  Copyright (c) 2020
40
 *  @license    http://opensource.org/licenses/MIT  MIT License
41
 *  @link   https://www.platine-php.com
42
 *  @version 1.0.0
43
 *  @filesource
44
 */
45
46
declare(strict_types=1);
47
48
namespace Platine\Cookie;
49
50
use DateTimeInterface;
51
use InvalidArgumentException;
52
53
/**
54
 * @class Cookie
55
 * @package Platine\Cookie
56
 */
57
class Cookie implements CookieInterface
58
{
59
    /**
60
     * The name of the cookie
61
     *
62
     * @var string
63
     */
64
    protected string $name;
65
66
    /**
67
     * The value of the cookie
68
     *
69
     * @var string
70
     */
71
    protected string $value;
72
73
    /**
74
     * The expires of the cookie
75
     *
76
     * @var int
77
     */
78
    protected int $expires;
79
80
    /**
81
     * The domain of the cookie
82
     *
83
     * @var string|null
84
     */
85
    protected ?string $domain;
86
87
    /**
88
     * The path of the cookie
89
     *
90
     * @var string|null
91
     */
92
    protected ?string $path;
93
94
    /**
95
     * Whether the cookie is transmetted under secure
96
     * connection
97
     *
98
     * @var bool|null
99
     */
100
    protected ?bool $secure;
101
102
    /**
103
     * Whether the cookie is accessed under HTTP
104
     * protocol
105
     *
106
     * @var bool|null
107
     */
108
    protected ?bool $httpOnly;
109
110
    /**
111
     * The value of the same site
112
     *
113
     * @var string|null
114
     */
115
    protected ?string $sameSite;
116
117
    /**
118
     * Create new instance
119
     *
120
     * @param string $name
121
     * @param string $value
122
     * @param int|string|DateTimeInterface|null $expire
123
     * @param string |null $domain
124
     * @param string |null $path
125
     * @param bool|null $secure
126
     * @param bool|null $httpOnly
127
     * @param string|null $sameSite
128
     */
129
    public function __construct(
130
        string $name,
131
        string $value = '',
132
        int|string|DateTimeInterface|null $expire = null,
133
        ?string $domain = null,
134
        ?string $path = '/',
135
        ?bool $secure = true,
136
        ?bool $httpOnly = true,
137
        ?string $sameSite = self::SAME_SITE_LAX
138
    ) {
139
        $this->setName($name);
140
        $this->setValue($value);
141
        $this->setExpires($expire);
142
        $this->setDomain($domain);
143
        $this->setPath($path);
144
        $this->setSecure($secure);
145
        $this->setHttpOnly($httpOnly);
146
        $this->setSameSite($sameSite);
147
    }
148
149
    /**
150
     * {@inheritdoc}
151
     */
152
    public function getName(): string
153
    {
154
        return $this->name;
155
    }
156
157
    /**
158
     * {@inheritdoc}
159
     */
160
    public function getValue(): string
161
    {
162
        return $this->value;
163
    }
164
165
    /**
166
     * {@inheritdoc}
167
     */
168
    public function withValue(string $value): self
169
    {
170
        if ($value === $this->value) {
171
            return $this;
172
        }
173
174
        $that = clone $this;
175
176
        $that->setValue($value);
177
178
        return $that;
179
    }
180
181
    /**
182
     * {@inheritdoc}
183
     */
184
    public function getMaxAge(): int
185
    {
186
        $maxAge = $this->expires - time();
187
188
        return $maxAge > 0 ? $maxAge : 0;
189
    }
190
191
    /**
192
     * {@inheritdoc}
193
     */
194
    public function getExpires(): int
195
    {
196
        return $this->expires;
197
    }
198
199
    /**
200
     * {@inheritdoc}
201
     */
202
    public function isExpired(): bool
203
    {
204
        return (!$this->isSession() && $this->expires < time());
205
    }
206
207
    /**
208
     * {@inheritdoc}
209
     */
210
    public function expire(): self
211
    {
212
        if ($this->isExpired()) {
213
            return $this;
214
        }
215
216
        $that = clone $this;
217
218
        $that->expires = time() - 31536001;
219
220
        return $that;
221
    }
222
223
    /**
224
     * {@inheritdoc}
225
     */
226
    public function withExpires(int|string|DateTimeInterface|null $expire = null): self
227
    {
228
        if ($expire === $this->expires) {
229
            return $this;
230
        }
231
232
        $that = clone $this;
233
234
        $that->setExpires($expire);
235
236
        return $that;
237
    }
238
239
    /**
240
     * {@inheritdoc}
241
     */
242
    public function getDomain(): ?string
243
    {
244
        return $this->domain;
245
    }
246
247
    /**
248
     * {@inheritdoc}
249
     */
250
    public function withDomain(?string $domain): self
251
    {
252
        if ($domain === $this->domain) {
253
            return $this;
254
        }
255
256
        $that = clone $this;
257
258
        $that->setDomain($domain);
259
260
        return $that;
261
    }
262
263
    /**
264
     * {@inheritdoc}
265
     */
266
    public function getPath(): ?string
267
    {
268
        return $this->path;
269
    }
270
271
    /**
272
     * {@inheritdoc}
273
     */
274
    public function withPath(?string $path): self
275
    {
276
        if ($path === $this->path) {
277
            return $this;
278
        }
279
280
        $that = clone $this;
281
282
        $that->setPath($path);
283
284
        return $that;
285
    }
286
287
    /**
288
     * {@inheritdoc}
289
     */
290
    public function isSecure(): bool
291
    {
292
        return $this->secure ? $this->secure : false;
293
    }
294
295
    /**
296
     * {@inheritdoc}
297
     */
298
    public function withSecure(bool $secure = true): self
299
    {
300
        if ($secure === $this->secure) {
301
            return $this;
302
        }
303
304
        $that = clone $this;
305
306
        $that->setSecure($secure);
307
308
        return $that;
309
    }
310
311
    /**
312
     * {@inheritdoc}
313
     */
314
    public function isHttpOnly(): bool
315
    {
316
        return $this->httpOnly ?? false;
317
    }
318
319
    /**
320
     * {@inheritdoc}
321
     */
322
    public function withHttpOnly(bool $httpOnly = true): self
323
    {
324
        if ($httpOnly === $this->httpOnly) {
325
            return $this;
326
        }
327
328
        $that = clone $this;
329
330
        $that->setHttpOnly($httpOnly);
331
332
        return $that;
333
    }
334
335
    /**
336
     * {@inheritdoc}
337
     */
338
    public function getSameSite(): ?string
339
    {
340
        return $this->sameSite;
341
    }
342
343
    /**
344
     * {@inheritdoc}
345
     */
346
    public function withSameSite(?string $sameSite): self
347
    {
348
        if ($sameSite === $this->sameSite) {
349
            return $this;
350
        }
351
352
        $that = clone $this;
353
354
        $that->setSameSite($sameSite);
355
356
        return $that;
357
    }
358
359
    /**
360
     * {@inheritdoc}
361
     */
362
    public function isSession(): bool
363
    {
364
        return $this->expires === 0;
365
    }
366
367
    /**
368
     * {@inheritdoc}
369
     */
370
    public function __toString(): string
371
    {
372
        $cookie = $this->name . '=' . rawurlencode($this->value);
373
374
        if ($this->isSession() === false) {
375
            $cookie .= '; Expires=' . gmdate('D, d-M-Y H:i:s T', $this->expires);
376
            $cookie .= '; Max-Age=' . $this->getMaxAge();
377
        }
378
379
        if ($this->domain !== null) {
380
            $cookie .= '; Domain=' . $this->domain;
381
        }
382
383
        if ($this->path !== null) {
384
            $cookie .= '; Path=' . $this->path;
385
        }
386
387
        if ($this->secure === true) {
388
            $cookie .= '; Secure';
389
        }
390
391
        if ($this->httpOnly === true) {
392
            $cookie .= '; HttpOnly';
393
        }
394
395
        if ($this->sameSite !== null) {
396
            $cookie .= '; SameSite=' . $this->sameSite;
397
        }
398
399
        return $cookie;
400
    }
401
402
    /**
403
     * Set the cookie name
404
     * @param string $name
405
     */
406
    private function setName(string $name): self
407
    {
408
        if (empty($name)) {
409
            throw new InvalidArgumentException(sprintf(
410
                'The cookie name [%s] could not be empty',
411
                $name
412
            ));
413
        }
414
415
        if (!preg_match('/^[a-zA-Z0-9!#$%&\' *+\-.^_`|~]+$/', $name)) {
416
            throw new InvalidArgumentException(sprintf(
417
                'The cookie name [%s] contains invalid characters; must contain any US-ASCII'
418
                . ' characters, except control and separator characters, spaces, or tabs.',
419
                $name
420
            ));
421
        }
422
423
        $this->name = $name;
424
425
        return $this;
426
    }
427
428
    /**
429
     * Set the cookie value
430
     * @param string $value
431
     */
432
    private function setValue(string $value): self
433
    {
434
        $this->value = $value;
435
436
        return $this;
437
    }
438
439
    /**
440
     * Set the cookie expires
441
     * @param int|string|DateTimeInterface|null $expire
442
     */
443
    private function setExpires(int|string|DateTimeInterface|null $expire): self
444
    {
445
        if ($expire === null || (is_string($expire) && empty($expire))) {
446
            $expire = 0;
447
        }
448
449
        if ($expire instanceof DateTimeInterface) {
450
            $expire = $expire->format('U');
451
        } elseif (!is_numeric($expire)) {
452
            $strExpire = $expire;
453
            $expire = strtotime($strExpire);
454
455
            if ($expire === false) {
456
                throw new InvalidArgumentException(sprintf(
457
                    'The string representation of the cookie expire time [%s] is not valid',
458
                    $strExpire
459
                ));
460
            }
461
        }
462
463
        $this->expires = ($expire > 0) ? (int) $expire : 0;
464
465
        return $this;
466
    }
467
468
    /**
469
     * Set the cookie domain
470
     * @param string|null $domain
471
     */
472
    private function setDomain(?string $domain): self
473
    {
474
        $this->domain = empty($domain) ? null : $domain;
475
476
        return $this;
477
    }
478
479
    /**
480
     * Set the cookie path
481
     * @param string|null $path
482
     */
483
    private function setPath(?string $path): self
484
    {
485
        $this->path = empty($path) ? null : $path;
486
487
        return $this;
488
    }
489
490
    /**
491
     * Set the cookie secure value
492
     * @param bool|null $secure
493
     */
494
    private function setSecure(?bool $secure): self
495
    {
496
        $this->secure = $secure;
497
498
        return $this;
499
    }
500
501
    /**
502
     * Set the cookie HTTP protocol flag
503
     * @param bool|null $httpOnly
504
     */
505
    private function setHttpOnly(?bool $httpOnly): self
506
    {
507
        $this->httpOnly = $httpOnly;
508
509
        return $this;
510
    }
511
512
    /**
513
     * Set the cookie same site value
514
     * @param string|null $sameSite
515
     */
516
    private function setSameSite(?string $sameSite): self
517
    {
518
        $sameSiteValue = empty($sameSite) ? null : ucfirst(strtolower($sameSite));
519
520
        $sameSiteList = [
521
            self::SAME_SITE_NONE,
522
            self::SAME_SITE_LAX,
523
            self::SAME_SITE_STRICT,
524
        ];
525
526
        if ($sameSiteValue !== null && !in_array($sameSiteValue, $sameSiteList, true)) {
527
            throw new InvalidArgumentException(sprintf(
528
                'The same site attribute `%s` is not valid; must be one of (%s).',
529
                $sameSiteValue,
530
                implode(', ', $sameSiteList)
531
            ));
532
        }
533
534
        $this->sameSite = $sameSiteValue;
535
536
        return $this;
537
    }
538
}
539