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
02:52
created

LaravelLocalization::getNonLocalizedURL()   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 1
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
                $localeCode = $this->getLocaleFromMapping($localeCode);
299
300
                $parsed_url['path'] = preg_replace('%^/?'.$localeCode.'/%', '$1', $parsed_url['path']);
301
                if ($parsed_url['path'] !== $path) {
302
                    $url_locale = $localeCode;
303
                    break;
304
                }
305
306
                $parsed_url['path'] = preg_replace('%^/?'.$localeCode.'$%', '$1', $parsed_url['path']);
307
                if ($parsed_url['path'] !== $path) {
308
                    $url_locale = $localeCode;
309
                    break;
310
                }
311
            }
312
        }
313
314
        $parsed_url['path'] = ltrim($parsed_url['path'], '/');
315
316
        if ($translatedRoute = $this->findTranslatedRouteByPath($parsed_url['path'], $url_locale)) {
317
            return $this->getURLFromRouteNameTranslated($locale, $translatedRoute, $attributes, $forceDefaultLocation).$urlQuery;
318
        }
319
320
        $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...
321
322
        if (!empty($locale)) {
323
            if ($forceDefaultLocation || $locale != $this->getDefaultLocale() || !$this->hideDefaultLocaleInURL()) {
324
                $parsed_url['path'] = $locale.'/'.ltrim($parsed_url['path'], '/');
325
            }
326
        }
327
        $parsed_url['path'] = ltrim(ltrim($base_path, '/').'/'.$parsed_url['path'], '/');
328
329
        //Make sure that the pass path is returned with a leading slash only if it come in with one.
330
        if (starts_with($path, '/') === true) {
331
            $parsed_url['path'] = '/'.$parsed_url['path'];
332
        }
333
        $parsed_url['path'] = rtrim($parsed_url['path'], '/');
334
335
        $url = $this->unparseUrl($parsed_url);
336
337
        if ($this->checkUrl($url)) {
338
            return $url.$urlQuery;
339
        }
340
341
        return $this->createUrlFromUri($url).$urlQuery;
342
    }
343
344
    /**
345
     * Returns an URL adapted to the route name and the locale given.
346
     *
347
     *
348
     * @param string|bool $locale       Locale to adapt
349
     * @param string      $transKeyName Translation key name of the url to adapt
350
     * @param array       $attributes   Attributes for the route (only needed if transKeyName needs them)
351
     * @param bool        $forceDefaultLocation Force to show default location even hideDefaultLocaleInURL set as TRUE
352
     *
353
     * @throws SupportedLocalesNotDefined
354
     * @throws UnsupportedLocaleException
355
     *
356
     * @return string|false URL translated
357
     */
358
    public function getURLFromRouteNameTranslated($locale, $transKeyName, $attributes = [], $forceDefaultLocation = false)
359
    {
360
        if (!$this->checkLocaleInSupportedLocales($locale)) {
361
            throw new UnsupportedLocaleException('Locale \''.$locale.'\' is not in the list of supported locales.');
362
        }
363
364
        if (!\is_string($locale)) {
365
            $locale = $this->getDefaultLocale();
366
        }
367
368
        $route = '';
369
370
        if ($forceDefaultLocation || !($locale === $this->defaultLocale && $this->hideDefaultLocaleInURL())) {
371
            $route = '/'.$locale;
372
        }
373
        if (\is_string($locale) && $this->translator->has($transKeyName, $locale)) {
374
            $translation = $this->translator->trans($transKeyName, [], $locale);
375
            $route .= '/'.$translation;
376
377
            $route = $this->substituteAttributesInRoute($attributes, $route);
378
        }
379
380
        if (empty($route)) {
381
            // This locale does not have any key for this route name
382
            return false;
383
        }
384
385
        return rtrim($this->createUrlFromUri($route), '/');
386
    }
387
388
    /**
389
     * It returns an URL without locale (if it has it)
390
     * Convenience function wrapping getLocalizedURL(false).
391
     *
392
     * @param string|false $url URL to clean, if false, current url would be taken
393
     *
394
     * @return string URL with no locale in path
395
     */
