Passed
Push — 1.0.x ( 3a2c37...ccae28 )
by Julien
14:07 queued 06:59
created

Locale::getFromSession()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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