Passed
Pull Request — master (#22)
by Aleksei
02:39
created

Warning::setValue()   B

Complexity

Conditions 8
Paths 17

Size

Total Lines 41
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 26
CRAP Score 8.0032

Importance

Changes 0
Metric Value
cc 8
eloc 28
c 0
b 0
f 0
nc 17
nop 1
dl 0
loc 41
ccs 26
cts 27
cp 0.963
crap 8.0032
rs 8.4444
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Http\Header\Value\Cache;
6
7
use DateTimeImmutable;
8
use DateTimeInterface;
9
use Yiisoft\Http\Header\Parser\ParsingException;
10
use Yiisoft\Http\Header\Internal\BaseHeaderValue;
11
12
/**
13
 * @link https://tools.ietf.org/html/rfc7234#section-5.5
14
 * @link https://developer.mozilla.org/docs/Web/HTTP/Headers/Warning
15
 */
16
final class Warning extends BaseHeaderValue
17
{
18
    public const NAME = 'Warning';
19
20
    /**
21
     * A cache SHOULD generate this whenever the sent response is stale.
22
     *
23
     * @link https://tools.ietf.org/html/rfc7234#section-5.5.1
24
     */
25
    public const RESPONSE_IS_STALE = 110;
26
    /**
27
     * A cache SHOULD generate this when sending a stale response because an attempt to validate the response failed,
28
     * due to an inability to reach the server.
29
     *
30
     * @link https://tools.ietf.org/html/rfc7234#section-5.5.2
31
     */
32
    public const REVALIDATION_FAILED = 111;
33
    /**
34
     * A cache SHOULD generate this if it is intentionally disconnected from the rest of the network for a period of
35
     * time.
36
     *
37
     * @link https://tools.ietf.org/html/rfc7234#section-5.5.3
38
     */
39
    public const DISCONNECTED_OPERATION = 112;
40
    /**
41
     * A cache SHOULD generate this if it heuristically chose a freshness lifetime greater than 24 hours and the
42
     * response's age is greater than 24 hours.
43
     *
44
     * @link https://tools.ietf.org/html/rfc7234#section-5.5.4
45
     */
46
    public const HEURISTIC_EXPIRATION = 113;
47
    /**
48
     * The warning text can include arbitrary information to be presented to a human user or logged.  A system receiving
49
     * this warning MUST NOT take any automated action, besides presenting the warning to the user.
50
     *
51
     * @link https://tools.ietf.org/html/rfc7234#section-5.5.5
52
     */
53
    public const MISCELLANEOUS_WARNING = 199;
54
    /**
55
     * This Warning code MUST be added by a proxy if it applies any transformation to the representation, such as
56
     * changing the content-coding, media-type, or modifying the representation data, unless this Warning code already
57
     * appears in the response.
58
     *
59
     * @link https://tools.ietf.org/html/rfc7234#section-5.5.6
60
     */
61
    public const TRANSFORMATION_APPLIED = 214;
62
    /**
63
     * The warning text can include arbitrary information to be presented to a human user or logged.  A system receiving
64
     * this warning MUST NOT take any automated action.
65
     *
66
     * @link https://tools.ietf.org/html/rfc7234#section-5.5.7
67
     */
68
    public const MISCELLANEOUS_PERSISTENT_WARNING = 299;
69
70
    private bool $useDataset = false;
71
    private int $code;
72
    private string $agent;
73
    private string $text;
74
    private ?DateTimeImmutable $date = null;
75
76 2
    public function __toString(): string
77
    {
78 2
        if ($this->useDataset) {
79 2
            $result = "{$this->code} $this->agent \"" . $this->encodeQuotedString($this->text) . '"';
80 2
            if ($this->date !== null) {
81 1
                $result .= ' "' . $this->date->format(DateTimeInterface::RFC7231) . '"';
82
            }
83 2
            return $result;
84
        }
85
        return parent::__toString();
86
    }
87
88 13
    public function getCode(): ?int
89
    {
90 13
        return $this->useDataset ? $this->code : null;
91
    }
92
93 13
    public function getAgent(): ?string
94
    {
95 13
        return $this->useDataset ? $this->agent : null;
96
    }
97
98 13
    public function getText(): ?string
99
    {
100 13
        return $this->useDataset ? $this->text : null;
101
    }
102
103 13
    public function getDate(): ?DateTimeImmutable
104
    {
105 13
        return $this->useDataset ? $this->date : null;
106
    }
107
108 2
    public function withDataset(int $code, string $agent = '-', string $text = '', DateTimeImmutable $date = null): self
109
    {
110 2
        $clone = clone $this;
111 2
        $clone->code = $code;
112 2
        $clone->agent = $agent;
113 2
        $clone->text = $text;
114 2
        $clone->date = $date;
115 2
        $clone->useDataset = true;
116 2
        return $clone;
117
    }
118
119 32
    protected function setValue(string $value): void
120
    {
121 32
        $value = trim($value);
122 32
        $parts = preg_split('/\\s+/', $value, 3);
123 32
        $this->resetValues();
124
        try {
125
            // code
126 32
            if (preg_match('/^[1-9]\\d{2}$/', $parts[0]) !== 1) {
127 32
                throw new ParsingException($parts[0], 0, 'Incorrect code value.');
128
            }
129 24
            $this->code = (int)$parts[0];
130
            // agent
131 24
            if (!isset($parts[1])) {
132
                throw new ParsingException($value, 0, 'Agent value not defined.');
133
            }
134 24
            $this->agent = $parts[1];
135
            // text
136 24
            if (!isset($parts[2])) {
137 2
                throw new ParsingException($value, 0, 'Text not defined.');
138
            }
139 22
            if (preg_match(
140 22
                '/^"(?<text>(?:(?:\\\\.)+|[^\\\\"]+)*)"(?:(?:\\s+"(?<date>[a-zA-Z0-9, \\-:]+)")?|\\s*)$/',
141 22
                $parts[2],
142
                $matches
143 22
            ) !== 1) {
144 3
                throw new ParsingException($parts[2], 0, 'Bad quoted string format.');
145
            }
146 19
            $this->text = preg_replace('/\\\\(.)/', '$1', $matches['text']);
147
            // date
148 19
            if (isset($matches['date'])) {
149 12
                if (!$this->validateDateTime($matches['date'])) {
150 7
                    throw new ParsingException($matches['date'], 0, 'Incorrect datetime format.');
151
                }
152 5
                $this->date = new DateTimeImmutable($matches['date']);
153
            }
154 12
            $this->useDataset = true;
155 12
            $this->error = null;
156 32
        } catch (\Exception $e) {
157 32
            $this->error = $e;
158
        }
159 32
        parent::setValue($value);
160 32
    }
161
162 32
    private function resetValues()
163
    {
164 32
        $this->useDataset = false;
165 32
        $this->date = null;
166 32
    }
167
}
168