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

DirectivesHeaderValue::__toString()   B

Complexity

Conditions 8
Paths 6

Size

Total Lines 23
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 8

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 8
eloc 15
c 1
b 0
f 1
nc 6
nop 0
dl 0
loc 23
ccs 15
cts 15
cp 1
crap 8
rs 8.4444
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Http\Header\Internal;
6
7
use InvalidArgumentException;
8
use Yiisoft\Http\Header\DirectiveHeader;
9
10
abstract class DirectivesHeaderValue extends BaseHeaderValue
11
{
12
    protected const DIRECTIVES = [];
13
14
    protected const ARG_EMPTY = 1;
15
    protected const ARG_DELTA_SECONDS = 2;
16
    protected const ARG_HEADERS_LIST = 4;
17
    protected const ARG_CUSTOM = 8;
18
19
    protected string $directive = '';
20
    protected ?string $argument = null;
21
    protected int $argumentType = self::ARG_EMPTY;
22
23 31
    public function __toString(): string
24
    {
25 31
        if ($this->directive === '') {
26 1
            return '';
27
        }
28 30
        if ($this->argument === null) {
29 9
            return $this->directive;
30
        }
31 22
        if ($this->argumentType === self::ARG_HEADERS_LIST) {
32 6
            return "{$this->directive}=\"{$this->argument}\"";
33
        }
34 16
        if ($this->argumentType === self::ARG_CUSTOM) {
35 12
            $argument = $this->encodeQuotedString($this->argument);
36
            if (
37 12
                $argument === ''
38 11
                || strlen($argument) !== strlen($this->argument)
39 12
                || preg_match('/[^a-z0-9_]/i', $argument) === 1
40
            ) {
41 7
                $argument = '"' . $argument . '"';
42
            }
43 12
            return "{$this->directive}={$argument}";
44
        }
45 4
        return "{$this->directive}={$this->argument}";
46
    }
47
48 1
    public static function createHeader(): DirectiveHeader
49
    {
50 1
        return new DirectiveHeader(static::class);
51
    }
52
53 23
    public function getDirective(): string
54
    {
55 23
        return $this->directive;
56
    }
57
58 1
    public function getValue(): string
59
    {
60 1
        return $this->getDirective();
61
    }
62
63
    public function hasArgument(): bool
64
    {
65
        return $this->argument !== null;
66
    }
67
68 22
    public function getArgument(): ?string
69
    {
70 22
        return $this->argument;
71
    }
72
73
    public function getArgumentList(): array
74
    {
75
        return $this->argument === null ? [] : explode(',', $this->argument);
76
    }
77
78
    /**
79
     * @param string $directive
80
     * @param string|null $argument
81
     *
82
     * @throws InvalidArgumentException
83
     */
84 42
    public function withDirective(string $directive, string $argument = null): self
85
    {
86 42
        $clone = clone $this;
87 42
        $clone->setDirective($directive, $argument, true);
88 29
        return $clone;
89
    }
90
91 45
    protected function setValue(string $value): void
92
    {
93 45
        $this->setDirective($value);
94 45
    }
95
96 45
    private function setDirective(string $value, string $argument = null, bool $trowError = false): bool
97
    {
98 45
        $name = strtolower($value);
99
100 45
        $argumentType = static::DIRECTIVES[$name] ?? self::ARG_CUSTOM;
101
102 45
        $writeProperties = function (\Exception $err = null, string $arg = null, int $type = self::ARG_EMPTY) use (
103 45
            $name,
104 45
            $trowError
105
        ) {
106 45
            if ($trowError && $err !== null) {
107 13
                throw $err;
108
            }
109 45
            $this->directive = $name;
110 45
            $this->argument = $arg;
111 45
            $this->argumentType = $type;
112 45
            $this->error = $err;
113 45
            return $this->error === null;
114 45
        };
115
116 45
        if ($argument === null && ($argumentType & self::ARG_EMPTY) === self::ARG_EMPTY) {
117 5
            return $writeProperties();
118
        }
119 45
        if ($argumentType === self::ARG_EMPTY) {
120 1
            if ($argument !== null) {
121 1
                return $writeProperties(new InvalidArgumentException("{$name} directive should not have an argument"));
122
            }
123
            return $writeProperties();
124
        }
125 45
        if (($argumentType & self::ARG_HEADERS_LIST) === self::ARG_HEADERS_LIST) {
126
            // Validate headers list
127 12
            $argument = $argument === null ? null : trim($argument);
128 12
            if ($argument === null || preg_match('/^[\\w\\-]+(?:(?:\\s*,\\s*)[\\w\\-]+)*$/', $argument) !== 1) {
129 6
                return $writeProperties(
130 6
                    new InvalidArgumentException(
131 6
                        "{$name} directive should have an argument as a comma separated headers name list"
132
                    )
133
                );
134
            }
135 6
            return $writeProperties(null, $argument, self::ARG_HEADERS_LIST);
136
        }
137 45
        if (($argumentType & self::ARG_DELTA_SECONDS) === self::ARG_DELTA_SECONDS) {
138 10
            $this->argumentType = self::ARG_DELTA_SECONDS;
139
            // Validate number
140 10
            if ($argument === null || preg_match('/^\\d+$/', $argument) !== 1) {
141 6
                return $writeProperties(
142 6
                    new InvalidArgumentException("{$name} directive should have numeric argument"),
143 6
                    '0',
144 6
                    self::ARG_DELTA_SECONDS
145
                );
146
            }
147 4
            return $writeProperties(null, $argument, self::ARG_DELTA_SECONDS);
148
        }
149 45
        return $writeProperties(null, $argument, $argumentType);
150
    }
151
}
152