Completed
Push — develop ( bdb11d...45f5c6 )
by Neomerx
04:46
created

BundleStorage::setEncodedStorage()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 16
ccs 8
cts 8
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 8
nc 1
nop 1
crap 2
1
<?php namespace Limoncello\l10n\Messages;
2
3
/**
4
 * Copyright 2015-2017 [email protected]
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 * http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
use Limoncello\l10n\Contracts\Messages\BundleStorageInterface;
20
21
/**
22
 * @package Limoncello\l10n
23
 */
24
class BundleStorage implements BundleStorageInterface
25
{
26
    /** Encode index */
27
    const INDEX_DEFAULT_LOCALE = 0;
28
29
    /** Encode index */
30
    const INDEX_DATA = self::INDEX_DEFAULT_LOCALE + 1;
31
32
    /**
33
     * @var array
34
     */
35
    private $encodedStorage;
36
37
    /**
38
     * @var string[]
39
     */
40
    private $locales;
41
42
    /**
43
     * @var string
44
     */
45
    private $defaultLocale;
46
47
    /**
48
     * @param array $encodedStorage
49
     */
50 5
    public function __construct(array $encodedStorage)
51
    {
52 5
        $this->setEncodedStorage($encodedStorage);
53
    }
54
55
    /**
56
     * @inheritdoc
57
     */
58 5
    public function has(string $locale, string $namespace, string $key): bool
59
    {
60 5
        assert(
61 5
            $this->checkNonEmptyString($locale) === true &&
62 5
            $this->checkNonEmptyString($namespace) === true &&
63 5
            $this->checkNonEmptyStringOrInt($key) === true
64
        );
65
66 5
        $has = isset($this->getEncodedStorage()[$locale][$namespace][$key]);
67
68 5
        return $has;
69
    }
70
71
    /**
72
     * @inheritdoc
73
     */
74 5
    public function get(string $locale, string $namespace, string $key): ?array
75
    {
76 5
        $locale = $this->lookupLocale($this->getLocales(), $locale, $this->getDefaultLocale());
77
78 5
        $result = $this->has($locale, $namespace, $key) === true ?
79 5
            $this->getEncodedStorage()[$locale][$namespace][$key] : null;
80
81 5
        assert($result === null || $this->checkValueWithLocale($result) === true);
82
83 5
        return $result;
84
    }
85
86
    /**
87
     * @inheritdoc
88
     */
89 1
    public function hasResources(string $locale, string $namespace): bool
90
    {
91 1
        assert($this->checkNonEmptyString($locale) === true && $this->checkNonEmptyString($namespace) === true);
92
93 1
        $has = isset($this->getEncodedStorage()[$locale][$namespace]);
94
95 1
        return $has;
96
    }
97
98
    /**
99
     * @inheritdoc
100
     */
101 1
    public function getResources(string $locale, string $namespace): array
102
    {
103 1
        $locale = $this->lookupLocale($this->getLocales(), $locale, $this->getDefaultLocale());
104
105 1
        assert($this->hasResources($locale, $namespace) === true);
106
107 1
        $result = $this->getEncodedStorage()[$locale][$namespace];
108
109 1
        return $result;
110
    }
111
112
    /**
113
     * @inheritdoc
114
     */
115 5
    public function getDefaultLocale(): string
116
    {
117 5
        return $this->defaultLocale;
118
    }
119
120
    /**
121
     * @return array
122
     */
123 5
    protected function getEncodedStorage(): array
124
    {
125 5
        return $this->encodedStorage;
126
    }
127
128
    /**
129
     * @param string[] $locales
130
     * @param string   $locale
131
     * @param string   $defaultLocale
132
     *
133
     * @return string
134
     */
135 5
    protected function lookupLocale(array $locales, string $locale, string $defaultLocale): string
136
    {
137 5
        return locale_lookup($locales, $locale, false, $defaultLocale);
138
    }
139
140
    /**
141
     * @return string[]
142
     */
143 5
    protected function getLocales(): array
144
    {
145 5
        return $this->locales;
146
    }
147
148
    /**
149
     * @param array $encodedStorage
150
     *
151
     * @return self
152
     */
153 5
    protected function setEncodedStorage(array $encodedStorage): self
154
    {
155 5
        assert(count($encodedStorage) === 2);
156
157 5
        $encodedData = $encodedStorage[static::INDEX_DATA];
158
159
        // check storage has 3 levels locale -> namespace -> key & value + culture pairs and
160
        // keys, values and cultures are non-empty strings
161 5
        assert(is_array($encodedData) === true && $this->checkEncodedData($encodedData) === true);
162
163 5
        $this->defaultLocale  = $encodedStorage[static::INDEX_DEFAULT_LOCALE];
164 5
        $this->encodedStorage = $encodedData;
165 5
        $this->locales        = array_keys($encodedData);
0 ignored issues
show
Documentation Bug introduced by
It seems like array_keys($encodedData) of type array<integer,integer|string> is incompatible with the declared type array<integer,string> of property $locales.

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...
166
167 5
        return $this;
168
    }
169
170
    /**
171
     * @param array $encodedData
172
     *
173
     * @return bool
174
     */
175 5
    private function checkEncodedData(array $encodedData): bool
176
    {
177 5
        $isValid = true;
178 5
        foreach ($encodedData as $locale => $namespaceResources) {
179
            $isValid =
180 5
                $isValid === true && $isValid = $this->checkNonEmptyString($locale) === true &&
181 5
                $isValid === true && $isValid = is_array($namespaceResources) === true &&
182 5
                $isValid === true && $isValid = $this->checkNamespaceResources($namespaceResources);
183
        }
184
185 5
        return $isValid;
186
    }
187
188
    /**
189
     * @param array $namespaceResources
190
     *
191
     * @return bool
192
     */
193 5
    private function checkNamespaceResources(array $namespaceResources): bool
194
    {
195 5
        $isValid = true;
196 5
        foreach ($namespaceResources as $namespace => $resources) {
197
            $isValid =
198 5
                $isValid === true && $isValid = $this->checkNonEmptyString($namespace) === true &&
199 5
                $isValid === true && $isValid = is_array($resources) === true &&
200 5
                $isValid === true && $isValid = $this->checkResources($resources);
201
        }
202
203 5
        return $isValid;
204
    }
205
206
    /**
207
     * @param array $resources
208
     *
209
     * @return bool
210
     */
211 5
    private function checkResources(array $resources): bool
212
    {
213 5
        $isValid = true;
214 5
        foreach ($resources as $key => $valueAndLocale) {
215
            $isValid =
216 5
                $isValid === true && $isValid = $this->checkPair($key, $valueAndLocale);
217
        }
218
219 5
        return $isValid;
220
    }
221
222
    /**
223
     * @param string $key
224
     * @param array  $valueAndLocale
225
     *
226
     * @return bool
227
     */
228 5
    private function checkPair(string $key, array $valueAndLocale): bool
229
    {
230
        $result =
231 5
            $this->checkNonEmptyStringOrInt($key) === true && $this->checkValueWithLocale($valueAndLocale) === true;
232
233 5
        return $result;
234
    }
235
236
    /**
237
     * @param array $valueAndLocale
238
     *
239
     * @return bool
240
     */
241 5
    private function checkValueWithLocale(array $valueAndLocale): bool
242
    {
243
        $result =
244 5
            count($valueAndLocale) === 2 &&
245 5
            $this->checkNonEmptyString($valueAndLocale[static::INDEX_PAIR_VALUE]) === true &&
246 5
            $this->checkNonEmptyString($valueAndLocale[static::INDEX_PAIR_LOCALE]) === true;
247
248 5
        return $result;
249
    }
250
251
    /**
252
     * @param mixed $value
253
     *
254
     * @return bool
255
     */
256 5
    private function checkNonEmptyStringOrInt($value): bool
257
    {
258 5
        $result = $this->checkNonEmptyString($value) || is_int($value) === true;
259
260 5
        return $result;
261
    }
262
263
    /**
264
     * @param mixed $value
265
     *
266
     * @return bool
267
     */
268 5
    private function checkNonEmptyString($value): bool
269
    {
270 5
        $result = is_string($value) === true && (empty($value) === false || $value === '0');
271
272 5
        return $result;
273
    }
274
}
275