396
    public function getNonLocalizedURL($url = null)
397
    {
398
        return $this->getLocalizedURL(false, $url);
399
    }
400
401
    /**
402
     * Returns default locale.
403
     *
404
     * @return string
405
     */
406
    public function getDefaultLocale()
407
    {
408
        return $this->defaultLocale;
409
    }
410
411
    /**
412
     * Return locales mapping.
413
     *
414
     * @return array
415
     */
416
    public function getLocalesMapping()
417
    {
418
        if (empty($this->localesMapping)) {
419
            $this->localesMapping = $this->configRepository->get('laravellocalization.localesMapping');
420
        }
421
422
        return $this->localesMapping;
423
    }
424
425
    /**
426
     * Returns a locale from the mapping.
427
     *
428
     * @param string|null $locale
429
     *
430
     * @return string|null
431
     */
432
    public function getLocaleFromMapping($locale)
433
    {
434
        return $this->getLocalesMapping()[$locale] ?? $locale;
435
    }
436
437
    /**
438
     * Returns inversed locale from the mapping.
439
     *
440
     * @param string|null $locale
441
     *
442
     * @return string|null
443
     */
444
    public function getInversedLocaleFromMapping($locale)
445
    {
446
        return \array_flip($this->getLocalesMapping())[$locale] ?? $locale;
447
    }
448
449
    /**
450
     * Return an array of all supported Locales.
451
     *
452
     * @throws SupportedLocalesNotDefined
453
     *
454
     * @return array
455
     */
456
    public function getSupportedLocales()
457
    {
458
        if (!empty($this->supportedLocales)) {
459
            return $this->supportedLocales;
460
        }
461
462
        $locales = $this->configRepository->get('laravellocalization.supportedLocales');
463
464
        if (empty($locales) || !\is_array($locales)) {
465
            throw new SupportedLocalesNotDefined();
466
        }
467
468
        $this->supportedLocales = $locales;
469
470
        return $locales;
471
    }
472
473
    /**
474
     * Return an array of all supported Locales but in the order the user
475
     * has specified in the config file. Useful for the language selector.
476
     *
477
     * @return array
478
     */
479
    public function getLocalesOrder()
480
    {
481
        $locales = $this->getSupportedLocales();
482
483
        $order = $this->configRepository->get('laravellocalization.localesOrder');
484
485
        uksort($locales, function ($a, $b) use ($order) {
486
            $pos_a = array_search($a, $order);
487
            $pos_b = array_search($b, $order);
488
            return $pos_a - $pos_b;
489
        });
490
491
        return $locales;
492
    }
493
494
    /**
495
     * Returns current locale name.
496
     *
497
     * @return string current locale name
498
     */
499
    public function getCurrentLocaleName()
500
    {
501
        return $this->supportedLocales[$this->getCurrentLocale()]['name'];
502
    }
503
504
    /**
505
     * Returns current locale native name.
506
     *
507
     * @return string current locale native name
508
     */
509
    public function getCurrentLocaleNative()
510
    {
511
        return $this->supportedLocales[$this->getCurrentLocale()]['native'];
512
    }
513
514
    /**
515
     * Returns current locale direction.
516
     *
517
     * @return string current locale direction
518
     */
519
    public function getCurrentLocaleDirection()
520
    {
521
        if (!empty($this->supportedLocales[$this->getCurrentLocale()]['dir'])) {
522
            return $this->supportedLocales[$this->getCurrentLocale()]['dir'];
523
        }
524
525
        switch ($this->getCurrentLocaleScript()) {
526
            // Other (historic) RTL scripts exist, but this list contains the only ones in current use.
527
            case 'Arab':
528
            case 'Hebr':
529
            case 'Mong':
530
            case 'Tfng':
531
            case 'Thaa':
532
            return 'rtl';
533
            default:
534
            return 'ltr';
535
        }
536
    }
