Test Setup Failed
Push — master ( 505488...66cfa9 )
by Avtandil
02:18
created

MultiLang::removeLocaleFromPath()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 1
dl 0
loc 10
ccs 6
cts 6
cp 1
crap 2
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/*
3
 * This file is part of the Laravel MultiLang package.
4
 *
5
 * (c) Avtandil Kikabidze aka LONGMAN <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Longman\LaravelMultiLang;
12
13
use Closure;
14
use Illuminate\Cache\CacheManager as Cache;
15
use Illuminate\Database\DatabaseManager as Database;
16
use Illuminate\Http\Request;
17
use Illuminate\Support\Collection;
18
use Illuminate\Support\Str;
19
use InvalidArgumentException;
20
21
class MultiLang
22
{
23
    /**
24
     * Language/Locale.
25
     *
26
     * @var string
27
     */
28
    protected $lang;
29
30
    /**
31
     * System environment
32
     *
33
     * @var string
34
     */
35
    protected $environment;
36
37
    /**
38
     * Config.
39
     *
40
     * @var \Longman\LaravelMultiLang\Config
41
     */
42
    protected $config;
43
44
    /**
45
     * Repository
46
     *
47
     * @var \Longman\LaravelMultiLang\Repository
48
     */
49
    protected $repository;
50
51
    /**
52
     * Texts.
53
     *
54
     * @var array
55
     */
56
    protected $texts;
57
58
    /**
59
     * Missing texts.
60
     *
61
     * @var array
62
     */
63
    protected $new_texts;
64
65
    /**
66
     * Application scope.
67
     *
68
     * @var string
69
     */
70
    protected $scope = 'global';
71
72
    /**
73
     * Create a new MultiLang instance.
74
     *
75
     * @param string $environment
76
     * @param array $config
77
     * @param \Illuminate\Cache\CacheManager $cache
78
     * @param \Illuminate\Database\DatabaseManager $db
79
     */
80 26
    public function __construct($environment, array $config, Cache $cache, Database $db)
81
    {
82 26
        $this->environment = $environment;
83 26
        $this->cache = $cache;
0 ignored issues
show
Bug introduced by
The property cache does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
84 26
        $this->db = $db;
0 ignored issues
show
Bug introduced by
The property db does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
85
86 26
        $this->setConfig($config);
87
88 26
        $this->setRepository(new Repository($this->config, $cache, $db));
89 26
    }
90
91
    /**
92
     * Set multilang config
93
     *
94
     * @param array $config
95
     * @return $this
96
     */
97 26
    public function setConfig(array $config)
98
    {
99 26
        $this->config = new Config($config);
100
101 26
        return $this;
102
    }
103
104
    /**
105
     * Set repository object
106
     *
107
     * @param \Longman\LaravelMultiLang\Repository $repository
108
     * @return $this
109
     */
110 26
    public function setRepository(Repository $repository)
111
    {
112 26
        $this->repository = $repository;
113
114 26
        return $this;
115
    }
116
117
    /**
118
     * Get repository object
119
     *
120
     * @return \Longman\LaravelMultiLang\Repository
121
     */
122 2
    public function getRepository()
123
    {
124 2
        return $this->repository;
125
    }
126
127
    /**
128
     * Set application scope
129
     *
130
     * @param $scope
131
     * @return $this
132
     */
133
    public function setScope($scope)
134
    {
135
        $this->scope = $scope;
136
137
        return $this;
138
    }
139
140
    /**
141
     * Get application scope
142
     *
143
     * @return string
144
     */
145
    public function getScope()
146
    {
147
        return $this->scope;
148
    }
149
150
    /**
151
     * Set locale and load texts
152
     *
153
     * @param  string $lang
154
     * @param  array $texts
155
     * @return void
156
     */
157 24
    public function setLocale($lang, array $texts = null)
158
    {
159 24
        if (! $lang) {
160 1
            throw new InvalidArgumentException('Locale is empty');
161
        }
162 23
        $this->lang = $lang;
163
164 23
        if (! is_array($texts)) {
165 20
            $texts = $this->loadTexts($this->getLocale(), $this->scope);
166 20
        }
167
168 23
        $this->texts = $texts;
169 23
    }
170
171
    /**
172
     * Load texts
173
     *
174
     * @param  string $lang
175
     * @param  string $scope
176
     * @return array
177
     */
178 20
    public function loadTexts($lang, $scope = null)
