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
Push — master ( 8e0157...c27cb0 )
by Marc
01:55
created

LaravelLocalization::getTranslatedRoutes()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
namespace Mcamara\LaravelLocalization;
4
5
use Illuminate\Config\Repository;
6
use Illuminate\Foundation\Application;
7
use Illuminate\Http\Request;
8
use Illuminate\Routing\Router;
9
use Illuminate\Support\Facades\URL;
10
use Illuminate\Translation\Translator;
11
use Illuminate\View\Factory;
12
use Mcamara\LaravelLocalization\Exceptions\SupportedLocalesNotDefined;
13
use Mcamara\LaravelLocalization\Exceptions\UnsupportedLocaleException;
14
15
class LaravelLocalization
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
     * Current locale.
89
     *
90
     * @var string
91
     */
92
    protected $currentLocale = false;
93
94
    /**
95
     * An array that contains all routes that should be translated.
96
     *
97
     * @var array
98
     */
99
    protected $translatedRoutes = [];
100
101
    /**
102
     * Name of the translation key of the current route, it is used for url translations.
103
     *
104
     * @var string
105
     */
106
    protected $routeName;
107
108
    /**
109
     * Creates new instance.
110
     *
111
     * @throws UnsupportedLocaleException
112
     */
113
    public function __construct()
114
    {
115
        $this->app = app();
116
117
        $this->configRepository = $this->app['config'];
118
        $this->view = $this->app['view'];
119
        $this->translator = $this->app['translator'];
120
        $this->router = $this->app['router'];
121
        $this->request = $this->app['request'];
122
        $this->url = $this->app['url'];
123
124
        // set default locale
125
        $this->defaultLocale = $this->configRepository->get('app.locale');
126
        $supportedLocales = $this->getSupportedLocales();
127
128
        if (empty($supportedLocales[$this->defaultLocale])) {
129
            throw new UnsupportedLocaleException('Laravel default locale is not in the supportedLocales array.');
130
        }
131
    }
132
133
    /**
134
     * Set and return current locale.
135
     *
136
     * @param string $locale Locale to set the App to (optional)
137
     *
138
     * @return string Returns locale (if route has any) or null (if route does not have a locale)
139
     */
140
    public function setLocale($locale = null)
141
    {
142
        if (empty($locale) || !is_string($locale)) {
143
            // If the locale has not been passed through the function
144
            // it tries to get it from the first segment of the url
145
            $locale = $this->request->segment(1);
146
        }
147
148
        if (!empty($this->supportedLocales[$locale])) {
149
            $this->currentLocale = $locale;
150
        } else {
151
            // if the first segment/locale passed is not valid
152
            // the system would ask which locale have to take
153
            // it could be taken by the browser
154
            // depending on your configuration
155
156
            $locale = null;
157
158
            // if we reached this point and hideDefaultLocaleInURL is true
159
            // we have to assume we are routing to a defaultLocale route.
160
            if ($this->hideDefaultLocaleInURL()) {
161
                $this->currentLocale = $this->defaultLocale;
162
            }
163
            // but if hideDefaultLocaleInURL is false, we have
164
            // to retrieve it from the browser...
165
            else {
166
                $this->currentLocale = $this->getCurrentLocale();
167
            }
168
        }
169
170
        $this->app->setLocale($this->currentLocale);
171
172
        // Regional locale such as de_DE, so formatLocalized works in Carbon
173
        $regional = $this->getCurrentLocaleRegional();
174
        if ($regional) {
175
            setlocale(LC_TIME, $regional.'.UTF-8');
176
            setlocale(LC_MONETARY, $regional.'.UTF-8');
177
        }
178
179
        return $locale;
180
    }
181
182
    /**
183
     * Set and return supported locales.
184
     *
185
     * @param array $locales Locales that the App supports
186
     */
187
    public function setSupportedLocales($locales)
188
    {
189
        $this->supportedLocales = $locales;
190
    }
191
192
    /**
193
     * Returns an URL adapted to $locale or current locale.
194
     *
195
     * @param string      $url    URL to adapt. If not passed, the current url would be taken.
196
     * @param string|bool $locale Locale to adapt, false to remove locale
197
     *
198
     * @throws UnsupportedLocaleException
199
     *
200
     * @return string URL translated
201
     */
202
    public function localizeURL($url = null, $locale = null)
