Completed
Push — master ( b47912...4eb3ae )
by ARCANEDEV
12s
created

Localization::setSupportedLocales()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 6
ccs 3
cts 3
cp 1
crap 1
rs 9.4285
c 0
b 0
f 0
1
<?php namespace Arcanedev\Localization;
2
3
use Arcanedev\Localization\Contracts\LocalesManager as LocalesManagerContract;
4
use Arcanedev\Localization\Contracts\Localization as LocalizationContract;
5
use Arcanedev\Localization\Contracts\RouteTranslator as RouteTranslatorContract;
6
use Arcanedev\Localization\Exceptions\UnsupportedLocaleException;
7
use Arcanedev\Localization\Utilities\Url;
8
use Illuminate\Contracts\Foundation\Application as ApplicationContract;
9
use Illuminate\Contracts\View\Factory as ViewFactoryContract;
10
use Illuminate\Http\Request;
11
12
/**
13
 * Class     Localization
14
 *
15
 * @package  Arcanedev\Localization
16
 * @author   ARCANEDEV <[email protected]>
17
 */
18
class Localization implements LocalizationContract
19
{
20
    /* -----------------------------------------------------------------
21
     |  Properties
22
     | -----------------------------------------------------------------
23
     */
24
25
    /**
26
     * Base url.
27
     *
28
     * @var string
29
     */
30
    protected $baseUrl;
31
32
    /**
33
     * Laravel application instance.
34
     *
35
     * @var \Illuminate\Contracts\Foundation\Application
36
     */
37
    private $app;
38
39
    /**
40
     * The RouteTranslator instance.
41
     *
42
     * @var \Arcanedev\Localization\Contracts\RouteTranslator
43
     */
44
    protected $routeTranslator;
45
46
    /**
47
     * The LocalesManager instance.
48
     *
49
     * @var \Arcanedev\Localization\Contracts\LocalesManager
50
     */
51
    private $localesManager;
52
53
    /* -----------------------------------------------------------------
54
     |  Constructor
55
     | -----------------------------------------------------------------
56
     */
57
58
    /**
59
     * Localization constructor.
60
     *
61
     * @param  \Illuminate\Contracts\Foundation\Application       $app
62
     * @param  \Arcanedev\Localization\Contracts\RouteTranslator  $routeTranslator
63
     * @param  \Arcanedev\Localization\Contracts\LocalesManager   $localesManager
64
     */
65 252
    public function __construct(
66
        ApplicationContract     $app,
67
        RouteTranslatorContract $routeTranslator,
68
        LocalesManagerContract  $localesManager
69
    ) {
70 252
        $this->app             = $app;
71 252
        $this->routeTranslator = $routeTranslator;
72 252
        $this->localesManager  = $localesManager;
73
74 252
        $this->localesManager->setDefaultLocale(
75 252
            $this->app['config']->get('app.locale')
76
        );
77 252
    }
78
79
    /* -----------------------------------------------------------------
80
     |  Getters & Setters
81
     | -----------------------------------------------------------------
82
     */
83
84
    /**
85
     * Get Request instance.
86
     *
87
     * @return \Illuminate\Http\Request
88
     */
89 106
    private function request()
90
    {
91 106
        return $this->app['request'];
92
    }
93
94
    /**
95
     * Returns default locale.
96
     *
97
     * @return string
98
     */
99 116
    public function getDefaultLocale()
100
    {
101 116
        return $this->localesManager->getDefaultLocale();
102
    }
103
104
    /**
105
     * Return an array of all supported Locales.
106
     *
107
     * @return \Arcanedev\Localization\Entities\LocaleCollection
108
     */
109 108
    public function getSupportedLocales()
110
    {
111 108
        return $this->localesManager->getSupportedLocales();
112
    }
113
114
    /**
115
     * Set the supported locales.
116
     *
117
     * @param  array  $supportedLocales
118
     *
119
     * @return self
120
     */
121 4
    public function setSupportedLocales(array $supportedLocales)
122
    {
123 4
        $this->localesManager->setSupportedLocales($supportedLocales);
124
125 2
        return $this;
126
    }
127
128
    /**
129
     * Get supported locales keys.
130
     *
131
     * @return array
132
     */
133 2
    public function getSupportedLocalesKeys()
134
    {
135 2
        return $this->localesManager->getSupportedLocalesKeys();
136
    }
137
138
    /**
139
     * Returns current language.
140
     *
141
     * @return string
142
     */
143 110
    public function getCurrentLocale()
144
    {
145 110
        return $this->localesManager->getCurrentLocale();
146
    }
147
148
    /**
149
     * Returns current language.
150
     *
151
     * @return \Arcanedev\Localization\Entities\Locale
152
     */
153 10
    public function getCurrentLocaleEntity()
154
    {
155 10
        return $this->localesManager->getCurrentLocaleEntity();
156
    }
157
158
    /**
159
     * Returns current locale name.
160
     *
161
     * @return string
162
     */
163 2
    public function getCurrentLocaleName()
164
    {
165 2
        return $this->getCurrentLocaleEntity()->name();
166
    }
167
168
    /**
169
     * Returns current locale script.
170
     *
171
     * @return string
172
     */
173 2
    public function getCurrentLocaleScript()
174
    {
175 2
        return $this->getCurrentLocaleEntity()->script();
176
    }
177
178
    /**
179
     * Returns current locale direction.
180
     *
181
     * @return string
182
     */
183 2
    public function getCurrentLocaleDirection()
184
    {
185 2
        return $this->getCurrentLocaleEntity()->direction();
186
    }
187
188
    /**
189
     * Returns current locale native name.
190
     *
191
     * @return string
192
     */
193 2
    public function getCurrentLocaleNative()
194
    {
195 2
        return $this->getCurrentLocaleEntity()->native();
196
    }
197
198
    /**
199
     * Returns current locale regional.
200
     *
201
     * @return string
202
     */
203 2
    public function getCurrentLocaleRegional()
204
    {
205 2
        return $this->getCurrentLocaleEntity()->regional();
206
    }
207
208
    /**
209
     * Get all locales.
210
     *
211
     * @return \Arcanedev\Localization\Entities\LocaleCollection
212
     */
213 2
    public function getAllLocales()
214
    {
215 2
        return $this->localesManager->getAllLocales();
216
    }
217
218
    /**
219
     * Set and return current locale.
220
     *
221
     * @param  string|null  $locale
222
     *
223
     * @return string
224
     */
225 252
    public function setLocale($locale = null)
226
    {
227 252
        return $this->localesManager->setLocale($locale);
228
    }
229
230
    /**
231
     * Sets the base url for the site.
232
     *
233
     * @param  string  $url
234
     *
235
     * @return self
236
     */
237 252
    public function setBaseUrl($url)
238
    {
239 252
        if (substr($url, -1) !== '/') $url .= '/';
240
241 252
        $this->baseUrl = $url;
242
243 252
        return $this;
244
    }
245
246
    /* -----------------------------------------------------------------
247
     |  Main Methods
248
     | -----------------------------------------------------------------
249
     */
250
251
    /**
252
     * Translate routes and save them to the translated routes array (used in the localize route filter).
253
     *
254
     * @param  string  $routeName
255
     *
256
     * @return string
257
     */
258 252
    public function transRoute($routeName)
259
    {
260 252
        return $this->routeTranslator->trans($routeName);
261
    }
262
263
    /**
264
     * Returns an URL adapted to $locale or current locale.
265
     *
266
     * @param  string|null  $url
267
     * @param  string|null  $locale
268
     *
269
     * @return string
270
     */
271 4
    public function localizeURL($url = null, $locale = null)
272
    {
273 4
        return $this->getLocalizedURL($locale, $url);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The expression $this->getLocalizedURL($locale, $url); of type string|false adds false to the return on line 273 which is incompatible with the return type declared by the interface Arcanedev\Localization\C...calization::localizeURL of type string. It seems like you forgot to handle an error condition.
Loading history...
274
    }
275
276
    /**
277
     * It returns an URL without locale (if it has it).
278
     *
279
     * @param  string|null  $url
280
     *
281
     * @return string
282
     */
283 106
    public function getNonLocalizedURL($url = null)
284
    {
285 106
        return $this->getLocalizedURL(false, $url);
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Comprehensibility Best Practice introduced by
The expression $this->getLocalizedURL(false, $url); of type string|false adds false to the return on line 285 which is incompatible with the return type declared by the interface Arcanedev\Localization\C...ion::getNonLocalizedURL of type string. It seems like you forgot to handle an error condition.
Loading history...
286
    }
287
288
    /**
289
     * Returns an URL adapted to $locale or current locale.
290
     *
291
     * @todo: Refactor this beast
292
     *
293
     * @param  string|null  $locale
294
     * @param  string|null  $url
295
     * @param  array        $attributes
296
     * @param  bool|false   $showHiddenLocale
297
     *
298
     * @return string|false
299
     */
300 106
    public function getLocalizedURL($locale = null, $url = null, array $attributes = [], $showHiddenLocale = false)
301
    {
302 106
        if (is_null($locale))
303 10
            $locale = $this->getCurrentLocale();
304
305 106
        $this->isLocaleSupportedOrFail($locale);
306
307 106
        if (empty($attributes))
308 106
            $attributes = Url::extractAttributes($url);
309
310 106
        if (empty($url)) {
311 10
            if ($this->routeTranslator->hasCurrentRoute()) {
312 2
                if (empty($attributes))
313 2
                    $attributes = $this->request()->route()->parameters();
314
315 2
                return $this->getUrlFromRouteName(
316 1
                    $locale,
317 2
                    $this->routeTranslator->getCurrentRoute(),
318 1
                    $attributes,
319 1
                    $showHiddenLocale
320
                );
321
            }
322
323 10
            $url = $this->request()->fullUrl();
324
        }
325
326
        if (
327 106
            $locale &&
328 106
            $translatedRoute = $this->findTranslatedRouteByUrl($url, $attributes, $this->getCurrentLocale())
329
        ) {
330 52
            return $this->getUrlFromRouteName($locale, $translatedRoute, $attributes, $showHiddenLocale);
331
        }
332
333 106
        $baseUrl    = $this->request()->getBaseUrl();
334 106
        $parsedUrl  = parse_url($url);
335
336 106
        $translatedRoute = $this->routeTranslator->getTranslatedRoute(
337 106
            $baseUrl, $parsedUrl, $this->getDefaultLocale(), $this->getSupportedLocales()
338
        );
339
340 106
        if ($translatedRoute !== false)
341 104
            return $this->getUrlFromRouteName($locale, $translatedRoute, $attributes, $showHiddenLocale);
342
343 90
        if ( ! empty($locale)) {
344 56
            if ($locale !== $this->getDefaultLocale() || ! $this->isDefaultLocaleHiddenInUrl() || $showHiddenLocale) {
345 52
                $parsedUrl['path'] = $locale.'/'.ltrim($parsedUrl['path'], '/');
346
            }
347
        }
348
349 90
        $parsedUrl['path'] = ltrim(ltrim($baseUrl, '/') . '/' . $parsedUrl['path'], '/');
350 90
        $parsedUrl['path'] = rtrim($parsedUrl['path'], '/');
351
352 90
        $url = Url::unparse($parsedUrl);
353
354 90
        if (filter_var($url, FILTER_VALIDATE_URL)) return $url;
355
356 2
        return $this->createUrlFromUri(
357 2
            empty($url) ? $parsedUrl['path'] : $url
358
        );
359
    }
360
361
    /**
362
     * Create an url from the uri.
363
     *
364
     * @param  string  $uri
365
     *
366
     * @return string
367
     */
368 110
    public function createUrlFromUri($uri)
369
    {
370 110
        $uri = ltrim($uri, '/');
371
372 110
        return empty($this->baseUrl)
373
            ? $this->app[\Illuminate\Contracts\Routing\UrlGenerator::class]->to($uri)
374 110
            : $this->baseUrl.$uri;
375
    }
376
377
    /**
378
     * Get locales navigation bar.
379
     *
380
     * @return string
381
     */
382 2
    public function localesNavbar()
383
    {
384
        /** @var  \Illuminate\Contracts\View\Factory  $view */
385 2
        $view = $this->app[ViewFactoryContract::class];
386
387 2
        return $view->make('localization::navbar', ['supportedLocales' => $this->getSupportedLocales()])
388 2
                    ->render();
389
    }
390
391
    /* -----------------------------------------------------------------
392
     |  Translation Methods
393
     | -----------------------------------------------------------------
394
     */
395
396
    /**
397
     * Returns the translated route for an url and the attributes given and a locale
398
     *
399
     * @param  string  $url
400
     * @param  array   $attributes
401
     * @param  string  $locale
402
     *
403
     * @return string|false
404
     */
405 104
    private function findTranslatedRouteByUrl($url, $attributes, $locale)
406
    {
407 104
        if (empty($url)) return false;
408
409
        // check if this url is a translated url
410 104
        foreach ($this->routeTranslator->getTranslatedRoutes() as $translatedRoute) {
411 104
            $translatedUrl = $this->getUrlFromRouteName($locale, $translatedRoute, $attributes);
412
413 104
            if ($this->getNonLocalizedURL($translatedUrl) === $this->getNonLocalizedURL($url))
0 ignored issues
show
Security Bug introduced by
It seems like $translatedUrl defined by $this->getUrlFromRouteNa...atedRoute, $attributes) on line 411 can also be of type false; however, Arcanedev\Localization\L...n::getNonLocalizedURL() does only seem to accept string|null, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
414 104
                return $translatedRoute;
415
        }
416
417 56
        return false;
418
    }