537
538
    /**
539
     * Returns current locale script.
540
     *
541
     * @return string current locale script
542
     */
543
    public function getCurrentLocaleScript()
544
    {
545
        return $this->supportedLocales[$this->getCurrentLocale()]['script'];
546
    }
547
548
    /**
549
     * Returns current language's native reading.
550
     *
551
     * @return string current language's native reading
552
     */
553
    public function getCurrentLocaleNativeReading()
554
    {
555
        return $this->supportedLocales[$this->getCurrentLocale()]['native'];
556
    }
557
558
    /**
559
     * Returns current language.
560
     *
561
     * @return string current language
562
     */
563
    public function getCurrentLocale()
564
    {
565
        if ($this->currentLocale) {
566
            return $this->currentLocale;
567
        }
568
569
        if ($this->useAcceptLanguageHeader() && !$this->app->runningInConsole()) {
570
            $negotiator = new LanguageNegotiator($this->defaultLocale, $this->getSupportedLocales(), $this->request);
571
572
            return $negotiator->negotiateLanguage();
573
        }
574
575
        // or get application default language
576
        return $this->configRepository->get('app.locale');
577
    }
578
579
    /**
580
     * Returns current regional.
581
     *
582
     * @return string current regional
583
     */
584
    public function getCurrentLocaleRegional()
585
    {
586
        // need to check if it exists, since 'regional' has been added
587
        // after version 1.0.11 and existing users will not have it
588
        if (isset($this->supportedLocales[$this->getCurrentLocale()]['regional'])) {
589
            return $this->supportedLocales[$this->getCurrentLocale()]['regional'];
590
        } else {
591
            return;
592
        }
593
    }
594
595
    /**
596
     * Returns supported languages language key.
597
     *
598
     * @return array keys of supported languages
599
     */
600
    public function getSupportedLanguagesKeys()
601
    {
602
        return array_keys($this->supportedLocales);
603
    }
604
605
    /**
606
     * Check if Locale exists on the supported locales array.
607
     *
608
     * @param string|bool $locale string|bool Locale to be checked
609
     *
610
     * @throws SupportedLocalesNotDefined
611
     *
612
     * @return bool is the locale supported?
613
     */
614
    public function checkLocaleInSupportedLocales($locale)
615
    {
616
        $inversedLocale = $this->getInversedLocaleFromMapping($locale);
0 ignored issues
show
Bug introduced by
It seems like $locale defined by parameter $locale on line 614 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...
617
        $locales = $this->getSupportedLocales();
618
        if ($locale !== false && empty($locales[$locale]) && empty($locales[$inversedLocale])) {
619
            return false;
620
        }
621
622
        return true;
623
    }
624
625
    /**
626
     * Change route attributes for the ones in the $attributes array.
627
     *
628
     * @param $attributes array Array of attributes
629
     * @param string $route string route to substitute
630
     *
631
     * @return string route with attributes changed
632
     */
633
    protected function substituteAttributesInRoute($attributes, $route)
634
    {
635
        foreach ($attributes as $key => $value) {
636
            if ($value instanceOf UrlRoutable) {
0 ignored issues
show
Bug introduced by
The class Illuminate\Contracts\Routing\UrlRoutable does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
637
                $value = $value->getRouteKey();
638
            }
639
            $route = str_replace(array('{'.$key.'}', '{'.$key.'?}'), $value, $route);
640
        }
641
642
        // delete empty optional arguments that are not in the $attributes array
643
        $route = preg_replace('/\/{[^)]+\?}/', '', $route);
644
645
        return $route;
646
    }
647
648
    /**
649
     * Returns translated routes.
650
     *
651
     * @return array translated routes
652
     */
653
    protected function getTranslatedRoutes()
654
    {
655
        return $this->translatedRoutes;
656
    }
657
658
    /**
659
     * Set current route name.
660
     *
661
     * @param string $routeName current route name
662
     */
663
    public function setRouteName($routeName)
664
    {
665
        $this->routeName = $routeName;
666
    }