203
    {
204
        return $this->getLocalizedURL($locale, $url);
205
    }
206
207
    /**
208
     * Returns an URL adapted to $locale.
209
     *
210
     *
211
     * @param string|bool  $locale     Locale to adapt, false to remove locale
212
     * @param string|false $url        URL to adapt in the current language. If not passed, the current url would be taken.
213
     * @param array        $attributes Attributes to add to the route, if empty, the system would try to extract them from the url.
214
     *
215
     * @throws SupportedLocalesNotDefined
216
     * @throws UnsupportedLocaleException
217
     *
218
     * @return string|false URL translated, False if url does not exist
219
     */
220
    public function getLocalizedURL($locale = null, $url = null, $attributes = [])
221
    {
222
        if ($locale === null) {
223
            $locale = $this->getCurrentLocale();
224
        }
225
226
        if (!$this->checkLocaleInSupportedLocales($locale)) {
227
            throw new UnsupportedLocaleException('Locale \''.$locale.'\' is not in the list of supported locales.');
228
        }
229
230
        if (empty($attributes)) {
231
            $attributes = $this->extractAttributes($url, $locale);
0 ignored issues
show
Bug introduced by
It seems like $locale defined by parameter $locale on line 220 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...
232
        }
233
234
        if (empty($url)) {
235
            if (!empty($this->routeName)) {
236
                return $this->getURLFromRouteNameTranslated($locale, $this->routeName, $attributes);
237
            }
238
239
            $url = $this->request->fullUrl();
240
        } else {
241
            $url = $this->url->to($url);
242
        }
243
244
        if ($locale && $translatedRoute = $this->findTranslatedRouteByUrl($url, $attributes, $this->currentLocale)) {
245
            return $this->getURLFromRouteNameTranslated($locale, $translatedRoute, $attributes);
246
        }
247
248
        $base_path = $this->request->getBaseUrl();
249
        $parsed_url = parse_url($url);
250
        $url_locale = $this->getDefaultLocale();
251
252
        if (!$parsed_url || empty($parsed_url['path'])) {
253
            $path = $parsed_url['path'] = '';
254
        } else {
255
            $parsed_url['path'] = str_replace($base_path, '', '/'.ltrim($parsed_url['path'], '/'));
256
            $path = $parsed_url['path'];
257
            foreach ($this->getSupportedLocales() as $localeCode => $lang) {
258
                $parsed_url['path'] = preg_replace('%^/?'.$localeCode.'/%', '$1', $parsed_url['path']);
259
                if ($parsed_url['path'] !== $path) {
260
                    $url_locale = $localeCode;
261
                    break;
262
                }
263
264
                $parsed_url['path'] = preg_replace('%^/?'.$localeCode.'$%', '$1', $parsed_url['path']);
265
                if ($parsed_url['path'] !== $path) {
266
                    $url_locale = $localeCode;
267
                    break;
268
                }
269
            }
270
        }
271
272
        $parsed_url['path'] = ltrim($parsed_url['path'], '/');
273
274
        if ($translatedRoute = $this->findTranslatedRouteByPath($parsed_url['path'], $url_locale)) {
275
            return $this->getURLFromRouteNameTranslated($locale, $translatedRoute, $attributes);
276
        }
277
278
        if (!empty($locale) && ($locale != $this->defaultLocale || !$this->hideDefaultLocaleInURL())) {
279
            $parsed_url['path'] = $locale.'/'.ltrim($parsed_url['path'], '/');
280
        }
281
        $parsed_url['path'] = ltrim(ltrim($base_path, '/').'/'.$parsed_url['path'], '/');
282
283
        //Make sure that the pass path is returned with a leading slash only if it come in with one.
284
        if (starts_with($path, '/') === true) {
285
            $parsed_url['path'] = '/'.$parsed_url['path'];
286
        }
287
        $parsed_url['path'] = rtrim($parsed_url['path'], '/');
288
289
        $url = $this->unparseUrl($parsed_url);
290
291
        if ($this->checkUrl($url)) {
292
            return $url;
293
        }
294
295
        return $this->createUrlFromUri($url);
296
    }
297
298
    /**
299
     * Returns an URL adapted to the route name and the locale given.
300
     *
301
     *
302
     * @param string|bool $locale       Locale to adapt
303
     * @param string      $transKeyName Translation key name of the url to adapt
304
     * @param array       $attributes   Attributes for the route (only needed if transKeyName needs them)
305
     *
306
     * @throws SupportedLocalesNotDefined
307
     * @throws UnsupportedLocaleException
308
     *
309
     * @return string|false URL translated
310
     */
