Completed
Push — master ( a8a12e...c67798 )
by Mathieu
05:04
created

LocalesManager::setCurrentLocale()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 8
nc 3
nop 1
1
<?php
2
3
namespace Charcoal\Translator;
4
5
use InvalidArgumentException;
6
7
/**
8
 *
9
 */
10
class LocalesManager
11
{
12
    /**
13
     * @var array
14
     */
15
    private $locales;
16
17
    /**
18
     * @var string[]
19
     */
20
    private $languages;
21
22
    /**
23
     * @var string
24
     */
25
    private $defaultLanguage;
26
27
    /**
28
     * @var string|null
29
     */
30
    private $currentLocale;
31
32
    /**
33
     * Create the Locales Manager with locales and optional options.
34
     *
35
     * Required parameters:
36
     * - **locales** (`array`)
37
     *
38
     * Optional parameters:
39
     * - **default_language** (`string`)
40
     *   - If none is set, the first language (from _locales_) will be used
41
     * - **fallback_languages** (`string[]`)
42
     *   - If none is set, then the default language will be used.
43
     *
44
     * @param array $data Constructor dependencies.
45
     * @throws InvalidArgumentException If the default language is not a valid language.
46
     */
47
    public function __construct(array $data)
48
    {
49
        $this->setLocales($data['locales']);
50
        $this->languages = array_keys($this->locales);
0 ignored issues
show
Documentation Bug introduced by
It seems like array_keys($this->locales) of type array<integer,integer|string> is incompatible with the declared type array<integer,string> of property $languages.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
51
52
        if (isset($data['default_language'])) {
53
            if (!in_array($data['default_language'], $this->languages)) {
54
                throw new InvalidArgumentException(
55
                    sprintf(
56
                        'Default language is not a valid language. Must be one of "%s"',
57
                        implode(', ', $this->languages)
58
                    )
59
                );
60
            }
61
            $this->defaultLanguage = $data['default_language'];
62
        } else {
63
            $this->defaultLanguage = $this->languages[0];
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->languages[0] can also be of type integer. However, the property $defaultLanguage is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
64
        }
65
    }
66
67
    /**
68
     * Retrieve the available locales information.
69
     *
70
     * @return array;
0 ignored issues
show
Documentation introduced by
The doc-type array; could not be parsed: Expected "|" or "end of type", but got ";" at position 5. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
71
     */
72
    public function locales()
73
    {
74
        return $this->locales;
75
    }
76
77
    /**
78
     * Retrieve the available languages (locale codes).
79
     *
80
     * @return string[]
81
     */
82
    public function availableLocales()
83
    {
84
        return $this->languages;
85
    }
86
87
    /**
88
     * @param string|null $lang The current language (ident).
89
     * @throws InvalidArgumentException If the language is invalid.
90
     * @return void
91
     */
92
    public function setCurrentLocale($lang)
93
    {
94
        if ($lang === null) {
95
            $this->currentLocale = null;
96
            return;
97
        }
98
        if (!$this->hasLocale($lang)) {
99
            throw new InvalidArgumentException(
100
                sprintf('Invalid language. Must be one of "%s"', implode(', ', $this->availableLocales()))
101
            );
102
        }
103
        $this->currentLocale = $lang;
104
    }
105
106
    /**
107
     * Retrieve the current language
108
     *
109
     * @return string
110
     */
111
    public function currentLocale()
112
    {
113
        if ($this->currentLocale === null) {
114
            return $this->defaultLanguage;
115
        }
116
        return $this->currentLocale;
117
    }
118
119
    /**
120
     * @param string $lang The language (code) to check.
121
     * @return boolean
122
     */
123
    public function hasLocale($lang)
124
    {
125
        return in_array($lang, $this->availableLocales());
126
    }
127
128
    /**
129
     * Ensure that explicitely inactive locales are skipped.
130
     * Also ensure that the required values are set on the locales configuration structure.
131
     * This method is only called from the constructor.
132
     *
133
     * @param array $locales The locales configuration structure.
134
     * @throws InvalidArgumentException If there are no active locales.
135
     * @return void
136
     */
137
    private function setLocales(array $locales)
138
    {
139
        $this->locales = [];
140
        foreach ($locales as $language => $locale) {
141
            if (isset($locale['active']) && !$locale['active']) {
142
                continue;
143
            }
144
            if (!isset($locale['locale'])) {
145
                $locale['locale'] = $language;
146
            }
147
            $this->locales[$language] = $locale;
148
        }
149
        if (empty($this->locales)) {
150
            throw new InvalidArgumentException(
151
                'Locales can not be empty.'
152
            );
153
        }
154
    }
155
}
156