179
    {
180 20
        if ($this->environment != 'production' || $this->config->get('cache.enabled', true) === false) {
181 18
            $texts = $this->repository->loadFromDatabase($lang, $scope);
182
183 18
            return $texts;
184
        }
185
186 3
        if ($this->repository->existsInCache($lang)) {
187
            $texts = $this->repository->loadFromCache($lang, $scope);
188
        } else {
189 3
            $texts = $this->repository->loadFromDatabase($lang, $scope);
190 3
            $this->repository->storeInCache($lang, $texts, $scope);
191
        }
192
193 3
        return $texts;
194
    }
195
196
    /**
197
     * Get translated text
198
     *
199
     * @param  string $key
200
     * @param  array $replace
201
     * @return string
202
     */
203 9
    public function get($key, array $replace = [])
204
    {
205
206 9
        if (empty($key)) {
207 1
            throw new InvalidArgumentException('String key not provided');
208
        }
209
210 8
        if (! $this->lang) {
211 1
            return $key;
212
        }
213
214 7
        if (! isset($this->texts[$key])) {
215 4
            $this->queueToSave($key);
216
217 4
            return $this->replaceMarkers($key, $replace);
218
        }
219
220 3
        $text = $this->texts[$key];
221
222 3
        return $this->replaceMarkers($text, $replace);
223
    }
224
225
    /**
226
     * Replace markers in text
227
     *
228
     * @param  string $text
229
     * @param  array $replace
230
     * @return string
231
     */
232 7
    protected function replaceMarkers($text, array $replace = [])
233
    {
234 7
        if (empty($replace)) {
235 6
            return $text;
236
        }
237
238 1
        return $this->makeReplacements($text, $replace);
239
    }
240
241
    /**
242
     * Make the place-holder replacements on a line.
243
     *
244
     * @param  string $text
245
     * @param  array $replace
246
     * @return string
247
     */
248 1
    protected function makeReplacements($text, array $replace)
249
    {
250 1
        $replace = $this->sortReplacements($replace);
251
252 1
        foreach ($replace as $key => $value) {
253 1
            $text = str_replace(
254 1
                [':' . $key, ':' . Str::upper($key), ':' . Str::ucfirst($key)],
255 1
                [$value, Str::upper($value), Str::ucfirst($value)],
256
                $text
257 1
            );
258 1
        }
259
260 1
        return $text;
261
    }
262
263
    /**
264
     * Sort the replacements array.
265
     *
266
     * @param  array $replace
267
     * @return \Illuminate\Support\Collection
268
     */
269
    protected function sortReplacements(array $replace)
270
    {
271 1
        return (new Collection($replace))->sortBy(function ($value, $key) {
272 1
            return mb_strlen($key) * -1;
273 1
        });
274
    }
275
276
    /**
277
     * Get redirect url in middleware
278
     *
279
     * @param \Illuminate\Http\Request $request
280
     * @return null|string
281
     */
282 4
    public function getRedirectUrl(Request $request)
283
    {
284 4
        $locale = $request->segment(1);
285 4
        $fallback_locale = $this->config->get('default_locale', 'en');
286 4
        $exclude_segments = $this->config->get('exclude_segments', []);
287 4
        if (in_array($locale, $exclude_segments)) {
288
            return null;
289
        }
290
291 4
        if (strlen($locale) == 2) {
292 3
            $locales = $this->config->get('locales', []);
293
294 3
            if (! isset($locales[$locale])) {
295 2
                $segments = $request->segments();
296 2
                $segments[0] = $fallback_locale;
297 2
                $url = implode('/', $segments);
298 2
                if ($query_string = $request->server->get('QUERY_STRING')) {
299 1
                    $url .= '?' . $query_string;
300 1
                }
301
302 2
                return $url;
303
            }
304 1
        } else {
305 1
            $segments = $request->segments();
306 1
            $url = $fallback_locale . '/' . implode('/', $segments);
307 1
            if ($query_string = $request->server->get('QUERY_STRING')) {
308
                $url .= '?' . $query_string;
309
            }
310
311 1
            return $url;
312
        }
313
314 1
        return null;
315
    }
316
317
    /**
318
     * Detect locale based on url segment
319
     *
320
     * @param \Illuminate\Http\Request $request
321
     * @return string
322
     */
323 1
    public function detectLocale(Request $request)
324
    {
325 1
        $locale = $request->segment(1);
326 1
        $locales = $this->config->get('locales');
327
328 1
        if (isset($locales[$locale])) {
329 1
            return isset($locales[$locale]['locale']) ? $locales[$locale]['locale'] : $locale;
330
        }
331
332
        return $this->config->get('default_locale', 'en');
333
    }