311
    public function getURLFromRouteNameTranslated($locale, $transKeyName, $attributes = [])
312
    {
313
        if (!$this->checkLocaleInSupportedLocales($locale)) {
314
            throw new UnsupportedLocaleException('Locale \''.$locale.'\' is not in the list of supported locales.');
315
        }
316
317
        if (!is_string($locale)) {
318
            $locale = $this->getDefaultLocale();
319
        }
320
321
        $route = '';
322
323
        if (!($locale === $this->defaultLocale && $this->hideDefaultLocaleInURL())) {
324
            $route = '/'.$locale;
325
        }
326
        if (is_string($locale) && $this->translator->has($transKeyName, $locale)) {
327
            $translation = $this->translator->trans($transKeyName, [], $locale);
328
            $route .= '/'.$translation;
329
330
            $route = $this->substituteAttributesInRoute($attributes, $route);
331
        }
332
333
        if (empty($route)) {
334
            // This locale does not have any key for this route name
335
            return false;
336
        }
337
338
        return rtrim($this->createUrlFromUri($route));
339
    }
340
341
    /**
342
     * It returns an URL without locale (if it has it)
343
     * Convenience function wrapping getLocalizedURL(false).
344
     *
345
     * @param string|false $url URL to clean, if false, current url would be taken
346
     *
347
     * @return string URL with no locale in path
348
     */
349
    public function getNonLocalizedURL($url = null)
350
    {
351
        return $this->getLocalizedURL(false, $url);
352
    }
353
354
    /**
355
     * Returns default locale.
356
     *
357
     * @return string
358
     */
359
    public function getDefaultLocale()
360
    {
361
        return $this->defaultLocale;
362
    }
363
364
    /**
365
     * Return an array of all supported Locales.
366
     *
367
     * @throws SupportedLocalesNotDefined
368
     *
369
     * @return array
370
     */
371
    public function getSupportedLocales()
372
    {
373
        if (!empty($this->supportedLocales)) {
374
            return $this->supportedLocales;
375
        }
376
377
        $locales = $this->configRepository->get('laravellocalization.supportedLocales');
378
379
        if (empty($locales) || !is_array($locales)) {
380
            throw new SupportedLocalesNotDefined();
381
        }
382
383
        $this->supportedLocales = $locales;
384
385
        return $locales;
386
    }
387
388
    /**
389
     * Return an array of all supported Locales but in the order the user
390
     * has specified in the config file. Useful for the language selector.
391
     *
392
     * @return array
393
     */
394
    public function getLocalesOrder()
395
    {
396
        $locales = $this->getSupportedLocales();
397
398
        $order = $this->configRepository->get('laravellocalization.localesOrder');
399
400
        uksort($locales, function ($a, $b) use ($order) {
401
            $pos_a = array_search($a, $order);
402
            $pos_b = array_search($b, $order);
403
            return $pos_a - $pos_b;
404
        });
405
406
        return $locales;
407
    }
408
409
    /**
410
     * Returns current locale name.
411
     *
412
     * @return string current locale name
413
     */
414
    public function getCurrentLocaleName()
415
    {
416
        return $this->supportedLocales[$this->getCurrentLocale()]['name'];
417
    }
418
419
    /**
420
     * Returns current locale native name.
421
     *
422
     * @return string current locale native name
423
     */
424
    public function getCurrentLocaleNative()
425
    {
426
        return $this->supportedLocales[$this->getCurrentLocale()]['native'];
427
    }
428
429
    /**
430
     * Returns current locale direction.
431
     *
432
     * @return string current locale direction
433
     */
434
    public function getCurrentLocaleDirection()
435
    {
436
        if (!empty($this->supportedLocales[$this->getCurrentLocale()]['dir'])) {
437
            return $this->supportedLocales[$this->getCurrentLocale()]['dir'];
438
        }
439
440
        switch ($this->getCurrentLocaleScript()) {
441
            // Other (historic) RTL scripts exist, but this list contains the only ones in current use.
442
            case 'Arab':
443
            case 'Hebr':
444
            case 'Mong':
445
            case 'Tfng':
446
            case 'Thaa':
447
            return 'rtl';
448
            default:
449
            return 'ltr';
450
        }
451
    }
