Passed
Push — master ( 06ad6f...5bb8ab )
by Alexander
05:30
created

Translator::validateLocale()   C

Complexity

Conditions 11
Paths 16

Size

Total Lines 53
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 0
loc 53
rs 6.2926
cc 11
eloc 25
nc 16
nop 1

How to fix   Long Method    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
 * PHP version 5.6
5
 *
6
 * Translator
7
 *
8
 * @category Translator
9
 * @package  Hokan22\LaravelTranslator
10
 * @author   Alexander Viertel <[email protected]>
11
 * @license  http://opensource.org/licenses/MIT MIT
12
 * @link     https://github.com/Hokan22/laravel-translator
13
 */
14
namespace Hokan22\LaravelTranslator;
15
16
use Hokan22\LaravelTranslator\Handler\DatabaseHandler;
17
use Hokan22\LaravelTranslator\Handler\HandlerInterface;
18
use Hokan22\LaravelTranslator\Handler\TranslationNotFoundException;
19
use Hokan22\LaravelTranslator\Models\TranslationIdentifier;
20
use Illuminate\Support\Facades\Config;
21
use Illuminate\Support\Facades\Log;
22
use Symfony\Component\Translation\Exception\NotFoundResourceException;
23
24
25
/**
26
 * Class Translator
27
 *
28
 * @category Translator
29
 * @package  Hokan22\LaravelTranslator
30
 * @author   Alexander Viertel <[email protected]>
31
 * @license  http://opensource.org/licenses/MIT MIT
32
 * @link     https://github.com/Hokan22/laravel-translator
33
 */
