Completed
Pull Request — master (#145)
by ARCANEDEV
06:11 queued 01:37
created

Localization::request()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 2
cts 2
cp 1
crap 1
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 268
    public function __construct(
66
        ApplicationContract     $app,
67
        RouteTranslatorContract $routeTranslator,
68
        LocalesManagerContract  $localesManager
69
    ) {
70 268
        $this->app             = $app;
71 268
        $this->routeTranslator = $routeTranslator;
72 268
        $this->localesManager  = $localesManager;
73
74 268
        $this->localesManager->setDefaultLocale(
75 268
            $this->app['config']->get('app.locale')
76
        );
77 268
    }
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 112
    public function getDefaultLocale()
100
    {
101 112
        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 268
    public function setLocale($locale = null)
226
    {
227 268
        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 268
    public function setBaseUrl($url)
238
    {
239 268
        if (substr($url, -1) !== '/') $url .= '/';
240
241 268
        $this->baseUrl = $url;
242
243 268
        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 268
    public function transRoute($routeName)
259
    {
260 268
        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
     * @param  string|null  $locale
292
     * @param  string|null  $url
293
     * @param  array        $attributes
294
     * @param  bool|false   $showHiddenLocale
295
     *
296
     * @return string|false
297
     */
298 106
    public function getLocalizedURL($locale = null, $url = null, array $attributes = [], $showHiddenLocale = false)
299
    {
300 106
        if (is_null($locale))
301 10
            $locale = $this->getCurrentLocale();
302
303 106
        $this->isLocaleSupportedOrFail($locale);
304
305 106
        if (empty($attributes))
306 106
            $attributes = Url::extractAttributes($url);
307
308 106
        if (empty($url)) {
309 10
            if ($this->routeTranslator->hasCurrentRoute()) {
310 2
                if (empty($attributes))
311 2
                    $attributes = $this->request()->route()->parameters();
312
313 2
                return $this->getUrlFromRouteName(
314 2
                    $locale,
315 2
                    $this->routeTranslator->getCurrentRoute(),
316 1
                    $attributes,
317 1
                    $showHiddenLocale
318
                );
319
            }
320
321 10
            $url = $this->request()->fullUrl();
322
        }
323
324
        if (
325 106
            $locale &&
326 106
            $translatedRoute = $this->findTranslatedRouteByUrl($url, $attributes, $this->getCurrentLocale())
327
        ) {
328 52
            return $this->getUrlFromRouteName($locale, $translatedRoute, $attributes, $showHiddenLocale);
329
        }
330
331 106
        $baseUrl    = $this->request()->getBaseUrl();
332 106
        $parsedUrl  = parse_url($url);
333
334 106
        $translatedRoute = $this->routeTranslator->getTranslatedRoute(
335 106
            $baseUrl, $parsedUrl, $this->getDefaultLocale(), $this->getSupportedLocales()
336
        );
337
338 106
        if ($translatedRoute !== false)
339 104
            return $this->getUrlFromRouteName($locale, $translatedRoute, $attributes, $showHiddenLocale);
340
341 90
        if ( ! empty($locale)) {
342 56
            if ($locale !== $this->getDefaultLocale() || ! $this->isDefaultLocaleHiddenInUrl() || $showHiddenLocale) {
343 52
                $parsedUrl['path'] = $locale.'/'.ltrim($parsedUrl['path'], '/');
344
            }
345
        }
346
347 90
        $parsedUrl['path'] = ltrim(ltrim($baseUrl, '/') . '/' . $parsedUrl['path'], '/');
348 90
        $parsedUrl['path'] = rtrim($parsedUrl['path'], '/');
349
350 90
        $url = Url::unparse($parsedUrl);
351
352 90
        if (filter_var($url, FILTER_VALIDATE_URL)) return $url;
353
354 2
        return $this->createUrlFromUri(
355 2
            empty($url) ? $parsedUrl['path'] : $url
356
        );
357
    }
358
359
    /**
360
     * Create an url from the uri.
361
     *
362
     * @param  string  $uri
363
     *
364
     * @return string
365
     */
366 110
    public function createUrlFromUri($uri)
367
    {
368 110
        $uri = ltrim($uri, '/');
369
370 110
        return empty($this->baseUrl)
371
            ? $this->app[\Illuminate\Contracts\Routing\UrlGenerator::class]->to($uri)
372 110
            : $this->baseUrl.$uri;
373
    }
374
375
    /**
376
     * Get locales navigation bar.
377
     *
378
     * @return string
379
     */
380 2
    public function localesNavbar()
381
    {
382
        /** @var  \Illuminate\Contracts\View\Factory  $view */
383 2
        $view = $this->app[ViewFactoryContract::class];
384
385 2
        return $view->make('localization::navbar', ['supportedLocales' => $this->getSupportedLocales()])
386 2
                    ->render();
387
    }
388
389
    /* -----------------------------------------------------------------
390
     |  Translation Methods
391
     | -----------------------------------------------------------------
392
     */
393
394
    /**
395
     * Returns the translated route for an url and the attributes given and a locale
396
     *
397
     * @param  string  $url
398
     * @param  array   $attributes
399
     * @param  string  $locale
400
     *
401
     * @return string|false
402
     */
403 104
    private function findTranslatedRouteByUrl($url, $attributes, $locale)
404
    {
405 104
        if (empty($url))
406
            return false;
407
408
        // check if this url is a translated url
409 104
        foreach ($this->routeTranslator->getTranslatedRoutes() as $translatedRoute) {
410 104
            $translatedUrl = $this->getUrlFromRouteName($locale, $translatedRoute, $attributes);
411
412 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 410 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...
413 52
                return $translatedRoute;
414
        }
415
416 56
        return false;
417
    }
418
419
    /**
420
     * Returns an URL adapted to the route name and the locale given.
421
     *
422
     * @param  string|bool  $locale
423
     * @param  string       $transKey
424
     * @param  array        $attributes
425
     * @param  bool|false   $showHiddenLocale
426
     *
427
     * @return string|false
428
     */
429 110
    public function getUrlFromRouteName($locale, $transKey, array $attributes = [], $showHiddenLocale = false)
430
    {
431 110
        $this->isLocaleSupportedOrFail($locale);
0 ignored issues
show
Bug introduced by
It seems like $locale defined by parameter $locale on line 429 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...
432
433 108
        $route = $this->routeTranslator->getUrlFromRouteName(
434 108
            $locale,
0 ignored issues
show
Bug introduced by
It seems like $locale defined by parameter $locale on line 429 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...
435 108
            $this->getDefaultLocale(),
436 54
            $transKey,
437 54
            $attributes,
438 108
            $this->isDefaultLocaleHiddenInUrl(),
439 54
            $showHiddenLocale
440
        );
441
442
        // This locale does not have any key for this route name
443 108
        if (empty($route)) return false;
444
445 108
        return rtrim($this->createUrlFromUri($route));
446
    }
447
448
    /**
449
     * Set route name from request.
450
     *
451
     * @param  \Illuminate\Http\Request  $request
452
     */
453 2
    public function setRouteNameFromRequest(Request $request)
454
    {
455 2
        $routeName = $this->routeTranslator->getRouteNameFromPath(
456 2
            $request->getUri(), $this->getCurrentLocale()
457
        );
458
459 2
        $this->routeTranslator->setCurrentRoute($routeName);
460 2
    }
461
462
    /* -----------------------------------------------------------------
463
     |  Check Methods
464
     | -----------------------------------------------------------------
465
     */
466
467
    /**
468
     * Hide the default locale in URL ??
469
     *
470
     * @return bool
471
     */
472 108
    public function isDefaultLocaleHiddenInUrl()
473
    {
474 108
        return $this->localesManager->isDefaultLocaleHiddenInUrl();
475
    }
476
477
    /**
478
     * Check if Locale exists on the supported locales collection.
479
     *
480
     * @param  string|bool  $locale
481
     *
482
     * @return bool
483
     */
484 112
    public function isLocaleSupported($locale)
485
    {
486 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 484 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...
487
    }
488
489
    /**
490
     * Check if the locale is supported or fail if not.
491
     *
492
     * @param  string  $locale
493
     *
494
     * @throws \Arcanedev\Localization\Exceptions\UnsupportedLocaleException
495
     */
496 112
    private function isLocaleSupportedOrFail($locale): void
497
    {
498 112
        if ( ! $this->isLocaleSupported($locale))
499 2
            throw new UnsupportedLocaleException(
500 2
                "Locale '{$locale}' is not in the list of supported locales."
501
            );
502 110
    }
503
}
504