452
453
    /**
454
     * Returns current locale script.
455
     *
456
     * @return string current locale script
457
     */
458
    public function getCurrentLocaleScript()
459
    {
460
        return $this->supportedLocales[$this->getCurrentLocale()]['script'];
461
    }
462
463
    /**
464
     * Returns current language's native reading.
465
     *
466
     * @return string current language's native reading
467
     */
468
    public function getCurrentLocaleNativeReading()
469
    {
470
        return $this->supportedLocales[$this->getCurrentLocale()]['native'];
471
    }
472
473
    /**
474
     * Returns current language.
475
     *
476
     * @return string current language
477
     */
478
    public function getCurrentLocale()
479
    {
480
        if ($this->currentLocale) {
481
            return $this->currentLocale;
482
        }
483
484
        if ($this->useAcceptLanguageHeader()) {
485
            $negotiator = new LanguageNegotiator($this->defaultLocale, $this->getSupportedLocales(), $this->request);
486
487
            return $negotiator->negotiateLanguage();
488
        }
489
490
        // or get application default language
491
        return $this->configRepository->get('app.locale');
492
    }
493
494
    /**
495
     * Returns current regional.
496
     *
497
     * @return string current regional
498
     */
499
    public function getCurrentLocaleRegional()
500
    {
501
        // need to check if it exists, since 'regional' has been added
502
        // after version 1.0.11 and existing users will not have it
503
        if (isset($this->supportedLocales[$this->getCurrentLocale()]['regional'])) {
504
            return $this->supportedLocales[$this->getCurrentLocale()]['regional'];
505
        } else {
506
            return;
507
        }
508
    }
509
510
    /**
511
     * Returns supported languages language key.
512
     *
513
     * @return array keys of supported languages
514
     */
515
    public function getSupportedLanguagesKeys()
516
    {
517
        return array_keys($this->supportedLocales);
518
    }
519
520
    /**
521
     * Check if Locale exists on the supported locales array.
522
     *
523
     * @param string|bool $locale string|bool Locale to be checked
524
     *
525
     * @throws SupportedLocalesNotDefined
526
     *
527
     * @return bool is the locale supported?
528
     */
529
    public function checkLocaleInSupportedLocales($locale)
530
    {
531
        $locales = $this->getSupportedLocales();
532
        if ($locale !== false && empty($locales[$locale])) {
533
            return false;
534
        }
535
536
        return true;
537
    }
538
539
    /**
540
     * Change route attributes for the ones in the $attributes array.
541
     *
542
     * @param $attributes array Array of attributes
543
     * @param string $route string route to substitute
544
     *
545
     * @return string route with attributes changed
546
     */
547
    protected function substituteAttributesInRoute($attributes, $route)
548
    {
549
        foreach ($attributes as $key => $value) {
550
            $route = str_replace('{'.$key.'}', $value, $route);
551
            $route = str_replace('{'.$key.'?}', $value, $route);
552
        }
553
554
        // delete empty optional arguments that are not in the $attributes array
555
        $route = preg_replace('/\/{[^)]+\?}/', '', $route);
556
557
        return $route;
558
    }
559
560
    /**
561
     * Returns translated routes.
562
     *
563
     * @return array translated routes
564
     */
565
    protected function getTranslatedRoutes()
566
    {
567
        return $this->translatedRoutes;
568
    }
569
570
    /**
571
     * Set current route name.
572
     *
573
     * @param string $routeName current route name
574
     */
575
    public function setRouteName($routeName)
576
    {
577
        $this->routeName = $routeName;
578
    }
579
580
    /**
581
     * Translate routes and save them to the translated routes array (used in the localize route filter).
582
     *
583
     * @param string $routeName Key of the translated string
584
     *
585
     * @return string Translated string
586
     */
587
    public function transRoute($routeName)
588
    {
589
        if (!in_array($routeName, $this->translatedRoutes)) {
590
            $this->translatedRoutes[] = $routeName;
591
        }
592
593
        return $this->translator->trans($routeName);
594
    }
595
596
    /**
597
     * Returns the translation key for a given path.
598
     *
599
     * @param string $path Path to get the key translated
600
     *
601
     * @return string|false Key for translation, false if not exist
602
     */