34
class Translator
35
{
36
    /** @var array|HandlerInterface[] $aHandler Class to Handle the Translation defined in config */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
37
    protected $aHandler = [];
38
    /** @var string $locale The locale to translate to  */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
39
    protected $locale = '';
40
    /** @var string $group The translation group */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
41
    protected $group = 'default';
42
    /** @var string $configName The name of the config file */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
43
    protected $configName = 'translator';
44
    /** @var array $config Config cache */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
45
    protected $config;
46
47
    /**
48
     * Translator constructor.
49
     *
50
     * @param string $locale The locale to translate to
51
     *
52
     * @throws \Exception
53
     */
54
    public function __construct($locale = '')
55
    {
56
        $this->config = Config::get($this->configName);
57
58
        $this->setLocale($locale);
59
    }
60
61
    /**
62
     * Return the config value for given key
63
     *
64
     * @param string $key Key for the config value to get
65
     *
66
     * @return string|array Config value for $key
67
     */
68
    public function getConfigValue($key)
69
    {
70
        return $this->config[$key];
71
    }
72
73
    /**
74
     * Actual translate function
75
     * $parameter and $locale are optional
76
     *
77
     * @param string $identifier The identifier of the translation
0 ignored issues
show
Coding Style introduced by
Expected 5 spaces after parameter type; 1 found
Loading history...
78
     * @param array|null $parameters The parameters to inject into the translation
79
     * @param string $locale The locale to which to translate to overrides the class location for one translation
0 ignored issues
show
Coding Style introduced by
Expected 5 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Expected 5 spaces after parameter name; 1 found
Loading history...
80
     *
81
     * @throws \Exception
82
     *
83
     * @return string Returns the translation with replaced parameters
84
     *
85
     * @todo Make function Parameters interchangeable
86
     */
87
    public function translate($identifier, $parameters = null, $locale = null)
88
    {
89
        // Validate the locale given as parameter or take the saved locale
90
        if ($locale !== null) {
91
            $locale = $this->validateLocale($locale);
92
        } else {
93
            $locale = $this->locale;
94
        }
95
96
        //Create a Handler if no one exists for the current locale
97
        if (!isset($this->aHandler[$locale])) {
98
            $this->aHandler[$locale] = $this->createHandler($locale);
99
        }
100
101
        // Try getting the resulting Translation
102
        // Based on the internal translate function, the getTranslation can throw exceptions
103
        try {
104
            $translation = $this->aHandler[$locale]->getTranslation($identifier, $this->group);
105
106
        } catch (NotFoundResourceException $exception) {
107
            // Thrown when the Identifier wasn't found
108
            // Log exception as error in Laravel log
109
            $this->log($exception, 'error');
110
111
            // Listener: When app is not in production and listening is enabled
112
            // add any missing translation identifier to the database
113
            if ($this->config['listening_enabled'] === true) {
114
                $this->addMissingIdentifier($identifier, $parameters, 'default');
115
            }
116
117
            return $this->returnMissingTranslation($identifier, $locale);
118
119
        } catch (TranslationNotFoundException $exception) {
120
            // Thrown when no translation for the locale was found
121
            // Log exception as error in Laravel log
122
            $this->log($exception, 'error');
123
124
            return $this->returnMissingTranslation($identifier, $locale);
125
        }
126
127
        // If there are no parameters, skip replacement
128
        if (is_array($parameters)) {
129
            $translation = $this->replaceParameter($translation, $parameters);
130
        }
131
132
        // Return the translation
133
        return $translation;
134
    }
135
136
    /**
137
     * Creates the Handler for the given locale
138
     *
139
     * @param string $locale The locale for which to create a handler
140
     *
141
     * @return HandlerInterface
142
     */
143
    protected function createHandler($locale)
144
    {
145
        // Get the Handler class from config file
146
        $handler_class = $this->config['handler'];
147
        // Define message as empty for later check
148
        $oHandler = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $oHandler is dead and can be removed.
Loading history...
149
150
        // Try to create new Instance of Handler and return it
151
        // If creating the Handler fails or it does not implement HandlerInterface the DatabaseHandler will be used
152
        try {
153
            $oHandler = new $handler_class($locale);
154
            if (!is_a($handler_class, 'Hokan22\LaravelTranslator\Handler\HandlerInterface', true)) {
155
                throw new \Exception($handler_class . ' does not implement HandlerInterface!');
156
            }
157
        } catch (\Exception $exception) {
158
            // Log error and fallback procedure
159
            $this->log($exception, 'error');
160
            $this->log('Falling back to DatabaseHandler', 'warning');
161
162
            // Fallback to Database Handler
163
            $oHandler = new DatabaseHandler($locale);
164
        }
165
        return $oHandler;
166
    }
167
168
    /**
169
     * Set the locale to use in translations
170
     *
171
     * @param string $locale The locale to use
172
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
173
    public function setLocale($locale)
174
    {
175
        $locale = $this->validateLocale($locale);
176
177
        if (!isset($this->aHandler[$locale])) {
178
            $this->aHandler[$locale] = $this->createHandler($locale);
179
        }
180
181
        $this->locale = $locale;
182
    }
183
184
    /**
185
     * Add the missing identifier to the texts table in the database
186
     *
187
     * @param string $identifier The identifier to add to the db
188
     * @param array $parameters The parameters available for the translation
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
189
     * @param string $group The group to put the identifier in
0 ignored issues
show
Coding Style introduced by
Expected 6 spaces after parameter name; 1 found
Loading history...
190
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
191
    public function addMissingIdentifier($identifier, $parameters, $group)
192
    {
193
        if (!$this->hasIdentifier($identifier)) {
194
195
            // Save only the keys from the parameter array
196
            $keys = [];
197
            if (is_array($parameters)) {
0 ignored issues
show
introduced by
The condition is_array($parameters) can never be false.
Loading history...
198
                foreach($parameters as $key => $value) {
0 ignored issues
show
Coding Style introduced by
Expected "foreach (...) {\n"; found "foreach(...) {\n"
Loading history...
199
                    $keys[] = $key;
200
                }
201
            }
202
            // Create new TranslationIdentifier with parameters and current url
203
            TranslationIdentifier::create(
204
                [
205
                    "identifier"    => $identifier,
206
                    "parameters"    => $keys,
207
                    "group"         => isset($group) ? $group : 'default',
208
                    "page_name"     => app()->runningInConsole() ? '' : substr(request()->getRequestUri(), 1),
0 ignored issues
show
introduced by
The method runningInConsole() does not exist on Illuminate\Container\Container. Are you sure you never get this type here, but always one of the subclasses? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

208
                    "page_name"     => app()->/** @scrutinizer ignore-call */ runningInConsole() ? '' : substr(request()->getRequestUri(), 1),
Loading history...
209
                ]