419
420
    /**
421
     * Returns an URL adapted to the route name and the locale given.
422
     *
423
     * @param  string|bool  $locale
424
     * @param  string       $transKey
425
     * @param  array        $attributes
426
     * @param  bool|false   $showHiddenLocale
427
     *
428
     * @return string|false
429
     */
430 110
    public function getUrlFromRouteName($locale, $transKey, array $attributes = [], $showHiddenLocale = false)
431
    {
432 110
        $this->isLocaleSupportedOrFail($locale);
0 ignored issues
show
Bug introduced by
It seems like $locale defined by parameter $locale on line 430 can also be of type boolean; however, Arcanedev\Localization\L...LocaleSupportedOrFail() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
433
434 108
        $route = $this->routeTranslator->getUrlFromRouteName(
435 54
            $locale,
0 ignored issues
show
Bug introduced by
It seems like $locale defined by parameter $locale on line 430 can also be of type boolean; however, Arcanedev\Localization\C...::getUrlFromRouteName() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
436 108
            $this->getDefaultLocale(),
437 54
            $transKey,
438 54
            $attributes,
439 108
            $this->isDefaultLocaleHiddenInUrl(),
440 54
            $showHiddenLocale
441
        );
442
443
        // This locale does not have any key for this route name
444 108
        if (empty($route)) return false;
445
446 108
        return rtrim($this->createUrlFromUri($route));
447
    }
