Passed
Push — master ( 4b3582...7f619e )
by Julien
06:12
created

Locale::lookup()   B

Complexity

Conditions 10
Paths 17

Size

Total Lines 39
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 10.017

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 10
eloc 17
c 1
b 0
f 0
nc 17
nop 4
dl 0
loc 39
ccs 17
cts 18
cp 0.9444
crap 10.017
rs 7.6666

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * This file is part of the Zemit Framework.
5
 *
6
 * (c) Zemit Team <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE.txt
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Zemit;
13
14
use Zemit\Di\Injectable;
15
use Zemit\Support\Options\Options;
16
use Zemit\Support\Options\OptionsInterface;
17
18
/**
19
 * Allow to manage and lookup the locale for the localisation
20
 * @property string|null $locale The current locale
21
 */
22
class Locale extends Injectable implements OptionsInterface
23
{
24
    use Options;
25
    
26
    /**
27
     * Default (router only)
28
     */
29
    public const string MODE_DEFAULT = 'default';
0 ignored issues
show
Bug introduced by
A parse error occurred: Syntax error, unexpected T_STRING, expecting '=' on line 29 at column 24
Loading history...
30
    
31
    /**
32
     * Router
33
     */
34
    public const string MODE_ROUTE = 'route';
35
    
36
    /**
37
     * Router -> http
38
     */
39
    public const string MODE_HTTP = 'http';
40
    
41
    /**
42
     * Router -> session -> http
43
     */
44
    public const string MODE_SESSION = 'session';
45
    
46
    /**
47
     * Locale mode
48
     * Locale::MODE_DEFAULT 'default' (Router -> http)
49
     * Locale::MODE_SESSION 'session' (Router -> session -> http)
50
     */
51
    public string $mode = self::MODE_DEFAULT;
52
    
53
    /**
54
     * The actual locale that was picked
55
     * @var string|null
56
     */
57
    public ?string $locale = null;
58
    
59
    /**
60
     * Session key for storing the locale
61
     * @var string $sessionKey The session key for storing the locale.
62
     */
63
    public string $sessionKey = 'zemit-locale';
64
    
65
    /**
66
     * Default locale
67
     *
68
     * This variable holds the default locale value for the application.
69
     * If no locale is explicitly specified, this value will be used.
70
     *
71
     * @var string $default
72
     */
73
    public string $default = 'en';
74
    
75
    /**
76
     * Array of allowed languages.
77
     *
78
     * @var array $allowed An array of allowed languages.
79
     */
80
    public array $allowed = ['en'];
81
    
82
    /**
83
     * Initializes the object by setting its properties based on the provided options.
84
     *
85
     * This method retrieves the values of the sessionKey, allowed, default, and mode options using the getOption()
86
     * method. If these options are not provided, the default values specified in the class properties are used instead.
87
     *
88
     * It then sets the obtained values to the corresponding class properties using the appropriate setter methods,
89
     * namely setAllowed(), setDefault(), and setMode(). Additionally, it assigns the obtained sessionKey value directly
90
     * to the sessionKey property.
91
     *
92
     * Finally, the initialize() method prepares the default value by calling the prepare() method with the getDefault()
93
     * method as its parameter.
94
     *
95
     * @return void
96
     */
97 21
    public function initialize(): void
98
    {
99 21
        $this->sessionKey = $this->getOption('sessionKey', $this->sessionKey);
100 21
        $this->setAllowed($this->getOption('allowed', $this->allowed));
101 21
        $this->setDefault($this->getOption('default', $this->default));
102 21
        $this->setMode($this->getOption('mode', $this->mode));
103 21
        $this->prepare($this->getDefault());
104
    }
105
    
106
    /**
107
     * Alias of the getLocale() method
108
     */
109 3
    public function get(): ?string
110
    {
111 3
        return $this->getLocale();
112
    }
113
    
114
    /**
115
     * Retrieves the locale value of the object.
116
     *
117
     * This method returns the value of the locale property, which represents the current locale of the object.
118
     * The locale property is set using the setLocale() method or may be null if no locale is set.
119
     *
120
     * @return string|null The locale value of the object, or null if no locale is set.
121
     */
122 21
    public function getLocale(): ?string
123
    {
124 21
        return $this->locale;
125
    }
126
    
127
    /**
128
     * Set the current locale value
129
     */
130 21
    public function setLocale(?string $locale = null): void
131
    {
132 21
        $this->locale = $this->lookup($locale);
133
    }
134
    
135
    /**
136
     * Get the default locale
137
     */
138 21
    public function getDefault(): string
139
    {
140 21
        return $this->default;
141
    }
142
    
143
    /**
144
     * Set the default locale value
145
     */
146 21
    public function setDefault(string $locale): void
147
    {
148 21
        $this->default = $locale;
149
    }
150
    
151
    /**
152
     * Get the list of possible locale
153
     */
154 21
    public function getAllowed(): array
155
    {
156 21
        return $this->allowed;
157
    }
158
    
159
    /**
160
     * Set the allowed locale
161
     */
162 21
    public function setAllowed(array $allowed): void
163
    {
164 21
        $this->allowed = array_values(array_unique($allowed));
165
    }
166
    
167
    /**
168
     * Get the defined mode
169
     */
170 1
    public function getMode(): string
171
    {
172 1
        return $this->mode;
173
    }
174
    
175
    /**
176
     * Set the mode
177
     */
178 21
    public function setMode(string $mode): void
179
    {
180 21
        $this->mode = $mode;
181
    }
182
    
183
    /**
184
     * Prepare and set and return the locale based on the defined mode
185
     */
186 21
    public function prepare(?string $default = null): ?string
187
    {
188 21
        $locale = match ($this->mode) {
189 21
            self::MODE_SESSION =>
190 1
                $this->getFromRoute() ??
191 1
                $this->getFromSession() ??
192 1
                $this->getFromHttp() ??
193 1
                $default,
194 21
            self::MODE_HTTP =>
195 1
                $this->getFromRoute() ??
196 1
                $this->getFromHttp() ??
197 1
                $default,
198 21
            default =>
199 21
                $this->getFromRoute() ??
200 21
                $default,
201 21
        };
202
        
203 21
        $locale ??= $this->locale;
204 21
        $this->setLocale($locale);
205 21
        $this->saveIntoSession($locale);
206 21
        return $this->getLocale();
207
    }
208
    
209
    /**
210
     * Retrieves the locale from the route
211
     */
212 21
    public function getFromRoute(?string $default = null): ?string
213
    {
214 21
        return $this->lookup($this->router->getParams()['locale'] ?? $default);
215
    }
216
    
217
    /**
218
     * Retrieves the locale from the dispatcher
219
     */
220
    public function getFromDispatcher(?string $default = null): ?string
221
    {
222
        return $this->lookup($this->dispatcher->getParams()['locale'] ?? $default);
223
    }
224
    
225
    /**
226
     * Retrieves the locale from the session
227
     */
228 2
    public function getFromSession(?string $default = null): ?string
229
    {
230 2
        return $this->lookup($this->session->get($this->sessionKey, $default));
231
    }
232
    
233
    /**
234
     * Retrieves the locale from the request
235
     * of getBestLanguage() header
236
     * or HTTP_ACCEPT_LANGUAGE header
237
     */
238 3
    public function getFromHttp(?string $default = null): ?string
239
    {
240 3
        return
241 3
            $this->lookup($this->request->getBestLanguage()) ?:
242 3
            \Locale::acceptFromHttp($this->request->getHeader('HTTP_ACCEPT_LANGUAGE')) ?:
243 3
            $default;
244
    }
245
    
246
    /**
247
     * Save locale into session if mode contain session handling
248
     */
249 21
    public function saveIntoSession(?string $locale = null, bool $force = false): void
250
    {
251 21
        $locale ??= $this->getLocale();
252
        
253
        // save into session
254 21
        if ($force || $this->mode === self::MODE_SESSION) {
255 2
            $this->session->set($this->sessionKey, $locale);
256
        }
257
    }
258
    
259
    /**
260
     * @param string|null $locale The locale to use as the language range when matching.
261
     * @param array|null $allowed An array containing a list of language tags to compare to locale. Maximum 100 items allowed.
262
     * @param bool $canonicalize If true, the arguments will be converted to canonical form before matching.
263
     * @param string|null $default The locale to use if no match is found.
264
     * @return string|null The closest matching language tag or default value.
265
     */
266 21
    public function lookup(?string $locale = null, ?array $allowed = null, bool $canonicalize = false, ?string $default = null): ?string
267
    {
268 21
        if (is_null($locale)) {
269 21
            return null;
270
        }
271
        
272 21
        $allowed ??= $this->getAllowed();
273
        
274
        // lookup first
275 21
        $lookup = \Locale::lookup($allowed, $locale, $canonicalize, $default);
276
        
277
        // base locale found without the region
278 21
        $force = false;
279 21
        if (isset($lookup) && ($locale === $lookup || strlen($lookup) === 2)) {
280 21
            $locale = $lookup;
281 21
            $force = true;
282
        }
283
        
284
        // lookup for the first configured region based on the locale without region
285 21
        if (empty($lookup) || $force) {
286
            
287
            // matches all the possible regions from the locale
288 21
            $matches = array_filter($allowed, function ($haystack) use ($locale) {
289 21
                $needle = $locale . '_';
290 21
                return stripos($haystack, $needle) === 0;
291 21
            });
292
            
293
            // some matches
294 21
            if (count($matches)) {
295
                // lookup again with the first match
296
                $lookup = \Locale::lookup($matches, array_shift($matches), $canonicalize, $default);
297
            }
298
            else {
299
                // otherwise keep the lookup if set or set the default if not
300 21
                $lookup = empty($lookup) ? $default : $lookup;
301
            }
302
        }
303
        
304 21
        return empty($lookup) ? null : $lookup;
305
    }
306
}
307