210
            );
211
212
            if (isset($this->aHandler[$this->locale])) {
213
                // refresh the Cache for the handler
214
                // When using file Cache, adding the Identifier to the Database will not add it to file Cache!
215
                $this->aHandler[$this->locale]->refreshCache();
216
            }
217
            // Print notice about creation to laravel log
218
            $this->log('The translation string "'.$identifier.'" will be written to the Database', 'notice');
219
        } else {
220
            $this->log('The translation string "'.$identifier.'" is already in the Database!', 'warning');
221
        }
222
    }
223
224
    /**
225
     * Check if the identifier exists in the database
226
     *
227
     * @param string $identifier The identifier to check
228
     *
229
     * @return boolean Returns true if the identifier was found
230
     */
231
    public function hasIdentifier($identifier)
232
    {
233
        // Returns true if at least one identifier was found
234
        return TranslationIdentifier::where('identifier', $identifier)->count() > 0;
235
    }
236
237
    /**
238
     * Replace the parameters in the translation
239
     *
240
     * @param string $translation The translation with the parameter tags
241
     * @param array $parameters The parameters which to inject in the translation
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Expected 2 spaces after parameter name; 1 found
Loading history...
242
     *
243
     * @return string Returns the translation which its parameters replaced
244
     *
245
     * @todo Make Prefix and Suffix configurable
246
     */
247
    protected function replaceParameter($translation, $parameters)
248
    {
249
        // Go through each specified Parameter and replace its placeholder "{$key}"
250
        foreach ($parameters as $key => $parameter) {
251
            // If the string (e.g "{name}") is not specified within the "parameters" array it won't be replaced!
252
            $translation = str_replace("{".$key."}", $parameter, $translation);
253
        }
254
        return $translation;
255
    }
256
257
    /**
258
     * Instead of the translation echo back 'Missing Translation' (when not in production!)
259
     * and show the translation identifier ($identifier) and the locale
260
     *
261
     * @param string $identifier The identifier which is missing
262
     * @param string $locale The locale of which the translation is missing
0 ignored issues
show
Coding Style introduced by
Expected 5 spaces after parameter name; 1 found
Loading history...
263
     *
264
     * @throws \Exception
265
     *
266
     * @return string The string to display instead of the translation
267
     */
268
    protected function returnMissingTranslation($identifier, $locale)
269
    {
270
        // Return identifier and locale for easier debug
271
        if (config('app.env') !== 'production') {
272
            return '&lt;'.$identifier.':'.$locale.'&gt;';
273
        }
274
        return $identifier;
275
    }
276
277
    /**
278
     * Checks the given locale and returns a valid local
279
     * If no locale was given, first try the locale from the session
280
     * If the Session has no
281
     *
282
     * @param string $locale The locale to validate
283
     *
284
     * @throws NotFoundResourceException
285
     *
286
     * @return string Returns the validated Locale
287
     */
288
    protected function validateLocale($locale)