448
449
    /**
450
     * Set route name from request.
451
     *
452
     * @param  \Illuminate\Http\Request  $request
453
     */
454 2
    public function setRouteNameFromRequest(Request $request)
455
    {
456 2
        $routeName = $this->routeTranslator->getRouteNameFromPath(
457 2
            $request->getUri(), $this->getCurrentLocale()
458
        );
459
460 2
        $this->routeTranslator->setCurrentRoute($routeName);
461 2
    }
462
463
    /* -----------------------------------------------------------------
464
     |  Check Methods
465
     | -----------------------------------------------------------------
466
     */
467
468
    /**
469
     * Hide the default locale in URL ??
470
     *
471
     * @return bool
472
     */
473 108
    public function isDefaultLocaleHiddenInUrl()
474
    {
475 108
        return $this->localesManager->isDefaultLocaleHiddenInUrl();
476
    }
477
478
    /**
479
     * Check if Locale exists on the supported locales collection.
480
     *
481
     * @param  string|bool  $locale
482
     *
483
     * @return bool
484
     */
485 112
    public function isLocaleSupported($locale)
486
    {
487 112
        return ! ($locale !== false && ! $this->localesManager->isSupportedLocale($locale));
0 ignored issues
show
Bug introduced by
It seems like $locale defined by parameter $locale on line 485 can also be of type boolean; however, Arcanedev\Localization\C...er::isSupportedLocale() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
488
    }
489
490
    /**
491
     * Check if the locale is supported or fail if not.
492
     *
493
     * @param  string  $locale
494
     *
495
     * @throws \Arcanedev\Localization\Exceptions\UnsupportedLocaleException
496
     */
497 112
    private function isLocaleSupportedOrFail($locale)
498
    {
499 112
        if ( ! $this->isLocaleSupported($locale))
500 2
            throw new UnsupportedLocaleException(
501 2
                "Locale '{$locale}' is not in the list of supported locales."
502
            );
503 110
    }
504
}
505