Localize   B
last analyzed

Complexity

Total Complexity 47

Size/Duplication

Total Lines 294
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 10
Bugs 3 Features 3
Metric Value
wmc 47
c 10
b 3
f 3
lcom 1
cbo 4
dl 0
loc 294
rs 8.439

18 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 12 3
A setResourceFileType() 0 5 1
A getResourceFileType() 0 3 1
A getValues() 0 3 1
A reloadConfig() 0 15 4
A checkDependences() 0 5 2
A setLocale() 0 4 1
A getLocales() 0 14 4
B getLocalesFromJson() 0 27 6
A getLocalesFromXml() 0 9 2
A get() 0 7 2
A onConfigChange() 0 3 1
A onLoad() 0 3 1
A onRemove() 0 3 1
A getValuesFromJson() 0 18 3
A getXmlResources() 0 13 3
B getValuesFromXml() 0 17 5
B parseXmlStringValues() 0 24 6

How to fix   Complexity   

Complex Class

Complex classes like Localize often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Localize, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/*
4
 * The MIT License
5
 *
6
 * Copyright 2016 Alejandro Peña Florentín ([email protected]).
7
 *
8
 * Permission is hereby granted, free of charge, to any person obtaining a copy
9
 * of this software and associated documentation files (the "Software"), to deal
10
 * in the Software without restriction, including without limitation the rights
11
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
 * copies of the Software, and to permit persons to whom the Software is
13
 * furnished to do so, subject to the following conditions:
14
 *
15
 * The above copyright notice and this permission notice shall be included in
16
 * all copies or substantial portions of the Software.
17
 *
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
 * THE SOFTWARE.
25
 */
26
27
namespace Tight\Modules\Localize;
28
29
/**
30
 * Localize module for translations
31
 *
32
 * @author Alejandro Peña Florentín ([email protected])
33
 */