289
    {
290
        // Set message for later log warning
291
        $message = '';
292
293
        //Get Locales configs from translator config file
294
        $avail_locales      = $this->config['available_locales'];
295
        $default_locale     = $this->config['default_locale'];
296
297
        // If locale is already set and not empty it has already been checked
298
        if ($this->locale == $locale && $this->locale !== '') {
299
            return $locale;
300
        }
301
302
        // Fallback if empty locale was given (should be handled in middleware)
303
        if ($locale == null){
0 ignored issues
show
Coding Style introduced by
Expected "if (...) {\n"; found "if (...){\n"
Loading history...
Coding Style introduced by
There must be a single space between the closing parenthesis and the opening brace of a multi-line IF statement; found 0 spaces
Loading history...
304
            if (session()->get('locale') != '') {
305
                $locale = session()->get('locale');
306
            }
307
            else {
0 ignored issues
show
Coding Style introduced by
Expected "} else \n"; found "\n else {\n"
Loading history...
308
                return $default_locale;
309
            }
310
        }
311
312
        // If the given locale is not defined as valid, try to get a fallback locale
313
        if (!in_array($locale, $avail_locales)){
0 ignored issues
show
Coding Style introduced by
Expected "if (...) {\n"; found "if (...){\n"
Loading history...
Coding Style introduced by
There must be a single space between the closing parenthesis and the opening brace of a multi-line IF statement; found 0 spaces
Loading history...
314
315
            $found_locales = [];
316
317
            // Find any available locale which contains the locale as substring
318
            foreach ($avail_locales as $avail_locale) {
319
                if (strpos($avail_locale, $locale) !== false){
0 ignored issues
show
Coding Style introduced by
Expected "if (...) {\n"; found "if (...){\n"
Loading history...
Coding Style introduced by
There must be a single space between the closing parenthesis and the opening brace of a multi-line IF statement; found 0 spaces
Loading history...
320
                    $found_locales[] = $avail_locale;
321
                }
322
            }
323
324
            // Check if default locale is inside the found locales. If it was, use it!
325
            if (in_array($default_locale, $found_locales)){
0 ignored issues
show
Coding Style introduced by
Expected "if (...) {\n"; found "if (...){\n"
Loading history...
Coding Style introduced by
There must be a single space between the closing parenthesis and the opening brace of a multi-line IF statement; found 0 spaces
Loading history...
326
                $message = 'Locale "'.$locale.'" was not found! Falling back to default locale "'.$default_locale.'"';
327
                $locale = $default_locale;
328
329
                // Check if any Locale containing '$locale' was found previously
330
            } elseif (count($found_locales, 0) >= 1) {
331
                $message = 'Locale "'.$locale.'" was not found! Falling back to similar locale "'.$found_locales[0].'"';
332
                $locale = $found_locales[0];
333
            } else {
334
                throw new NotFoundResourceException("Locale '".$locale."' was not found in available locales");
335
            }
336
        }
337
338
        if ($message !== '') $this->log($message, 'warning');
0 ignored issues
show
Coding Style introduced by
Inline control structures are discouraged
Loading history...
339
340
        return $locale;
341
    }
342
343
    /**
344
     * Returns all translation in the in $locale from $group
345
     *
346
     * @param string $locale The locale of the translations to get
347
     * @param string $group The group of the translations to get
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 1 found
Loading history...
348
     *
349
     * @return array|mixed Returns an array of all translation in the $locale from group $group
350
     */
351
    public function getAllTranslations($locale, $group)
352
    {
353
        if (!isset($this->aHandler[$locale])) {
354
            $this->aHandler[$locale] = $this->createHandler($locale);
355
        }
356
357
        return $this->aHandler[$locale]->getAllTranslations($group);
358
    }
359
360
    /**
361
     * Log the given exception or string $exception as type $log_type when config log_level is set to debug
362
     *
363
     * @param \Exception|string $exception The Exception to log
364
     * @param string $log_type The type of the log to write in the log file
0 ignored issues
show
Coding Style introduced by
Expected 12 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Expected 2 spaces after parameter name; 1 found
Loading history...
365
     *
366
     */
0 ignored issues
show
Coding Style introduced by
Additional blank lines found at end of doc comment
Loading history...
Coding Style introduced by
Missing @return tag in function comment
Loading history...
367
    protected function log($exception, $log_type = 'notice')
368
    {
369
        if ($this->config['log_level'] !== 'debug') {
370
            return;
371
        }
372
373
        switch ($log_type) {
374
            case 'error':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
375
                Log::error($exception);
376
                break;
377
378
            case 'warning':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
379
                Log::warning($exception);
380
                break;
381
382
            case 'notice':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
383
            default :
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
384
                Log::notice($exception);
385
                break;
386
        }
387
    }
388
}