667
668
    /**
669
     * Translate routes and save them to the translated routes array (used in the localize route filter).
670
     *
671
     * @param string $routeName Key of the translated string
672
     *
673
     * @return string Translated string
674
     */
675
    public function transRoute($routeName)
676
    {
677
        if (!\in_array($routeName, $this->translatedRoutes)) {
678
            $this->translatedRoutes[] = $routeName;
679
        }
680
681
        return $this->translator->trans($routeName);
682
    }
683
684
    /**
685
     * Returns the translation key for a given path.
686
     *
687
     * @param string $path Path to get the key translated
688
     *
689
     * @return string|false Key for translation, false if not exist
690
     */
691
    public function getRouteNameFromAPath($path)
692
    {
693
        $attributes = $this->extractAttributes($path);
694
695
        $path = parse_url($path)['path'];
696
        $path = trim(str_replace('/'.$this->currentLocale.'/', '', $path), "/");
697
698
        foreach ($this->translatedRoutes as $route) {
699
            if (trim($this->substituteAttributesInRoute($attributes, $this->translator->trans($route)), '/') === $path) {
700
                return $route;
701
            }
702
        }
703
704
        return false;
705
    }
706
707
    /**
708
     * Returns the translated route for the path and the url given.
709
     *
710
     * @param string $path       Path to check if it is a translated route
711
     * @param string $url_locale Language to check if the path exists
712
     *
713
     * @return string|false Key for translation, false if not exist
714
     */
715
    protected function findTranslatedRouteByPath($path, $url_locale)
716
    {
717
        // check if this url is a translated url
718
        foreach ($this->translatedRoutes as $translatedRoute) {
719
            if ($this->translator->trans($translatedRoute, [], $url_locale) == rawurldecode($path)) {
720
                return $translatedRoute;
721
            }
722
        }
723
724
        return false;
725
    }
726
727
    /**
728
     * Returns the translated route for an url and the attributes given and a locale.
729
     *
730
     *
731
     * @param string|false|null $url        Url to check if it is a translated route
732
     * @param array             $attributes Attributes to check if the url exists in the translated routes array
733
     * @param string            $locale     Language to check if the url exists
734
     *
735
     * @throws SupportedLocalesNotDefined
736
     * @throws UnsupportedLocaleException
737
     *
738
     * @return string|false Key for translation, false if not exist
739
     */
740
    protected function findTranslatedRouteByUrl($url, $attributes, $locale)
741
    {
742
        if (empty($url)) {
743
            return false;
744
        }
745
746
        if (isset($this->cachedTranslatedRoutesByUrl[$locale][$url])) {
747
            return $this->cachedTranslatedRoutesByUrl[$locale][$url];
748
        }
749
750
        // check if this url is a translated url
751
        foreach ($this->translatedRoutes as $translatedRoute) {
752
            $routeName = $this->getURLFromRouteNameTranslated($locale, $translatedRoute, $attributes);
753
754
            // We can ignore extra url parts and compare only their url_path (ignore arguments that are not attributes)
755
            if (parse_url($this->getNonLocalizedURL($routeName), PHP_URL_PATH) == parse_url($this->getNonLocalizedURL($url), PHP_URL_PATH)) {
756
                $this->cachedTranslatedRoutesByUrl[$locale][$url] = $translatedRoute;
757
758
                return $translatedRoute;
759
            }
760
        }
761
762
        return false;
763
    }
764
765
    /**
766
     * Returns true if the string given is a valid url.
767
     *
768
     * @param string $url String to check if it is a valid url
769
     *
770
     * @return bool Is the string given a valid url?
771
     */
772
    protected function checkUrl($url)
773
    {
774
        return filter_var($url, FILTER_VALIDATE_URL);
775
    }
776
777
    /**
778
     * Returns the config repository for this instance.
779
     *
780
     * @return Repository Configuration repository
781
     */
782
    public function getConfigRepository()
783
    {
784
        return $this->configRepository;
785
    }
786
787
    /**
788
     * Returns the translation key for a given path.
789
     *
790
     * @return bool Returns value of useAcceptLanguageHeader in config.
791
     */