34
class Localize extends \Tight\Modules\AbstractModule
35
{
36
37
    /**
38
     * @var string Resource file type
39
     */
40
    private $resourceFileType;
41
42
    /**
43
     * @var string Current locale
44
     */
45
    private $locale;
46
47
    /**
48
     * @var array Associative array for the current locale
49
     */
50
    private $values;
51
52
    /**
53
     * Constructor
54
     * 
55
     * @param array|\Tight\Modules\Localize\LocalizeConfig $config
56
     * @throws \InvalidArgumentException If $config is not an array or an object
57
     * of \Tight\Modules\Localize\LocalizeConfig class
58
     */
59
    public function __construct($config = []) {
60
        if (is_array($config)) {
61
            $config = new \Tight\Modules\Localize\LocalizeConfig($config);
62
        } else if (!$config instanceof \Tight\Modules\Localize\LocalizeConfig) {
63
            throw new \InvalidArgumentException("Argument 1 passed to " . get_class($this) . " must be an array or an instance of Tight\Modules\Localize\LocalizeConfig");
64
        }
65
        parent::__construct("LocalizeModule", "v1.2");
66
        $this->setConfig($config);
67
        $this->checkDependences();
68
        $this->setResourceFileType($this->getConfig()->resourceFileType);
69
        $this->setLocale($this->getConfig()->defaultLocale);
70
    }
71
72
    /**
73
     * Sets the resource file type
74
     * @param string $resourceFileType Resource file type
75
     * @return \Tight\Modules\Localize\Localize Fluent setter
76
     */
77
    public function setResourceFileType($resourceFileType) {
78
        $this->resourceFileType = $resourceFileType;
79
        $this->reloadConfig();
80
        return $this;
81
    }
82
83
    /**
84
     * Gets the current resource file type
85
     * @return string Resource file type
86
     * @see \Tight\Modules\Localize\LocalizeConfig::FILETYPE_INI
87
     * @see \Tight\Modules\Localize\LocalizeConfig::FILETYPE_JSON
88
     * @see \Tight\Modules\Localize\LocalizeConfig::FILETYPE_XML
89
     */
90
    public function getResourceFileType() {
91
        return $this->resourceFileType;
92
    }
93
94
    /**
95
     * Gets all the defined values for the current locale
96
     * @return array Associative array of values
97
     */
98
    public function getValues() {
99
        return $this->values;
100
    }
101
102
    /**
103
     * Reloads the class with the new locale
104
     */
105
    public function reloadConfig() {
106
        if (null == $this->locale) {
107
            $this->locale = $this->getConfig()->defaultLocale;
108
        }
109
        $values = null;
110
        switch ($this->resourceFileType) {
111
            case LocalizeConfig::FILETYPE_JSON:
112
                $values = $this->getValuesFromJson();
113
                break;
114
            case LocalizeConfig::FILETYPE_XML:
115
                $values = $this->getValuesFromXml();
116
                break;
117
        }
118
        $this->values = $values;
119
    }
120
121
    /**
122
     * Checks the dependences for the class
123
     * @throws \Tight\Exception\ModuleException If resource directory cant be 
124
     * found
125
     */
126
    private function checkDependences() {
127
        if (!is_dir($this->getConfig()->resourceFolder)) {
128
            throw new \Tight\Exception\ModuleException("Resource directory not found");
129
        }
130
    }
131
132
    /**
133
     * Sets a new locale
134
     * @param string $locale New defined locale
135
     * @throws \Tight\Exception\ModuleException If resource default resource file
136
     * cant be found
137
     */
138
    public function setLocale($locale) {
139
        $this->locale = $locale;
140
        $this->reloadConfig();
141
    }
142
143
    /**
144
     * Gets the available locales
145
     * @return array Available locales
146
     */
147
    public function getLocales() {
148
        $output = [];
149
        switch ($this->resourceFileType) {
150
            case LocalizeConfig::FILETYPE_JSON:
151
                $output = $this->getLocalesFromJson();
152
                break;
153
            case LocalizeConfig::FILETYPE_XML:
154
                $output = $this->getLocalesFromXml();
155
                break;
156
            case LocalizeConfig::FILETYPE_INI:
157
                break;
158
        }
159
        return $output;
160
    }
161
162
    private function getLocalesFromJson() {
163
        $output = [];
164
        $directory = $this->getConfig()->resourceFolder;
165
        $fileName = $this->getConfig()->resourceFileName;
166
        $dir = opendir($directory);
167
        $files = [];
168
        while ($entry = readdir($dir)) {
169
            if (strpos($entry, $fileName) !== false) {
170
                $files[] = $entry;
171
            }
172
        }
173
        foreach ($files as $element) {
174
            $file = \Tight\Utils::getSlicedFile($directory . $element);
175
            //Removes extension
176
            $name = $file["name"];
177
            $explode = explode($this->getConfig()->langSeparator, $name);
178
            // Get the locale of the defined file type
179
            if ($file["ext"] == $this->getConfig()->resourceFileType) {
180
                if (count($explode) > 1) {
181
                    $output[] = $explode[count($explode) - 1];
182
                } else {
183
                    $output[] = $this->getConfig()->defaultLocale;
184
                }
185
            }
186
        }
187
        return $output;
188
    }
189
190
    /**
191
     * Gets the json values from the json file
192
     * @return array String values
193
     * @throws \Tight\Exception\ModuleException If json file cant be found
194
     */
195
    private function getValuesFromJson() {
196
        $output = [];
197
        $folder = \Tight\Utils::addTrailingSlash($this->getConfig()->resourceFolder);
198
        $fileName = $this->getConfig()->resourceFileName . $this->getConfig()->langSeparator . $this->locale . "." . $this->getConfig()->resourceFileType;
199
        $file = $folder . $fileName;
200
        if (is_file($file)) {
201
            $output = json_decode(file_get_contents($file), JSON_FORCE_OBJECT);
202
        } else {
203
            $fileName = $this->getConfig()->resourceFileName . "." . $this->getConfig()->resourceFileType;
204
            $file = $folder . $fileName;
205
            if (is_file($file)) {
206
                $output = json_decode(file_get_contents($file), JSON_FORCE_OBJECT);
207
            } else {
208
                throw new \Tight\Exception\ModuleException("Resource file <strong>" . $file . "</strong> not found");
209
            }
210
        }
211
        return $output;
212
    }
213
214
    /**
215
     * Gets the locales from the xml resource file
216
     * @return array Array of locales
217
     */
218
    private function getLocalesFromXml() {
219
        $output = [];
220
        $resources = $this->getXmlResources();
221
        $size = count($resources->values);
222
        for ($index = 0; $index < $size; $index++) {
223
            $output[] = $resources->values[$index]['lang']->__toString();
224
        }
225
        return $output;
226
    }
227
228
    /**
229
     * Gets the xml resource read from the xml resource file
230
     * @return \SimpleXMLElement XML values for the current locale
231
     * @throws \Tight\Exception\ModuleException If xml values resource file cant be found
232
     */
233
    private function getXmlResources() {
234
        $output = null;
235
        if ($this->resourceFileType === LocalizeConfig::FILETYPE_XML) {
236
            $file = \Tight\Utils::addTrailingSlash($this->getConfig()->resourceFolder) . $this->getConfig()->resourceFileName . "." . $this->resourceFileType;
237
            if (is_file($file)) {
238
                $xmlContent = file_get_contents($file);
239
                $output = new \SimpleXMLElement($xmlContent);
240
            } else {
241
                throw new \Tight\Exception\ModuleException("Resource file <strong>" . $file . "</strong> does not exists");
242
            }
243
        }
244
        return $output;
245
    }
246
247
    /**
248
     * Gets the values from xml resource file
249
     * @return array Array of values
250
     * @throws \Tight\Exception\ModuleException If the current locale cant be 
251
     * found in the xml resource file
252
     */
253
    private function getValuesFromXml() {
254
        $resources = $this->getXmlResources();
255
        $locale = null;
256
        $size = count($resources->values);
257
        $index = 0;
258
        while ($index < $size && $locale == null) {
259
            if ($resources->values[$index]['lang'] == $this->locale) {
260
                $locale = $resources->values[$index];
261
            }
262
            $index++;
263
        }
264
        if (null == $locale) {
265
            $fileName = $this->getConfig()->resourceFileName . "." . $this->getConfig()->resourceFileType;
266
            throw new \Tight\Exception\ModuleException("Locale <strong>" . $this->locale . "</strong> not found at resource file <strong>" . $fileName . "</strong>");
267
        }
268
        return $this->parseXmlStringValues($locale);
269
    }
270
271
    /**
272
     * Parses a \SimpleXmlElement object to get its values
273
     * @param \SimpleXMLElement $xml XML object
274
     * @return array Values
275
     */
276
    private function parseXmlStringValues(\SimpleXMLElement $xml) {
277
        $output = [];
278
        if ($xml->count() > 0) {
279
            $children = $xml->children();
280
            $size = count($children);
281
            for ($index = 0; $index < $size; $index++) {
282
                // If xml tag is <array>, parse without merge
283
                if ($children[$index]->getName() === "array") {
284
                    $key = $children[$index]['name'];
285
                    if (null !== $key) {
286
                        $output[$key->__toString()] = $this->parseXmlStringValues($children[$index]);
287
                    }
288
                } else {
289
                    $output = array_merge($output, $this->parseXmlStringValues($children[$index]));
290
                }
291
            }
292
        } else {
293
            $key = $xml['name'];
294
            if (null !== $key) {
295
                $output[$key->__toString()] = $xml->__toString();
296
            }
297
        }
298
        return $output;
299
    }
300
301
    /**
302
     * Gets a value from a defined key
303
     * @param string $key Key
304
     * @return string Value defined for the key $key or an empty string if the
305
     * key is not defined
306
     */
307
    public function get($key) {
308
        if (isset($this->values[$key])) {
309
            return $this->values[$key];
310
        } else {
311
            return "";
312
        }
313
    }
314
315
    public function onConfigChange() {
316
        $this->reloadConfig();
317
    }
318
319
    public function onLoad() {
320
        
321
    }
322
323
    public function onRemove() {
324
        
325
    }
326
327
}
328