Completed
Push — master ( bae02d...4b4318 )
by Ivan
01:47
created

BrowserLocale   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 232
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 96.67%

Importance

Changes 5
Bugs 0 Features 0
Metric Value
wmc 27
c 5
b 0
f 0
lcom 1
cbo 1
dl 0
loc 232
ccs 58
cts 60
cp 0.9667
rs 10

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A getLocale() 0 4 1
A getLocales() 0 8 2
A parseAcceptLanguages() 0 14 4
A splitAcceptLanguages() 0 4 2
A splitAcceptLanguage() 0 4 2
A getLanguage() 0 4 1
A getCountry() 0 8 2
A getWeight() 0 11 2
A sortLocales() 0 10 3
B filterLocaleInfo() 0 18 5
A parseAcceptLanguage() 0 19 2
1
<?php
2
3
namespace CodeZero\BrowserLocale;
4
5
class BrowserLocale
6
{
7
    /**
8
     * Array of all preferred locales that are
9
     * configured in a visitor's browser.
10
     *
11
     * @var array
12
     */
13
    protected $locales = [];
14
15
    /**
16
     * Supported filters for getLocales().
17
     *
18
     * @var array
19
     */
20
    protected $filters = ['full', 'language', 'country', 'weight'];
21
22
    /**
23
     * Create a new BrowserLocale instance.
24
     *
25
     * @param string $httpAcceptLanguages
26
     */
27 8
    public function __construct($httpAcceptLanguages)
28
    {
29
        // $_SERVER["HTTP_ACCEPT_LANGUAGE"] will return a comma separated list of language codes.
30
        // Each language code MAY have a "relative quality factor" attached ("nl;q=0.8") which
31
        // determines the order of preference. For example: "nl-NL,nl;q=0.8,en-US;q=0.6,en;q=0.4"
32 8
        $this->parseAcceptLanguages($httpAcceptLanguages);
33 8
    }
34
35
    /**
36
     * Get the most preferred locale.
37
     *
38
     * @return \CodeZero\BrowserLocale\Locale|null
39
     */
40 3
    public function getLocale()
41
    {
42 3
        return $this->locales[0] ?? null;
43
    }
44
45
    /**
46
     * Get an array of Locale objects in descending order of preference.
47
     *
48
     * If a property filter is specified, a flattened array of locale information,
49
     * containing only the requested property values will be returned instead.
50
     *
51
     * @param string $propertyFilter
52
     *
53
     * @return array
54
     */
55 6
    public function getLocales($propertyFilter = null)
56
    {
57 6
        if ($propertyFilter === null) {
58 2
            return $this->locales;
59
        }
60
61 5
        return $this->filterLocaleInfo($propertyFilter);
62
    }
63
64
    /**
65
     * Parse all HTTP Accept Languages.
66
     *
67
     * @param string $httpAcceptLanguages
68
     *
69
     * @return void
70
     */
71 8
    protected function parseAcceptLanguages($httpAcceptLanguages)
72
    {
73 8
        if (empty($httpAcceptLanguages)) {
74 1
            return;
75
        }
76
77 7
        foreach ($this->splitAcceptLanguages($httpAcceptLanguages) as $httpAcceptLanguage) {
78 7
            if ($locale = $this->parseAcceptLanguage($httpAcceptLanguage)) {
1 ignored issue
show
Bug introduced by
Are you sure the assignment to $locale is correct as $this->parseAcceptLanguage($httpAcceptLanguage) (which targets CodeZero\BrowserLocale\B...::parseAcceptLanguage()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
79 7
                $this->locales[] = $locale;
80
            }
81
        }
82
83 7
        $this->sortLocales();
84 7
    }
85
86
    /**
87
     * Extract and save information from a HTTP Accept Language.
88
     *
89
     * @param string $httpAcceptLanguage
90
     *
91
     * @return \CodeZero\BrowserLocale\Locale|null
92
     */
93 7
    protected function parseAcceptLanguage($httpAcceptLanguage)
94
    {
95 7
        $parts = $this->splitAcceptLanguage($httpAcceptLanguage);
96
97 7
        $locale = $parts[0] ?? null;
98 7
        $weight = $parts[1] ?? null;
99
100 7
        if ($locale === null) {
101
            return null;
102
        }
103
104 7
        $localeInstance = new Locale();
105 7
        $localeInstance->full = $locale;
106 7
        $localeInstance->language = $this->getLanguage($locale);
107 7
        $localeInstance->country = $this->getCountry($locale);
108 7
        $localeInstance->weight = $this->getWeight($weight);
109
110 7
        return $localeInstance;
111
    }
112
113
    /**
114
     * Convert a comma separated list to an array.
115
     *
116
     * Example: ["en", "en-US;q=0.8"]
117
     *
118
     * @param string $httpAcceptLanguages
119
     *
120
     * @return array
121
     */
122 7
    protected function splitAcceptLanguages($httpAcceptLanguages)
123
    {
124 7
        return explode(',', $httpAcceptLanguages) ?: [];
125
    }
126
127
    /**
128
     * Split a language code and the relative quality factor by semicolon.
129
     *
130
     * Example: ["en"] or ["en-US"] or ["en-US", "q=0.8"]
131
     *
132
     * @param string $httpAcceptLanguage
133
     *
134
     * @return array
135
     */
136 7
    protected function splitAcceptLanguage($httpAcceptLanguage)
137
    {
138 7
        return explode(';', trim($httpAcceptLanguage)) ?: [];
139
    }
140
141
    /**
142
     * Get the 2-letter language code from the locale.
143
     *
144
     * Example: "en"
145
     *
146
     * @param string $locale
147
     *
148
     * @return string
149
     */
150 7
    protected function getLanguage($locale)
151
    {
152 7
        return substr($locale, 0, 2);
153
    }
154
155
    /**
156
     * Get the 2-letter country code from the locale.
157
     *
158
     * Example: "US"
159
     *
160
     * @param string $locale
161
     *
162
     * @return string
163
     */
164 7
    protected function getCountry($locale)
165
    {
166 7
        if (($divider = strpos($locale, '-')) === false){
167 7
            return '';
168
        }
169
170 7
        return substr($locale, $divider + 1, 2);
171
    }
172
173
    /**
174
     * Parse the relative quality factor and return its value.
175
     *
176
     * Example: 1.0 or 0.8
177
     *
178
     * @param string $q
179
     *
180
     * @return float
181
     */
182 7
    protected function getWeight($q)
183
    {
184 7
        $weight = 1.0;
185 7
        $parts = explode('=', $q);
186
187 7
        if (isset($parts[1])) {
188 7
            $weight = ((float) $parts[1]);
189
        }
190
191 7
        return $weight;
192
    }
193
194
    /**
195
     * Sort the array of locales in descending order of preference.
196
     *
197
     * @return void
198
     */
199
    protected function sortLocales()
200
    {
201 7
        usort($this->locales, function ($a, $b) {
202 7
            if ($a->weight === $b->weight) {
203 1
                return 0;
204
            }
205
206 7
            return ($a->weight > $b->weight) ? -1 : 1;
207 7
        });
208 7
    }
209
210
    /**
211
     * Get a flattened array of locale information,
212
     * containing only the requested property values.
213
     *
214
     * @param string $property
215
     *
216
     * @return array
217
     */
218 5
    protected function filterLocaleInfo($property)
219
    {
220 5
        $locales = $this->locales;
221
222 5
        if ( ! in_array($property, $this->filters)) {
223
            return $locales;
224
        }
225
226 5
        $filtered = [];
227
228 5
        foreach ($locales as $locale) {
229 4
            if ($locale->$property && ! in_array($locale->$property, $filtered)) {
230 4
                $filtered[] = $locale->$property;
231
            }
232
        }
233
234 5
        return $filtered;
235
    }
236
}
237