Test Failed
Push — master ( d89333...e2d202 )
by Alexey
03:26
created

Cookie::expires()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
ccs 0
cts 4
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 2
1
<?php declare(strict_types = 1);
2
3
namespace Venta\Http;
4
5
use DateTime;
6
use DateTimeImmutable;
7
use DateTimeInterface;
8
use InvalidArgumentException;
9
use Venta\Contracts\Http\Cookie as CookieContract;
10
11
/**
12
 * Class Cookie
13
 *
14
 * @package Venta\Http
15
 */
16
class Cookie implements CookieContract
17
{
18
19
    /**
20
     * @var string
21
     */
22
    private $domain = '';
23
24
    /**
25
     * @var DateTimeInterface|null
26
     */
27
    private $expires = null;
28
29
    /**
30
     * @var bool
31
     */
32
    private $httpOnly = false;
33
34
    /**
35
     * @var string
36
     */
37
    private $name;
38
39
    /**
40
     * @var string
41
     */
42
    private $path = '';
43
44
    /**
45
     * @var bool
46
     */
47
    private $secure = false;
48
49
    /**
50
     * @var string
51
     */
52
    private $value = '';
53
54
    /**
55
     * Cookie constructor.
56
     *
57
     * @param string $name
58
     * @param string $value
0 ignored issues
show
Documentation introduced by
Should the type for parameter $value not be null|string?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
59
     * @param DateTimeInterface|null $expires
60
     * @param string $path
61
     * @param string $domain
62
     * @param bool $secure
63
     * @param bool $httpOnly
64
     * @throws InvalidArgumentException
65
     */
66
    public function __construct(
67
        string $name,
68
        string $value = null,
69
        DateTimeInterface $expires = null,
70
        string $path = '',
71
        string $domain = '',
72
        bool $secure = false,
73
        bool $httpOnly = false
74
    ) {
75
        if (empty($name)) {
76
            throw new InvalidArgumentException('The cookie name cannot be empty.');
77
        }
78
79
        if (preg_match("/[=,; \t\r\n\013\014]/", $name)) {
80
            throw new InvalidArgumentException(sprintf('The cookie name "%s" contains invalid characters.', $name));
81
        }
82
83
        $this->name = $name;
84
        $this->value = $value;
85
        $this->domain = $domain;
86
        $this->expires = $expires ? $this->lockExpires($expires) : null;
87
        $this->path = $path;
88
        $this->secure = $secure;
89
        $this->httpOnly = $httpOnly;
90
    }
91
92
    /**
93
     * @inheritDoc
94
     */
95
    public function __toString()
96
    {
97
        $attributes = [];
98
        $name = urlencode($this->name);
99
        if ((string)$this->value === '') {
100
            // Cookie with empty value assumed expired.
101
            $value = 'deleted';
102
            $attributes[] = 'expires=' . (new DateTime())->setTimestamp(1)->format(DateTime::COOKIE);
103
        } else {
104
            $value = urlencode($this->value);
105
        }
106
107
        // Create cookie crumb with name and value.
108
        $cookieCrumb = "$name=$value";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $name instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $value instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
109
110
        // Add cookie attributes.
111
        if ($this->expires) {
112
            $attributes[] = 'expires=' . $this->expires->format(DateTime::COOKIE);
113
        }
114
        if ($this->path) {
115
            $attributes[] = "path={$this->path}";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $this instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
116
        }
117
        if ($this->domain) {
118
            $attributes[] = "domain={$this->domain}";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $this instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
119
        }
120
        if ($this->secure) {
121
            $attributes[] = 'secure';
122
        }
123
        if ($this->httpOnly) {
124
            $attributes[] = 'httponly';
125
        }
126
127
        if (count($attributes) > 0) {
128
            // Add attributes to cookie crumb.
129
            $cookieCrumb .= '; ' . implode('; ', $attributes);
130
        }
131
132
        return $cookieCrumb;
133
    }
134
135
    /**
136
     * @inheritDoc
137
     */
138
    public function domain(): string
139
    {
140
        return $this->domain;
141
    }
142
143
    /**
144
     * @inheritDoc
145
     */
146
    public function expires()
147
    {
148
        return $this->expires;
149
    }
150
151
    /**
152
     * @inheritDoc
153
     */
154
    public function httpOnly(): CookieContract
155
    {
156
        $cookie = clone $this;
157
        $cookie->httpOnly = true;
158
159
        return $cookie;
160
    }
161
162
    /**
163
     * @inheritDoc
164
     */
165
    public function isHttpOnly(): bool
166
    {
167
        return $this->httpOnly;
168
    }
169
170
    /**
171
     * @inheritDoc
172
     */
173
    public function isSecure(): bool
174
    {
175
        return $this->secure;
176
    }
177
178
    /**
179
     * @inheritDoc
180
     */
181
    public function name(): string
182
    {
183
        return $this->name;
184
    }
185
186
    /**
187
     * @inheritDoc
188
     */
189
    public function path(): string
190
    {
191
        return $this->path;
192
    }
193
194
    /**
195
     * @inheritDoc
196
     */
197
    public function secured(): CookieContract
198
    {
199
        $cookie = clone $this;
200
        $cookie->secure = true;
201
202
        return $cookie;
203
    }
204
205
    /**
206
     * @inheritDoc
207
     */
208
    public function value(): string
209
    {
210
        return $this->value;
211
    }
212
213
    /**
214
     * @inheritDoc
215
     */
216
    public function withDomain(string $domain): CookieContract
217
    {
218
        $cookie = clone $this;
219
        $cookie->domain = $domain;
220
221
        return $cookie;
222
    }
223
224
    /**
225
     * @inheritDoc
226
     */
227
    public function withExpires(DateTimeInterface $expires = null): CookieContract
228
    {
229
        $cookie = clone $this;
230
        $cookie->expires = $expires ? $cookie->lockExpires($expires) : null;
231
232
        return $cookie;
233
    }
234
235
    /**
236
     * @inheritDoc
237
     */
238
    public function withPath(string $path): CookieContract
239
    {
240
        $cookie = clone $this;
241
        $cookie->path = $path;
242
243
        return $cookie;
244
    }
245
246
    /**
247
     * @inheritDoc
248
     */
249
    public function withValue(string $value): CookieContract
250
    {
251
        $cookie = clone $this;
252
        $cookie->value = $value;
253
254
        return $cookie;
255
    }
256
257
    /**
258
     * Creates immutable date time instance from provided one.
259
     *
260
     * @param DateTimeInterface $expires
261
     * @return DateTimeImmutable
262
     */
263
    private function lockExpires(DateTimeInterface $expires): DateTimeImmutable
264
    {
265
        if (!$expires instanceof DateTimeImmutable) {
266
            $expires = new DateTimeImmutable($expires->format(DateTime::ISO8601), $expires->getTimezone());
267
        }
268
269
        return $expires;
270
    }
271
}