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