334
335
    /**
336
     * Wrap routes to available languages group
337
     *
338
     * @param \Closure $callback
339
     */
340
    public function routeGroup(Closure $callback)
341
    {
342
        $router = app('router');
343
344
        $locales = $this->config->get('locales', []);
345
346
        foreach ($locales as $locale => $val) {
347
            $router->group([
348
                'prefix' => $locale,
349
                'as'     => $locale . '.',
350
            ], $callback);
351
        }
352
    }
353
354
    /**
355
     *  Manage texts
356
     */
357
    public function manageTextsRoutes()
358
    {
359
        $router = app('router');
360
        $route = $this->config->get('text-route.route', 'texts');
361
        $controller = $this->config->get(
362
            'text-route.controller',
363
            '\Longman\LaravelMultiLang\Controllers\TextsController'
364
        );
365
366
        $router->get(
367
            $route,
368
            ['uses' => $controller . '@index']
369
        );
370
        $router->post(
371
            $route,
372
            ['uses' => $controller . '@save']
373
        );
374
    }
375
376
    /**
377
     * Get texts
378
     *
379
     * @return array
380
     */
381 4
    public function getTexts()
382
    {
383
384 4
        return $this->texts;
385
    }
386
387
    /**
388
     * Get all texts
389
     *
390
     * @param string $lang
391
     * @param string $scope
392
     * @return array
393
     */
394
    public function getAllTexts($lang = null, $scope = null)
395
    {
396
        return $this->repository->loadAllFromDatabase($lang, $scope);
397
    }
398
399
    /**
400
     * Set texts manually
401
     *
402
     * @param  array $texts_array
403
     * @return \Longman\LaravelMultiLang\MultiLang
404
     */
405 4
    public function setTexts(array $texts_array)
406
    {
407 4
        $texts = [];
408 4
        foreach ($texts_array as $key => $value) {
409 4
            $texts[$key] = $value;
410 4
        }
411
412 4
        $this->texts = $texts;
413
414 4
        return $this;
415
    }
416
417
    /**
418
     * Queue missing texts
419
     *
420
     * @param  string $key
421
     * @return void
422
     */
423 4
    protected function queueToSave($key)
424
    {
425 4
        $this->new_texts[$key] = $key;
426 4
    }
427
428
    /**
429
     * Get language prefixed url
430
     *
431
     * @param string $path
432
     * @param string $lang
433
     * @return string
434
     */
435 3
    public function getUrl($path, $lang = null)
436
    {
437 3
        $locale = $lang ? $lang : $this->getLocale();
438 3
        if ($locale) {
439 3
            $path = $locale . '/' . $this->removeLocaleFromPath($path);
440 3
        }
441
442 3
        return $path;
443
    }
444
445
    /**
446
     * Remove locale from the path
447
     *
448
     * @param string $path
449
     * @return string
450
     */
451 3
    private function removeLocaleFromPath($path)
452
    {
453 3
        $locales = $this->config->get('locales');
454 3
        $locale = mb_substr($path, 0, 2);
455 3
        if (isset($locales[$locale])) {
456 1
            return mb_substr($path, 3);
457
        }
458
459 3
        return $path;
460
    }
461
462
    /**
463
     * Get language prefixed route
464
     *
465
     * @param string $name
466
     * @return string
467
     */
468 1
    public function getRoute($name)
469
    {
470 1
        $locale = $this->getLocale();
471 1
        if ($locale) {
472 1
            $name = $locale . '.' . $name;
473 1
        }
474
475 1
        return $name;
476
    }
477
478
    /**
479
     * Check if autosave allowed
480
     *
481
     * @return bool
482
     */
483 5
    public function autoSaveIsAllowed()
484
    {
485 5
        if ($this->environment == 'local' && $this->config->get('db.autosave', true)) {
486 1
            return true;
487
        }
488
489 5
        return false;
490
    }
491
492
    /**
493
     * Get locale
494
     *
495
     * @return string
496
     */
497 21
    public function getLocale()
498
    {
499 21
        return $this->lang;
500
    }
501
502
    /**
503
     * Get available locales
504
     *
505
     * @return array
506
     */
507 1
    public function getLocales()
508
    {
509 1
        return $this->config->get('locales');
510
    }
511
512
    /**
513
     * Save missing texts
514
     *
515
     * @return bool
516
     */
517 3
    public function saveTexts()
518
    {
519 3
        if (empty($this->new_texts)) {
520 3
            return false;
521
        }
522
523 3
        $this->repository->save($this->new_texts, $this->scope);
524
525 3
        return true;
526
    }
527
}
528