603
    public function getRouteNameFromAPath($path)
604
    {
605
        $attributes = $this->extractAttributes($path);
606
607
        $path = str_replace(url('/'), '', $path);
608
        if ($path[0] !== '/') {
609
            $path = '/'.$path;
610
        }
611
        $path = str_replace('/'.$this->currentLocale.'/', '', $path);
612
        $path = trim($path, '/');
613
614
        foreach ($this->translatedRoutes as $route) {
615
            if ($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...
616
                return $route;
617
            }
618
        }
619
620
        return false;
621
    }
622
623
    /**
624
     * Returns the translated route for the path and the url given.
625
     *
626
     * @param string $path       Path to check if it is a translated route
627
     * @param string $url_locale Language to check if the path exists
628
     *
629
     * @return string|false Key for translation, false if not exist
630
     */
631
    protected function findTranslatedRouteByPath($path, $url_locale)
632
    {
633
        // check if this url is a translated url
634
        foreach ($this->translatedRoutes as $translatedRoute) {
635
            if ($this->translator->trans($translatedRoute, [], $url_locale) == rawurldecode($path)) {
636
                return $translatedRoute;
637
            }
638
        }
639
640
        return false;
641
    }
642
643
    /**
644
     * Returns the translated route for an url and the attributes given and a locale.
645
     *
646
     *
647
     * @param string|false|null $url        Url to check if it is a translated route
648
     * @param array             $attributes Attributes to check if the url exists in the translated routes array
649
     * @param string            $locale     Language to check if the url exists
650
     *
651
     * @throws SupportedLocalesNotDefined
652
     * @throws UnsupportedLocaleException
653
     *
654
     * @return string|false Key for translation, false if not exist
655
     */
656
    protected function findTranslatedRouteByUrl($url, $attributes, $locale)
657
    {
658
        if (empty($url)) {
659
            return false;
660
        }
661
662
        // check if this url is a translated url
663
        foreach ($this->translatedRoutes as $translatedRoute) {
664
            $routeName = $this->getURLFromRouteNameTranslated($locale, $translatedRoute, $attributes);
665
666
            if ($this->getNonLocalizedURL($routeName) == $this->getNonLocalizedURL($url)) {
667
                return $translatedRoute;
668
            }
669
        }
670
671
        return false;
672
    }
673
674
    /**
675
     * Returns true if the string given is a valid url.
676
     *
677
     * @param string $url String to check if it is a valid url
678
     *
679
     * @return bool Is the string given a valid url?
680
     */
681
    protected function checkUrl($url)
682
    {
683
        return filter_var($url, FILTER_VALIDATE_URL);
684
    }
685
686
    /**
687
     * Returns the config repository for this instance.
688
     *
689
     * @return Repository Configuration repository
690
     */
691
    public function getConfigRepository()
692
    {
693
        return $this->configRepository;
694
    }
695
696
    /**
697
     * Returns the translation key for a given path.
698
     *
699
     * @return bool Returns value of useAcceptLanguageHeader in config.
700
     */
701
    protected function useAcceptLanguageHeader()
702
    {
703
        return $this->configRepository->get('laravellocalization.useAcceptLanguageHeader');
704
    }
705
706
    /**
707
     * Returns the translation key for a given path.
708
     *
709
     * @return bool Returns value of hideDefaultLocaleInURL in config.
710
     */
711
    public function hideDefaultLocaleInURL()
712
    {
713
        return $this->configRepository->get('laravellocalization.hideDefaultLocaleInURL');
714
    }
715
716
    /**
717
     * Create an url from the uri.
718
     *
719
     * @param string $uri Uri
720
     *
721
     * @return string Url for the given uri
722
     */
723
    public function createUrlFromUri($uri)
724
    {
725
        $uri = ltrim($uri, '/');
726
727
        if (empty($this->baseUrl)) {
728
            return app('url')->to($uri);
729
        }
730
731
        return $this->baseUrl.$uri;
732
    }
733
734
    /**
735
     * Sets the base url for the site.
736
     *
737
     * @param string $url Base url for the site
738
     */
739
    public function setBaseUrl($url)
740
    {
741
        if (substr($url, -1) != '/') {
742
            $url .= '/';
743
        }
744
745
        $this->baseUrl = $url;
746
    }