792
    protected function useAcceptLanguageHeader()
793
    {
794
        return $this->configRepository->get('laravellocalization.useAcceptLanguageHeader');
795
    }
796
797
    public function hideUrlAndAcceptHeader()
798
    {
799
      return $this->hideDefaultLocaleInURL() && $this->useAcceptLanguageHeader();
800
    }
801
802
    /**
803
     * Returns the translation key for a given path.
804
     *
805
     * @return bool Returns value of hideDefaultLocaleInURL in config.
806
     */
807
    public function hideDefaultLocaleInURL()
808
    {
809
        return $this->configRepository->get('laravellocalization.hideDefaultLocaleInURL');
810
    }
811
812
    /**
813
     * Create an url from the uri.
814
     *
815
     * @param string $uri Uri
816
     *
817
     * @return string Url for the given uri
818
     */
819
    public function createUrlFromUri($uri)
820
    {
821
        $uri = ltrim($uri, '/');
822
823
        if (empty($this->baseUrl)) {
824
            return app('url')->to($uri);
825
        }
826
827
        return $this->baseUrl.$uri;
828
    }
829
830
    /**
831
     * Sets the base url for the site.
832
     *
833
     * @param string $url Base url for the site
834
     */
835
    public function setBaseUrl($url)
836
    {
837
        if (substr($url, -1) != '/') {
838
            $url .= '/';
839
        }
840
841
        $this->baseUrl = $url;
842
    }
843
844
    /**
845
     * Returns serialized translated routes for caching purposes.
846
     *
847
     * @return string
848
     */
849
    public function getSerializedTranslatedRoutes()
850
    {
851
        return base64_encode(serialize($this->translatedRoutes));
852
    }
853
854
    /**
855
     * Sets the translated routes list.
856
     * Only useful from a cached routes context.
857
     *
858
     * @param string $serializedRoutes
859
     */
860
    public function setSerializedTranslatedRoutes($serializedRoutes)
861
    {
862
        if ( ! $serializedRoutes) {
863
            return;
864
        }
865
866
        $this->translatedRoutes = unserialize(base64_decode($serializedRoutes));
867
    }
868
869
    /**
870
     * Extract attributes for current url.
871
     *
872
     * @param bool|false|null|string $url    to extract attributes, if not present, the system will look for attributes in the current call
873
     * @param string                 $locale
874
     *
875
     * @return array Array with attributes
876
     */
877
    protected function extractAttributes($url = false, $locale = '')
