GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — master (#631)
by Dmitry
20:04
created

LaravelLocalization::getCurrentLocaleNative()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Mcamara\LaravelLocalization;
4
5
use Illuminate\Config\Repository;
6
use Illuminate\Contracts\Routing\UrlRoutable;
7
use Mcamara\LaravelLocalization\Exceptions\SupportedLocalesNotDefined;
8
use Mcamara\LaravelLocalization\Exceptions\UnsupportedLocaleException;
9
10
class LaravelLocalization
11
{
12
    /**
13
     * The env key that the forced locale for routing is stored in.
14
     */
15
    const ENV_ROUTE_KEY = 'ROUTING_LOCALE';
16
17
    /**
18
     * Config repository.
19
     *
20
     * @var \Illuminate\Config\Repository
21
     */
22
    protected $configRepository;
23
24
    /**
25
     * Illuminate view Factory.
26
     *
27
     * @var \Illuminate\View\Factory
28
     */
29
    protected $view;
30
31
    /**
32
     * Illuminate translator class.
33
     *
34
     * @var \Illuminate\Translation\Translator
35
     */
36
    protected $translator;
37
38
    /**
39
     * Illuminate router class.
40
     *
41
     * @var \Illuminate\Routing\Router
42
     */
43
    protected $router;
44
45
    /**
46
     * Illuminate request class.
47
     *
48
     * @var \Illuminate\Routing\Request
49
     */
50
    protected $request;
51
52
    /**
53
     * Illuminate url class.
54
     *
55
     * @var \Illuminate\Routing\UrlGenerator
56
     */
57
    protected $url;
58
59
    /**
60
     * Illuminate request class.
61
     *
62
     * @var Illuminate\Foundation\Application
63
     */
64
    protected $app;
65
66
    /**
67
     * Illuminate request class.
68
     *
69
     * @var string
70
     */
71
    protected $baseUrl;
72
73
    /**
74
     * Default locale.
75
     *
76
     * @var string
77
     */
78
    protected $defaultLocale;
79
80
    /**
81
     * Supported Locales.
82
     *
83
     * @var array
84
     */
85
    protected $supportedLocales;
86
87
    /**
88
     * Locales mapping.
89
     *
90
     * @var array
91
     */
92
    protected $localesMapping;
93
94
    /**
95
     * Current locale.
96
     *
97
     * @var string
98
     */
99
    protected $currentLocale = false;
100
101
    /**
102
     * An array that contains all routes that should be translated.
103
     *
104
     * @var array
105
     */
106
    protected $translatedRoutes = [];
107
108
    /**
109
     * Name of the translation key of the current route, it is used for url translations.
110
     *
111
     * @var string
112
     */
113
    protected $routeName;
114
115
    /**
116
     * An array that contains all translated routes by url
117
     *
118
     * @var array
119
     */
120
    protected $cachedTranslatedRoutesByUrl = [];
121
122
    /**
123
     * Creates new instance.
124
     *
125
     * @throws UnsupportedLocaleException
126
     */
127
    public function __construct()
128
    {
129
        $this->app = app();
130
131
        $this->configRepository = $this->app['config'];
132
        $this->view = $this->app['view'];
133
        $this->translator = $this->app['translator'];
134
        $this->router = $this->app['router'];
135
        $this->request = $this->app['request'];
136
        $this->url = $this->app['url'];
137
138
        // set default locale
139
        $this->defaultLocale = $this->configRepository->get('app.locale');
140
        $supportedLocales = $this->getSupportedLocales();
141
142
        if (empty($supportedLocales[$this->defaultLocale])) {
143
            throw new UnsupportedLocaleException('Laravel default locale is not in the supportedLocales array.');
144
        }
145
    }
146
147
    /**
148
     * Set and return current locale.
149
     *
150
     * @param string $locale Locale to set the App to (optional)
151
     *
152
     * @return string Returns locale (if route has any) or null (if route does not have a locale)
153
     */
154
    public function setLocale($locale = null)
155
    {
156
        if (empty($locale) || !\is_string($locale)) {
157
            // If the locale has not been passed through the function
158
            // it tries to get it from the first segment of the url
159
            $locale = $this->request->segment(1);
160
161
            // If the locale is determined by env, use that
162
            // Note that this is how per-locale route caching is performed.
163
            if ( ! $locale) {
164
                $locale = $this->getForcedLocale();
165
            }
166
        }
167
168
        $locale = $this->getInversedLocaleFromMapping($locale);
169
170
        if (!empty($this->supportedLocales[$locale])) {
171
            $this->currentLocale = $locale;
172
        } else {
173
            // if the first segment/locale passed is not valid
174
            // the system would ask which locale have to take
175
            // it could be taken by the browser
176
            // depending on your configuration
177
178
            $locale = null;
179
180
            // if we reached this point and hideDefaultLocaleInURL is true
181
            // we have to assume we are routing to a defaultLocale route.
182
            if ($this->hideDefaultLocaleInURL()) {
183
                $this->currentLocale = $this->defaultLocale;
184
            }
185
            // but if hideDefaultLocaleInURL is false, we have
186
            // to retrieve it from the browser...
187
            else {
188
                $this->currentLocale = $this->getCurrentLocale();
189
            }
190
        }
191
192
        $this->app->setLocale($this->currentLocale);
193
194
        // Regional locale such as de_DE, so formatLocalized works in Carbon
195
        $regional = $this->getCurrentLocaleRegional();
196
        $suffix = $this->configRepository->get('laravellocalization.utf8suffix');
197
        if ($regional) {
198
            setlocale(LC_TIME, $regional . $suffix);
199
            setlocale(LC_MONETARY, $regional . $suffix);
200
        }
201
202
        return $this->getLocaleFromMapping($locale);
203
    }
204
205
    /**
206
     * Check if $locale is default locale and supposed to be hidden in url
207
     *
208
     * @param string $locale Locale to be checked
209
     *
210
     * @return boolean Returns true if above requirement are met, otherwise false
211
     */
212
213
     public function isHiddenDefault($locale)
214
     {
215
       return  ($this->getDefaultLocale() === $locale && $this->hideDefaultLocaleInURL());
216
     }
217
218
    /**
219
     * Set and return supported locales.
220
     *
221
     * @param array $locales Locales that the App supports
222
     */
223
    public function setSupportedLocales($locales)
224
    {
225
        $this->supportedLocales = $locales;
226
    }
227
228
    /**
229
     * Returns an URL adapted to $locale or current locale.
230
     *
231
     * @param string      $url    URL to adapt. If not passed, the current url would be taken.
232
     * @param string|bool $locale Locale to adapt, false to remove locale
233
     *
234
     * @throws UnsupportedLocaleException
235
     *
236
     * @return string URL translated
237
     */
238
    public function localizeURL($url = null, $locale = null)
239
    {
240
        return $this->getLocalizedURL($locale, $url);
241
    }
242
243
    /**
244
     * Returns an URL adapted to $locale.
245
     *
246
     *
247
     * @param string|bool  $locale     Locale to adapt, false to remove locale
248
     * @param string|false $url        URL to adapt in the current language. If not passed, the current url would be taken.
249
     * @param array        $attributes Attributes to add to the route, if empty, the system would try to extract them from the url.
250
     * @param bool         $forceDefaultLocation Force to show default location even hideDefaultLocaleInURL set as TRUE
251
     *
252
     * @throws SupportedLocalesNotDefined
253
     * @throws UnsupportedLocaleException
254
     *
255
     * @return string|false URL translated, False if url does not exist
256
     */
257
    public function getLocalizedURL($locale = null, $url = null, $attributes = [], $forceDefaultLocation = false)
258
    {
259
        if ($locale === null) {
260
            $locale = $this->getCurrentLocale();
261
        }
262
263
        if (!$this->checkLocaleInSupportedLocales($locale)) {
264
            throw new UnsupportedLocaleException('Locale \''.$locale.'\' is not in the list of supported locales.');
265
        }
266
267
        if (empty($attributes)) {
268
            $attributes = $this->extractAttributes($url, $locale);
0 ignored issues
show
Bug introduced by
It seems like $locale defined by parameter $locale on line 257 can also be of type boolean; however, Mcamara\LaravelLocalizat...on::extractAttributes() 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...
269
        }
270
        $urlQuery = parse_url($url, PHP_URL_QUERY);
271
        $urlQuery = $urlQuery ? '?'.$urlQuery : '';
272
273
        if (empty($url)) {
274
            if (!empty($this->routeName)) {
275
                return $this->getURLFromRouteNameTranslated($locale, $this->routeName, $attributes, $forceDefaultLocation);
276
            }
277
278
            $url = $this->request->fullUrl();
279
        } else {
280
            $url = $this->url->to($url);
281
            $url = preg_replace('/'. preg_quote($urlQuery, '/') . '$/', '', $url);
282
        }
283
284
        if ($locale && $translatedRoute = $this->findTranslatedRouteByUrl($url, $attributes, $this->currentLocale)) {
285
            return $this->getURLFromRouteNameTranslated($locale, $translatedRoute, $attributes, $forceDefaultLocation).$urlQuery;
286
        }
287
288
        $base_path = $this->request->getBaseUrl();
289
        $parsed_url = parse_url($url);
290
        $url_locale = $this->getDefaultLocale();
291
292
        if (!$parsed_url || empty($parsed_url['path'])) {
293
            $path = $parsed_url['path'] = '';
294
        } else {
295
            $parsed_url['path'] = str_replace($base_path, '', '/'.ltrim($parsed_url['path'], '/'));
296
            $path = $parsed_url['path'];
297
            foreach ($this->getSupportedLocales() as $localeCode => $lang) {
298
                $parsed_url['path'] = preg_replace('%^/?'.$localeCode.'/%', '$1', $parsed_url['path']);
299
                if ($parsed_url['path'] !== $path) {
300
                    $url_locale = $localeCode;
301
                    break;
302
                }
303
304
                $parsed_url['path'] = preg_replace('%^/?'.$localeCode.'$%', '$1', $parsed_url['path']);
305
                if ($parsed_url['path'] !== $path) {
306
                    $url_locale = $localeCode;
307
                    break;
308
                }
309
            }
310
        }
311
312
        $parsed_url['path'] = ltrim($parsed_url['path'], '/');
313
314
        if ($translatedRoute = $this->findTranslatedRouteByPath($parsed_url['path'], $url_locale)) {
315
            return $this->getURLFromRouteNameTranslated($locale, $translatedRoute, $attributes, $forceDefaultLocation).$urlQuery;
316
        }
317
318
        $locale = $this->getLocaleFromMapping($locale);
0 ignored issues
show
Bug introduced by
It seems like $locale can also be of type boolean; however, Mcamara\LaravelLocalizat...:getLocaleFromMapping() does only seem to accept string|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
319
320
        if (!empty($locale)) {
321
            if ($forceDefaultLocation || $locale != $this->getDefaultLocale() || !$this->hideDefaultLocaleInURL()) {
322
                $parsed_url['path'] = $locale.'/'.ltrim($parsed_url['path'], '/');
323
            }
324
        }
325
        $parsed_url['path'] = ltrim(ltrim($base_path, '/').'/'.$parsed_url['path'], '/');
326
327
        //Make sure that the pass path is returned with a leading slash only if it come in with one.
328
        if (starts_with($path, '/') === true) {
0 ignored issues
show
Deprecated Code introduced by
The function starts_with() has been deprecated with message: Str::startsWith() should be used directly instead. Will be removed in Laravel 5.9.

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
329
            $parsed_url['path'] = '/'.$parsed_url['path'];
330
        }
331
        $parsed_url['path'] = rtrim($parsed_url['path'], '/');
332
333
        $url = $this->unparseUrl($parsed_url);
334
335
        if ($this->checkUrl($url)) {
336
            return $url.$urlQuery;
337
        }
338
339
        return $this->createUrlFromUri($url).$urlQuery;
340
    }
341
342
    /**
343
     * Returns an URL adapted to the route name and the locale given.
344
     *
345
     *
346
     * @param string|bool $locale       Locale to adapt
347
     * @param string      $transKeyName Translation key name of the url to adapt
348
     * @param array       $attributes   Attributes for the route (only needed if transKeyName needs them)
349
     * @param bool        $forceDefaultLocation Force to show default location even hideDefaultLocaleInURL set as TRUE
350
     *
351
     * @throws SupportedLocalesNotDefined
352
     * @throws UnsupportedLocaleException
353
     *
354
     * @return string|false URL translated
355
     */
356
    public function getURLFromRouteNameTranslated($locale, $transKeyName, $attributes = [], $forceDefaultLocation = false)
357
    {
358
        if (!$this->checkLocaleInSupportedLocales($locale)) {
359
            throw new UnsupportedLocaleException('Locale \''.$locale.'\' is not in the list of supported locales.');
360
        }
361
362
        if (!\is_string($locale)) {
363
            $locale = $this->getDefaultLocale();
364
        }
365
366
        $route = '';
367
368
        if ($forceDefaultLocation || !($locale === $this->defaultLocale && $this->hideDefaultLocaleInURL())) {
369
            $route = '/'.$locale;
370
        }
371
        if (\is_string($locale) && $this->translator->has($transKeyName, $locale)) {
372
            $translation = $this->translator->trans($transKeyName, [], $locale);
373
            $route .= '/'.$translation;
374
375
            $route = $this->substituteAttributesInRoute($attributes, $route);
376
        }
377
378
        if (empty($route)) {
379
            // This locale does not have any key for this route name
380
            return false;
381
        }
382
383
        return rtrim($this->createUrlFromUri($route), '/');
384
    }
385
386
    /**
387
     * It returns an URL without locale (if it has it)
388
     * Convenience function wrapping getLocalizedURL(false).
389
     *
390
     * @param string|false $url URL to clean, if false, current url would be taken
391
     *
392
     * @return string URL with no locale in path
393
     */
394
    public function getNonLocalizedURL($url = null)
395
    {
396
        return $this->getLocalizedURL(false, $url);
397
    }
398
399
    /**
400
     * Returns default locale.
401
     *
402
     * @return string
403
     */
404
    public function getDefaultLocale()
405
    {
406
        return $this->defaultLocale;
407
    }
408
409
    /**
410
     * Return locales mapping.
411
     *
412
     * @return array
413
     */
414
    public function getLocalesMapping()
415
    {
416
        if (empty($this->localesMapping)) {
417
            $this->localesMapping = $this->configRepository->get('laravellocalization.localesMapping');
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->configRepository-...zation.localesMapping') of type * is incompatible with the declared type array of property $localesMapping.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
418
        }
419
420
        return $this->localesMapping;
421
    }
422
423
    /**
424
     * Returns a locale from the mapping.
425
     *
426
     * @param string|null $locale
427
     *
428
     * @return string|null
429
     */
430
    public function getLocaleFromMapping($locale)
431
    {
432
        return $this->getLocalesMapping()[$locale] ?? $locale;
433
    }
434
435
    /**
436
     * Returns inversed locale from the mapping.
437
     *
438
     * @param string|null $locale
439
     *
440
     * @return string|null
441
     */
442
    public function getInversedLocaleFromMapping($locale)
443
    {
444
        return \array_flip($this->getLocalesMapping())[$locale] ?? $locale;
445
    }
446
447
    /**
448
     * Return an array of all supported Locales.
449
     *
450
     * @throws SupportedLocalesNotDefined
451
     *
452
     * @return array
453
     */
454
    public function getSupportedLocales()
455
    {
456
        if (!empty($this->supportedLocales)) {
457
            return $this->supportedLocales;
458
        }
459
460
        $locales = $this->configRepository->get('laravellocalization.supportedLocales');
461
462
        if (empty($locales) || !\is_array($locales)) {
463
            throw new SupportedLocalesNotDefined();
464
        }
465
466
        $this->supportedLocales = $locales;
467
468
        return $locales;
469
    }
470
471
    /**
472
     * Return an array of all supported Locales but in the order the user
473
     * has specified in the config file. Useful for the language selector.
474
     *
475
     * @return array
476
     */
477
    public function getLocalesOrder()
478
    {
479
        $locales = $this->getSupportedLocales();
480
481
        $order = $this->configRepository->get('laravellocalization.localesOrder');
482
483
        uksort($locales, function ($a, $b) use ($order) {
484
            $pos_a = array_search($a, $order);
485
            $pos_b = array_search($b, $order);
486
            return $pos_a - $pos_b;
487
        });
488
489
        return $locales;
490
    }
491
492
    /**
493
     * Returns current locale name.
494
     *
495
     * @return string current locale name
496
     */
497
    public function getCurrentLocaleName()
498
    {
499
        return $this->supportedLocales[$this->getCurrentLocale()]['name'];
500
    }
501
502
    /**
503
     * Returns current locale native name.
504
     *
505
     * @return string current locale native name
506
     */
507
    public function getCurrentLocaleNative()
508
    {
509
        return $this->supportedLocales[$this->getCurrentLocale()]['native'];
510
    }
511
512
    /**
513
     * Returns current locale direction.
514
     *
515
     * @return string current locale direction
516
     */
517
    public function getCurrentLocaleDirection()
518
    {
519
        if (!empty($this->supportedLocales[$this->getCurrentLocale()]['dir'])) {
520
            return $this->supportedLocales[$this->getCurrentLocale()]['dir'];
521
        }
522
523
        switch ($this->getCurrentLocaleScript()) {
524
            // Other (historic) RTL scripts exist, but this list contains the only ones in current use.
525
            case 'Arab':
526
            case 'Hebr':
527
            case 'Mong':
528
            case 'Tfng':
529
            case 'Thaa':
530
            return 'rtl';
531
            default:
532
            return 'ltr';
533
        }
534
    }
535
536
    /**
537
     * Returns current locale script.
538
     *
539
     * @return string current locale script
540
     */
541
    public function getCurrentLocaleScript()
542
    {
543
        return $this->supportedLocales[$this->getCurrentLocale()]['script'];
544
    }
545
546
    /**
547
     * Returns current language's native reading.
548
     *
549
     * @return string current language's native reading
550
     */
551
    public function getCurrentLocaleNativeReading()
552
    {
553
        return $this->supportedLocales[$this->getCurrentLocale()]['native'];
554
    }
555
556
    /**
557
     * Returns current language.
558
     *
559
     * @return string current language
560
     */
561
    public function getCurrentLocale()
562
    {
563
        if ($this->currentLocale) {
564
            return $this->currentLocale;
565
        }
566
567
        if ($this->useAcceptLanguageHeader() && !$this->app->runningInConsole()) {
568
            $negotiator = new LanguageNegotiator($this->defaultLocale, $this->getSupportedLocales(), $this->request);
569
570
            return $negotiator->negotiateLanguage();
571
        }
572
573
        // or get application default language
574
        return $this->configRepository->get('app.locale');
575
    }
576
577
    /**
578
     * Returns current regional.
579
     *
580
     * @return string current regional
581
     */
582
    public function getCurrentLocaleRegional()
583
    {
584
        // need to check if it exists, since 'regional' has been added
585
        // after version 1.0.11 and existing users will not have it
586
        if (isset($this->supportedLocales[$this->getCurrentLocale()]['regional'])) {
587
            return $this->supportedLocales[$this->getCurrentLocale()]['regional'];
588
        } else {
589
            return;
590
        }
591
    }
592
593
    /**
594
     * Returns supported languages language key.
595
     *
596
     * @return array keys of supported languages
597
     */
598
    public function getSupportedLanguagesKeys()
599
    {
600
        return array_keys($this->supportedLocales);
601
    }
602
603
    /**
604
     * Check if Locale exists on the supported locales array.
605
     *
606
     * @param string|bool $locale string|bool Locale to be checked
607
     *
608
     * @throws SupportedLocalesNotDefined
609
     *
610
     * @return bool is the locale supported?
611
     */
612
    public function checkLocaleInSupportedLocales($locale)
613
    {
614
        $inversedLocale = $this->getInversedLocaleFromMapping($locale);
0 ignored issues
show
Bug introduced by
It seems like $locale defined by parameter $locale on line 612 can also be of type boolean; however, Mcamara\LaravelLocalizat...rsedLocaleFromMapping() does only seem to accept string|null, 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...
615
        $locales = $this->getSupportedLocales();
616
        if ($locale !== false && empty($locales[$locale]) && empty($locales[$inversedLocale])) {
617
            return false;
618
        }
619
620
        return true;
621
    }
622
623
    /**
624
     * Change route attributes for the ones in the $attributes array.
625
     *
626
     * @param $attributes array Array of attributes
627
     * @param string $route string route to substitute
628
     *
629
     * @return string route with attributes changed
630
     */
631
    protected function substituteAttributesInRoute($attributes, $route)
632
    {
633
        foreach ($attributes as $key => $value) {
634
            if ($value instanceOf UrlRoutable) {
635
                $value = $value->getRouteKey();
636
            }
637
            $route = str_replace(array('{'.$key.'}', '{'.$key.'?}'), $value, $route);
638
        }
639
640
        // delete empty optional arguments that are not in the $attributes array
641
        $route = preg_replace('/\/{[^)]+\?}/', '', $route);
642
643
        return $route;
644
    }
645
646
    /**
647
     * Returns translated routes.
648
     *
649
     * @return array translated routes
650
     */
651
    protected function getTranslatedRoutes()
652
    {
653
        return $this->translatedRoutes;
654
    }
655
656
    /**
657
     * Set current route name.
658
     *
659
     * @param string $routeName current route name
660
     */
661
    public function setRouteName($routeName)
662
    {
663
        $this->routeName = $routeName;
664
    }
665
666
    /**
667
     * Translate routes and save them to the translated routes array (used in the localize route filter).
668
     *
669
     * @param string $routeName Key of the translated string
670
     *
671
     * @return string Translated string
672
     */
673
    public function transRoute($routeName)
674
    {
675
        if (!\in_array($routeName, $this->translatedRoutes)) {
676
            $this->translatedRoutes[] = $routeName;
677
        }
678
679
        return $this->translator->trans($routeName);
680
    }
681
682
    /**
683
     * Returns the translation key for a given path.
684
     *
685
     * @param string $path Path to get the key translated
686
     *
687
     * @return string|false Key for translation, false if not exist
688
     */
689
    public function getRouteNameFromAPath($path)
690
    {
691
        $attributes = $this->extractAttributes($path);
692
693
        $path = parse_url($path)['path'];
694
        $path = trim(str_replace('/'.$this->currentLocale.'/', '', $path), "/");
695
696
        foreach ($this->translatedRoutes as $route) {
697
            if (trim($this->substituteAttributesInRoute($attributes, $this->translator->trans($route)), '/') === $path) {
0 ignored issues
show
Bug introduced by
It seems like $this->translator->trans($route) targeting Illuminate\Translation\Translator::trans() can also be of type array; however, Mcamara\LaravelLocalizat...tuteAttributesInRoute() does only seem to accept string, maybe add an additional type check?

This check looks at variables that 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...
698
                return $route;
699
            }
700
        }
701
702
        return false;
703
    }
704
705
    /**
706
     * Returns the translated route for the path and the url given.
707
     *
708
     * @param string $path       Path to check if it is a translated route
709
     * @param string $url_locale Language to check if the path exists
710
     *
711
     * @return string|false Key for translation, false if not exist
712
     */
713
    protected function findTranslatedRouteByPath($path, $url_locale)
714
    {
715
        // check if this url is a translated url
716
        foreach ($this->translatedRoutes as $translatedRoute) {
717
            if ($this->translator->trans($translatedRoute, [], $url_locale) == rawurldecode($path)) {
718
                return $translatedRoute;
719
            }
720
        }
721
722
        return false;
723
    }
724
725
    /**
726
     * Returns the translated route for an url and the attributes given and a locale.
727
     *
728
     *
729
     * @param string|false|null $url        Url to check if it is a translated route
730
     * @param array             $attributes Attributes to check if the url exists in the translated routes array
731
     * @param string            $locale     Language to check if the url exists
732
     *
733
     * @throws SupportedLocalesNotDefined
734
     * @throws UnsupportedLocaleException
735
     *
736
     * @return string|false Key for translation, false if not exist
737
     */
738
    protected function findTranslatedRouteByUrl($url, $attributes, $locale)
739
    {
740
        if (empty($url)) {
741
            return false;
742
        }
743
744
        if (isset($this->cachedTranslatedRoutesByUrl[$locale][$url])) {
745
            return $this->cachedTranslatedRoutesByUrl[$locale][$url];
746
        }
747
748
        // check if this url is a translated url
749
        foreach ($this->translatedRoutes as $translatedRoute) {
750
            $routeName = $this->getURLFromRouteNameTranslated($locale, $translatedRoute, $attributes);
751
752
            // We can ignore extra url parts and compare only their url_path (ignore arguments that are not attributes)
753
            if (parse_url($this->getNonLocalizedURL($routeName), PHP_URL_PATH) == parse_url($this->getNonLocalizedURL($url), PHP_URL_PATH)) {
754
                $this->cachedTranslatedRoutesByUrl[$locale][$url] = $translatedRoute;
755
756
                return $translatedRoute;
757
            }
758
        }
759
760
        return false;
761
    }
762
763
    /**
764
     * Returns true if the string given is a valid url.
765
     *
766
     * @param string $url String to check if it is a valid url
767
     *
768
     * @return bool Is the string given a valid url?
769
     */
770
    protected function checkUrl($url)
771
    {
772
        return filter_var($url, FILTER_VALIDATE_URL);
773
    }
774
775
    /**
776
     * Returns the config repository for this instance.
777
     *
778
     * @return Repository Configuration repository
779
     */
780
    public function getConfigRepository()
781
    {
782
        return $this->configRepository;
783
    }
784
785
    /**
786
     * Returns the translation key for a given path.
787
     *
788
     * @return bool Returns value of useAcceptLanguageHeader in config.
789
     */
790
    protected function useAcceptLanguageHeader()
791
    {
792
        return $this->configRepository->get('laravellocalization.useAcceptLanguageHeader');
793
    }
794
795
    public function hideUrlAndAcceptHeader()
796
    {
797
      return $this->hideDefaultLocaleInURL() && $this->useAcceptLanguageHeader();
798
    }
799
800
    /**
801
     * Returns the translation key for a given path.
802
     *
803
     * @return bool Returns value of hideDefaultLocaleInURL in config.
804
     */
805
    public function hideDefaultLocaleInURL()
806
    {
807
        return $this->configRepository->get('laravellocalization.hideDefaultLocaleInURL');
808
    }
809
810
    /**
811
     * Create an url from the uri.
812
     *
813
     * @param string $uri Uri
814
     *
815
     * @return string Url for the given uri
816
     */
817
    public function createUrlFromUri($uri)
818
    {
819
        $uri = ltrim($uri, '/');
820
821
        if (empty($this->baseUrl)) {
822
            return app('url')->to($uri);
823
        }
824
825
        return $this->baseUrl.$uri;
826
    }
827
828
    /**
829
     * Sets the base url for the site.
830
     *
831
     * @param string $url Base url for the site
832
     */
833
    public function setBaseUrl($url)
834
    {
835
        if (substr($url, -1) != '/') {
836
            $url .= '/';
837
        }
838
839
        $this->baseUrl = $url;
840
    }
841
842
    /**
843
     * Returns serialized translated routes for caching purposes.
844
     *
845
     * @return string
846
     */
847
    public function getSerializedTranslatedRoutes()
848
    {
849
        return base64_encode(serialize($this->translatedRoutes));
850
    }
851
852
    /**
853
     * Sets the translated routes list.
854
     * Only useful from a cached routes context.
855
     *
856
     * @param string $serializedRoutes
857
     */
858
    public function setSerializedTranslatedRoutes($serializedRoutes)
859
    {
860
        if ( ! $serializedRoutes) {
861
            return;
862
        }
863
864
        $this->translatedRoutes = unserialize(base64_decode($serializedRoutes));
865
    }
866
867
    /**
868
     * Extract attributes for current url.
869
     *
870
     * @param bool|false|null|string $url    to extract attributes, if not present, the system will look for attributes in the current call
871
     * @param string                 $locale
872
     *
873
     * @return array Array with attributes
874
     */
875
    protected function extractAttributes($url = false, $locale = '')
876
    {
877
        if (!empty($url)) {
878
            $attributes = [];
879
            $parse = parse_url($url);
880
            if (isset($parse['path'])) {
881
                $parse['path'] = trim(str_replace('/'.$this->currentLocale.'/', '', $parse['path']), "/");
882
                $url = explode('/', trim($parse['path'], '/'));
883
            } else {
884
                $url = [];
885
            }
886
887
            foreach ($this->router->getRoutes() as $route) {
888
                $attributes = [];
889
                $path = method_exists($route, 'uri') ? $route->uri() : $route->getUri();
890
891
                if (!preg_match("/{[\w]+\??}/", $path)) {
892
                    continue;
893
                }
894
895
                $path = explode('/', $path);
896
                $i = 0;
897
898
                // The system's route can't be smaller
899
                // only the $url can be missing segments (optional parameters)
900
                // We can assume it's the wrong route
901
                if (count($path) < count($url)) {
902
                    continue;
903
                }
904
905
                $match = true;
906
                foreach ($path as $j => $segment) {
907
                    if (isset($url[$i])) {
908
                        if ($segment === $url[$i]) {
909
                            $i++;
910
                            continue;
911 View Code Duplication
                        } elseif (preg_match("/{[\w]+}/", $segment)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
912
                            // must-have parameters
913
                            $attribute_name = preg_replace(['/}/', '/{/', "/\?/"], '', $segment);
914
                            $attributes[$attribute_name] = $url[$i];
915
                            $i++;
916
                            continue;
917
                        } elseif (preg_match("/{[\w]+\?}/", $segment)) {
918
                            // optional parameters
919
                            if (!isset($path[$j + 1]) || $path[$j + 1] !== $url[$i]) {
920
                                // optional parameter taken
921
                                $attribute_name = preg_replace(['/}/', '/{/', "/\?/"], '', $segment);
922
                                $attributes[$attribute_name] = $url[$i];
923
                                $i++;
924
                                continue;
925
                            } else {
926
                                $match = false;
927
                                break;
928
                            }
929
                        } else {
930
                            // As soon as one segment doesn't match, then we have the wrong route
931
                            $match = false;
932
                            break;
933
                        }
934 View Code Duplication
                    } elseif (preg_match("/{[\w]+\?}/", $segment)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
935
                        $attribute_name = preg_replace(['/}/', '/{/', "/\?/"], '', $segment);
936
                        $attributes[$attribute_name] = null;
937
                        $i++;
938
                    } else {
939
                        // no optional parameters but no more $url given
940
                        // this route does not match the url
941
                        $match = false;
942
                        break;
943
                    }
944
                }
945
946
                if (isset($url[$i + 1])) {
947
                    $match = false;
948
                }
949
950
                if ($match) {
951
                    return $attributes;
952
                }
953
            }
954
        } else {
955
            if (!$this->router->current()) {
956
                return [];
957
            }
958
959
            $attributes = $this->normalizeAttributes($this->router->current()->parameters());
960
            $response = event('routes.translation', [$locale, $attributes]);
961
962
            if (!empty($response)) {
963
                $response = array_shift($response);
964
            }
965
966
            if (\is_array($response)) {
967
                $attributes = array_merge($attributes, $response);
968
            }
969
        }
970
971
        return $attributes;
972
    }
973
974
    /**
975
     * Build URL using array data from parse_url.
976
     *
977
     * @param array|false $parsed_url Array of data from parse_url function
978
     *
979
     * @return string Returns URL as string.
980
     */
981
    protected function unparseUrl($parsed_url)
982
    {
983
        if (empty($parsed_url)) {
984
            return '';
985
        }
986
987
        $url = '';
988
        $url .= isset($parsed_url['scheme']) ? $parsed_url['scheme'].'://' : '';
989
        $url .= $parsed_url['host'] ?? '';
990
        $url .= isset($parsed_url['port']) ? ':'.$parsed_url['port'] : '';
991
        $user = $parsed_url['user'] ?? '';
992
        $pass = isset($parsed_url['pass']) ? ':'.$parsed_url['pass'] : '';
993
        $url .= $user.(($user || $pass) ? "$pass@" : '');
994
995
        if (!empty($url)) {
996
            $url .= isset($parsed_url['path']) ? '/'.ltrim($parsed_url['path'], '/') : '';
997
        } else {
998
            $url .= $parsed_url['path'] ?? '';
999
        }
1000
1001
        $url .= isset($parsed_url['query']) ? '?'.$parsed_url['query'] : '';
1002
        $url .= isset($parsed_url['fragment']) ? '#'.$parsed_url['fragment'] : '';
1003
1004
        return $url;
1005
    }
1006
1007
    /**
1008
    * Normalize attributes gotten from request parameters.
1009
    *
1010
    * @param      array  $attributes  The attributes
1011
    * @return     array  The normalized attributes
1012
    */
1013
     protected function normalizeAttributes($attributes)
1014
     {
1015
         if (array_key_exists('data', $attributes) && \is_array($attributes['data']) && ! \count($attributes['data'])) {
1016
             $attributes['data'] = null;
1017
             return $attributes;
1018
         }
1019
         return $attributes;
1020
     }
1021
1022
    /**
1023
     * Returns the forced environment set route locale.
1024
     *
1025
     * @return string|null
1026
     */
1027
    protected function getForcedLocale()
1028
    {
1029
        return env(static::ENV_ROUTE_KEY, function () {
1030
            $value = getenv(static::ENV_ROUTE_KEY);
1031
1032
            if ($value !== false) {
1033
                return $value;
1034
            }
1035
        });
1036
    }
1037
}
1038