Passed
Pull Request — master (#22)
by Aleksei
02:32
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 1
    public function getValue(): string
58
    {
59 1
        return $this->getDirective();
60
    }
61
62
    public function hasArgument(): bool
63
    {
64
        return $this->argument !== null;
65
    }
66 22
    public function getArgument(): ?string
67
    {
68 22
        return $this->argument;
69
    }
70
    public function getArgumentList(): array
71
    {
72
        return $this->argument === null ? [] : explode(',', $this->argument);
73
    }
74
75
    /**
76
     * @param string $directive
77
     * @param string|null $argument
78
     *
79
     * @throws InvalidArgumentException
80
     */
81 42
    public function withDirective(string $directive, string $argument = null): self
82
    {
83 42
        $clone = clone $this;
84 42
        $clone->setDirective($directive, $argument, true);
85 29
        return $clone;
86
    }
87
88 45
    protected function setValue(string $value): void
89
    {
90 45
        $this->setDirective($value);
91 45
    }
92 45
    private function setDirective(string $value, string $argument = null, bool $trowError = false): bool
93
    {
94 45
        $name = strtolower($value);
95
96 45
        $argumentType = static::DIRECTIVES[$name] ?? self::ARG_CUSTOM;
97
98 45
        $writeProperties = function (\Exception $err = null, string $arg = null, int $type = self::ARG_EMPTY) use (
99 45
            $name,
100 45
            $trowError
101
        ) {
102 45
            if ($trowError && $err !== null) {
103 13
                throw $err;
104
            }
105 45
            $this->directive = $name;
106 45
            $this->argument = $arg;
107 45
            $this->argumentType = $type;
108 45
            $this->error = $err;
109 45
            return $this->error === null;
110 45
        };
111
112 45
        if ($argument === null && ($argumentType & self::ARG_EMPTY) === self::ARG_EMPTY) {
113 5
            return $writeProperties();
114 45
        } elseif ($argumentType === self::ARG_EMPTY) {
115 1
            if ($argument !== null) {
116 1
                return $writeProperties(new InvalidArgumentException("{$name} directive should not have an argument"));
117
            }
118
            return $writeProperties();
119 45
        } elseif (($argumentType & self::ARG_HEADERS_LIST) === self::ARG_HEADERS_LIST) {
120
            // Validate headers list
121 12
            $argument = $argument === null ? null : trim($argument);
122 12
            if ($argument === null || preg_match('/^[\\w\\-]+(?:(?:\\s*,\\s*)[\\w\\-]+)*$/', $argument) !== 1) {
123 6
                return $writeProperties(
124 6
                    new InvalidArgumentException(
125 6
                        "{$name} directive should have an argument as a comma separated headers name list"
126
                    )
127
                );
128
            }
129 6
            return $writeProperties(null, $argument, self::ARG_HEADERS_LIST);
130 45
        } elseif (($argumentType & self::ARG_DELTA_SECONDS) === self::ARG_DELTA_SECONDS) {
131 10
            $this->argumentType = self::ARG_DELTA_SECONDS;
132
            // Validate number
133 10
            if ($argument === null || preg_match('/^\\d+$/', $argument) !== 1) {
134 6
                return $writeProperties(
135 6
                    new InvalidArgumentException("{$name} directive should have numeric argument"),
136 6
                    '0',
137 6
                    self::ARG_DELTA_SECONDS
138
                );
139
            }
140 4
            return $writeProperties(null, $argument, self::ARG_DELTA_SECONDS);
141
        }
142 45
        return $writeProperties(null, $argument, $argumentType);
143
    }
144
}
145