878
    {
879
        if (!empty($url)) {
880
            $attributes = [];
881
            $parse = parse_url($url);
882
            if (isset($parse['path'])) {
883
                $parse['path'] = trim(str_replace('/'.$this->currentLocale.'/', '', $parse['path']), "/");
884
                $url = explode('/', trim($parse['path'], '/'));
885
            } else {
886
                $url = [];
887
            }
888
889
            foreach ($this->router->getRoutes() as $route) {
890
                $attributes = [];
891
                $path = method_exists($route, 'uri') ? $route->uri() : $route->getUri();
892
893
                if (!preg_match("/{[\w]+\??}/", $path)) {
894
                    continue;
895
                }
896
897
                $path = explode('/', $path);
898
                $i = 0;
899
900
                // The system's route can't be smaller
901
                // only the $url can be missing segments (optional parameters)
902
                // We can assume it's the wrong route
903
                if (count($path) < count($url)) {
904
                    continue;
905
                }
906
907
                $match = true;
908
                foreach ($path as $j => $segment) {
909
                    if (isset($url[$i])) {
910
                        if ($segment === $url[$i]) {
911
                            $i++;
912
                            continue;
913 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...
914
                            // must-have parameters
915
                            $attribute_name = preg_replace(['/}/', '/{/', "/\?/"], '', $segment);
916
                            $attributes[$attribute_name] = $url[$i];
917
                            $i++;
918
                            continue;
919
                        } elseif (preg_match("/{[\w]+\?}/", $segment)) {
920
                            // optional parameters
921
                            if (!isset($path[$j + 1]) || $path[$j + 1] !== $url[$i]) {
922
                                // optional parameter taken
923
                                $attribute_name = preg_replace(['/}/', '/{/', "/\?/"], '', $segment);
924
                                $attributes[$attribute_name] = $url[$i];
925
                                $i++;
926
                                continue;
927
                            } else {
928
                                $match = false;
929
                                break;
930
                            }
931
                        } else {
932
                            // As soon as one segment doesn't match, then we have the wrong route
933
                            $match = false;
934
                            break;
935
                        }
936 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...
937
                        $attribute_name = preg_replace(['/}/', '/{/', "/\?/"], '', $segment);
938
                        $attributes[$attribute_name] = null;
939
                        $i++;
940
                    } else {
941
                        // no optional parameters but no more $url given
942
                        // this route does not match the url
943
                        $match = false;
944
                        break;
945
                    }
946
                }
947
948
                if (isset($url[$i + 1])) {
949
                    $match = false;
950
                }
951
952
                if ($match) {
953
                    return $attributes;
954
                }
955
            }
956
        } else {
957
            if (!$this->router->current()) {
958
                return [];
959
            }
960
961
            $attributes = $this->normalizeAttributes($this->router->current()->parameters());
962
            $response = event('routes.translation', [$locale, $attributes]);
963
964
            if (!empty($response)) {
965
                $response = array_shift($response);
966
            }
967
968
            if (\is_array($response)) {
969
                $attributes = array_merge($attributes, $response);
970
            }
971
        }
972
973
        return $attributes;
974
    }
975
976
    /**
977
     * Build URL using array data from parse_url.
978
     *
979
     * @param array|false $parsed_url Array of data from parse_url function
980
     *
981
     * @return string Returns URL as string.
982
     */
983
    protected function unparseUrl($parsed_url)
984
    {
985
        if (empty($parsed_url)) {
986
            return '';
987
        }
988
989
        $url = '';
990
        $url .= isset($parsed_url['scheme']) ? $parsed_url['scheme'].'://' : '';
991
        $url .= $parsed_url['host'] ?? '';
992
        $url .= isset($parsed_url['port']) ? ':'.$parsed_url['port'] : '';
993
        $user = $parsed_url['user'] ?? '';
994
        $pass = isset($parsed_url['pass']) ? ':'.$parsed_url['pass'] : '';
995
        $url .= $user.(($user || $pass) ? "$pass@" : '');
996
997
        if (!empty($url)) {
998
            $url .= isset($parsed_url['path']) ? '/'.ltrim($parsed_url['path'], '/') : '';
999
        } else {
1000
            $url .= $parsed_url['path'] ?? '';
1001
        }
1002
1003
        $url .= isset($parsed_url['query']) ? '?'.$parsed_url['query'] : '';
1004
        $url .= isset($parsed_url['fragment']) ? '#'.$parsed_url['fragment'] : '';
1005
1006
        return $url;
1007
    }
1008
1009
    /**
1010
    * Normalize attributes gotten from request parameters.
1011
    *
1012
    * @param      array  $attributes  The attributes
1013
    * @return     array  The normalized attributes
1014
    */
1015
     protected function normalizeAttributes($attributes)
1016
     {
1017
         if (array_key_exists('data', $attributes) && \is_array($attributes['data']) && ! \count($attributes['data'])) {
1018
             $attributes['data'] = null;
1019
             return $attributes;
1020
         }
1021
         return $attributes;
1022
     }
1023
1024
    /**
1025
     * Returns the forced environment set route locale.
1026
     *
1027
     * @return string|null
1028
     */
1029
    protected function getForcedLocale()
1030
    {
1031
        return env(static::ENV_ROUTE_KEY, function () {
1032
            $value = getenv(static::ENV_ROUTE_KEY);
1033
1034
            if ($value !== false) {
1035
                return $value;
1036
            }
1037
        });
1038
    }
1039
}
1040