Language::get_last_error()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 3
nc 2
nop 0
dl 0
loc 7
ccs 4
cts 4
cp 1
crap 3
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Vendi\HttpLanguageHelper;
6
7
final class Language
8
{
9
    public const VARIANT_SIGNIFIER = '-';
10
11
    public const WEIGHT_SIGNIFIER = ';';
12
13
    public const WEIGHT_BEGIN = 'q';
14
15
    public const WEIGHT_SEPARATOR = '=';
16
17
    public const DEFAULT_WEIGHT = 1.0;
18
19
    private $language;
20
21
    private $variant;
22
23
    //Spec says that 1 is the default
24
    private $weight = self::DEFAULT_WEIGHT;
25
26
    private $original;
27
28
    private $parsing_errors = null;
29
30 4
    public function get_variant() : ?string
31
    {
32 4
        if ($this->get_last_error()) {
33 1
            return null;
34
        }
35 4
        return $this->variant;
36
    }
37
38 3
    public function get_language() : ?string
39
    {
40 3
        if ($this->get_last_error()) {
41 1
            return null;
42
        }
43 3
        return $this->language;
44
    }
45
46 3
    public function get_weight() : ?float
47
    {
48
        //Weight should always be a number, even if absent, however we're
49
        //return null to be consistent with get_variant() and get_language()
50 3
        if ($this->get_last_error()) {
51 1
            return null;
52
        }
53 3
        return $this->weight;
54
    }
55
56 2
    public function get_original() : ?string
57
    {
58
        //Always return original, even if there's an error
59 2
        return $this->original;
60
    }
61
62 3
    public function with_string(string $string) : self
63
    {
64
        //Immutable mode
65 3
        $obj = clone $this;
66
67
        //Backup copy
68 3
        $obj->original = $string;
69
70 3
        if (!$string) {
71 3
            $obj->add_parsing_error('Null string');
72 3
            return $obj;
73
        }
74
75
        //Look for a weight
76 2
        $parts = explode(self::WEIGHT_SIGNIFIER, $string);
77 2
        if (2 === count($parts)) {
78 2
            $obj = $obj->with_specific_weight($parts[1]);
79
80 2
            if ($obj->get_last_error()) {
81 1
                $obj->add_parsing_error('Weight parser failed');
82 1
                return $obj;
83
            }
84
        }
85
86
        //Even if there was no weight, the first part of the array would hold
87
        //the entire string anyway so that's what we're working with.
88 2
        $obj = $obj->with_language_and_maybe_variant($parts[0]);
89 2
        if ($obj->get_last_error()) {
90 1
            $obj->add_parsing_error('String parser failed');
91 1
            return $obj;
92
        }
93
94 2
        return $obj;
95
    }
96
97 3
    public function with_language_and_maybe_variant(string $string) : self
98
    {
99
        //Immutable mode
100 3
        $obj = clone $this;
101
102 3
        if (!$string) {
103 2
            $obj->add_parsing_error('Null string');
104 2
            return $obj;
105
        }
106
107
        //Look for a variant signifier
108 3
        $parts = explode(self::VARIANT_SIGNIFIER, $string);
109 3
        if (2 === count($parts)) {
110 3
            $obj = $obj->with_variant($parts[1]);
111
        }
112
113 3
        $obj->language = mb_strtolower($parts[0]);
114
115 3
        return $obj;
116
    }
117
118 4
    public function with_variant(string $string) : self
119
    {
120 4
        $obj = clone $this;
121 4
        $obj->variant = mb_strtolower($string);
122 4
        return $obj;
123
    }
124
125 3
    public function with_specific_weight(string $weight_string) : self
126
    {
127 3
        $obj = clone $this;
128
129 3
        if (!$weight_string) {
130 1
            $obj->add_parsing_error('Empty weight string');
131 1
            return $obj;
132
        }
133
134 3
        $parts = explode(self::WEIGHT_SEPARATOR, $weight_string);
135 3
        if (2 !== count($parts)) {
136 1
            $obj->add_parsing_error('Unknown weight string: ' . $weight_string);
137 1
            return $obj;
138
        }
139
140 3
        if (self::WEIGHT_BEGIN !== $parts[0]) {
141 1
            $obj->add_parsing_error('Missing q in weight string');
142 1
            return $obj;
143
        }
144
145 3
        $weight = $parts[1];
146 3
        if (!preg_match('/[0-9\.]/', $weight)) {
147 2
            $obj->add_parsing_error('Invalid weight portion: ' . $weight);
148 2
            return $obj;
149
        }
150
151 3
        $obj->weight = floatval($weight);
152 3
        return $obj;
153
    }
154
155 6
    public function get_last_error() : ?string
156
    {
157 6
        if (is_array($this->parsing_errors) && count($this->parsing_errors) > 0) {
158 5
            return end($this->parsing_errors);
159
        }
160
161 6
        return null;
162
    }
163
164 5
    public function get_errors() : ?array
165
    {
166 5
        return $this->parsing_errors;
167
    }
168
169 6
    public function add_parsing_error(string $message)
170
    {
171 6
        if (!is_array($this->parsing_errors)) {
172 6
            $this->parsing_errors = [];
173
        }
174
175 6
        $this->parsing_errors[] = $message;
176 6
    }
177
}
178