747
748
    /**
749
     * Extract attributes for current url.
750
     *
751
     * @param bool|false|null|string $url    to extract attributes, if not present, the system will look for attributes in the current call
752
     * @param string                 $locale
753
     *
754
     * @return array Array with attributes
755
     */
756
    protected function extractAttributes($url = false, $locale = '')
757
    {
758
        if (!empty($url)) {
759
            $attributes = [];
760
            $parse = parse_url($url);
761
            if (isset($parse['path'])) {
762
                $parse = explode('/', $parse['path']);
763
            } else {
764
                $parse = [];
765
            }
766
            $url = [];
767
            foreach ($parse as $segment) {
768
                if (!empty($segment)) {
769
                    $url[] = $segment;
770
                }
771
            }
772
773
            foreach ($this->router->getRoutes() as $route) {
774
                $path = method_exists($route, 'uri') ? $route->uri() : $route->getUri();
775
776
                if (!preg_match("/{[\w]+}/", $path)) {
777
                    continue;
778
                }
779
780
                $path = explode('/', $path);
781
                $i = 0;
782
783
                $match = true;
784
                foreach ($path as $j => $segment) {
785
                    if (isset($url[$i])) {
786
                        if ($segment === $url[$i]) {
787
                            $i++;
788
                            continue;
789
                        }
790
                        if (preg_match("/{[\w]+}/", $segment)) {
791
                            // must-have parameters
792
                            $attribute_name = preg_replace(['/}/', '/{/', "/\?/"], '', $segment);
793
                            $attributes[$attribute_name] = $url[$i];
794
                            $i++;
795
                            continue;
796
                        }
797
                        if (preg_match("/{[\w]+\?}/", $segment)) {
798
                            // optional parameters
799
                            if (!isset($path[$j + 1]) || $path[$j + 1] !== $url[$i]) {
800
                                // optional parameter taken
801
                                $attribute_name = preg_replace(['/}/', '/{/', "/\?/"], '', $segment);
802
                                $attributes[$attribute_name] = $url[$i];
803
                                $i++;
804
                                continue;
805
                            }
806
                        }
807
                    } elseif (!preg_match("/{[\w]+\?}/", $segment)) {
808
                        // no optional parameters but no more $url given
809
                        // this route does not match the url
810
                        $match = false;
811
                        break;
812
                    }
813
                }
814
815
                if (isset($url[$i + 1])) {
816
                    $match = false;
817
                }
818
819
                if ($match) {
820
                    return $attributes;
821
                }
822
            }
823
        } else {
824
            if (!$this->router->current()) {
825
                return [];
826
            }
827
828
            $attributes = $this->router->current()->parameters();
829
            $response = event('routes.translation', [$locale, $attributes]);
830
831
            if (!empty($response)) {
832
                $response = array_shift($response);
833
            }
834
835
            if (is_array($response)) {
836
                $attributes = array_merge($attributes, $response);
837
            }
838
        }
839
840
        return $attributes;
841
    }
842
843
    /**
844
     * Build URL using array data from parse_url.
845
     *
846
     * @param array|false $parsed_url Array of data from parse_url function
847
     *
848
     * @return string Returns URL as string.
849
     */
850
    protected function unparseUrl($parsed_url)
851
    {
852
        if (empty($parsed_url)) {
853
            return '';
854
        }
855
856
        $url = '';
857
        $url .= isset($parsed_url['scheme']) ? $parsed_url['scheme'].'://' : '';
858
        $url .= isset($parsed_url['host']) ? $parsed_url['host'] : '';
859
        $url .= isset($parsed_url['port']) ? ':'.$parsed_url['port'] : '';
860
        $user = isset($parsed_url['user']) ? $parsed_url['user'] : '';
861
        $pass = isset($parsed_url['pass']) ? ':'.$parsed_url['pass'] : '';
862
        $url .= $user.(($user || $pass) ? "$pass@" : '');
863
864
        if (!empty($url)) {
865
            $url .= isset($parsed_url['path']) ? '/'.ltrim($parsed_url['path'], '/') : '';
866
        } else {
867
            $url .= isset($parsed_url['path']) ? $parsed_url['path'] : '';
868
        }
869
870
        $url .= isset($parsed_url['query']) ? '?'.$parsed_url['query'] : '';
871
        $url .= isset($parsed_url['fragment']) ? '#'.$parsed_url['fragment'] : '';
872
873
        return $url;
874
    }
875
}
876