Passed
Push — master ( 4a0863...f9bf6d )
by Magnar Ovedal
03:47 queued 10s
created

GeneralDirective::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 2
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stadly\Http\Header\Value\CacheControl;
6
7
use InvalidArgumentException;
8
use Stadly\Http\Utilities\Rfc7230;
9
use Stadly\Http\Utilities\Rfc7234;
10
11
/**
12
 * Class for handling cache control directives with optional value.
13
 *
14
 * Specification: https://tools.ietf.org/html/rfc7234#section-5.2.2
15
 */
16
final class GeneralDirective extends Directive
17
{
18
    /**
19
     * @var string|null Value.
20
     */
21
    private $value;
22
23
    /**
24
     * Constructor.
25
     *
26
     * @param string $name Name.
27
     * @param string|null $value Value.
28
     */
29 9
    public function __construct(string $name, ?string $value = null)
30
    {
31 9
        $this->setName($name);
32 4
        $this->setValue($value);
33 3
    }
34
35
    /**
36
     * Construct directive from string.
37
     *
38
     * @param string $directive Directive string.
39
     * @return self Directive generated based on the string.
40
     */
41 7
    public static function fromString(string $directive): self
42
    {
43 7
        $regEx = '{^' . Rfc7234::CACHE_DIRECTIVE_CAPTURE . '$}';
44 7
        if (utf8_decode($directive) !== $directive || preg_match($regEx, $directive, $matches) !== 1) {
45 3
            throw new InvalidArgumentException('Invalid directive: ' . $directive);
46
        }
47
48 4
        if (!isset($matches['VALUE'])) {
49 1
            return new self($matches['NAME'], /*value*/null);
50
        }
51
52 3
        $value = $matches['VALUE'];
53
        // Strip slashes if value is quoted.
54 3
        if (mb_strlen($value) >= 2 && mb_substr($value, 0, 1) === '"' && mb_substr($value, -1) === '"') {
55 2
            $value = stripslashes(mb_substr($value, 1, -1));
56
        }
57
58 3
        return new self($matches['NAME'], $value);
59
    }
60
61
    /**
62
     * @inheritDoc
63
     */
64 4
    public function __toString(): string
65
    {
66 4
        if ($this->value === null) {
67 1
            return $this->name;
68
        }
69
70 3
        return $this->name . '=' . self::encodeValue($this->value);
71
    }
72
73
    /**
74
     * @param string $name Name.
75
     */
76 6
    public function setName(string $name): void
77
    {
78 6
        if (utf8_decode($name) !== $name || preg_match('{^' . Rfc7230::TOKEN . '$}', $name) !== 1) {
79 2
            throw new InvalidArgumentException('Invalid name: ' . $name);
80
        }
81
82 6
        if (in_array(strtolower($name), FieldListDirective::RESERVED_NAMES, /*strict*/true)) {
83 1
            throw new InvalidArgumentException('Name reserved for field list directive: ' . $name);
84
        }
85 6
        if (in_array(strtolower($name), IntegerDirective::RESERVED_NAMES, /*strict*/true)) {
86 1
            throw new InvalidArgumentException('Name reserved for integer directive: ' . $name);
87
        }
88 6
        if (in_array(strtolower($name), ValuelessDirective::RESERVED_NAMES, /*strict*/true)) {
89 1
            throw new InvalidArgumentException('Name reserved for valueless directive: ' . $name);
90
        }
91
92 6
        $this->name = $name;
93 6
    }
94
95
    /**
96
     * @inheritDoc
97
     */
98 1
    public function getValue(): ?string
99
    {
100 1
        return $this->value;
101
    }
102
103
    /**
104
     * @param string|null $value Value.
105
     */
106 5
    public function setValue(?string $value): void
107
    {
108 5
        if ($value !== null) {
109 5
            $encodedValue = self::encodeValue($value);
110
111 5
            $regEx = '{^(?:' . Rfc7230::TOKEN . '|' . Rfc7230::QUOTED_STRING . ')$}';
112 5
            if (utf8_decode($encodedValue) !== $encodedValue || preg_match($regEx, $encodedValue) !== 1) {
113 1
                throw new InvalidArgumentException('Invalid value: ' . $value);
114
            }
115
        }
116
117 5
        $this->value = $value;
118 5
    }
119
120
    /**
121
     * @param string $value Value.
122
     * @return string Encoded value.
123
     */
124 22
    private static function encodeValue(string $value): string
125
    {
126 22
        if (preg_match('{^' . Rfc7230::TOKEN . '$}', $value) === 1) {
127 16
            return $value;
128
        }
129
130
        // If value is not a valid token, turn it into a quoted token.
131 9
        return '"' . addslashes($value) . '"';
132
    }
133
}
134