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 (#387)
by
unknown
01:52
created

LaravelLocalization::getLocalizedURL()   F

Complexity

Conditions 22
Paths 534

Size

Total Lines 80
Code Lines 47

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 80
rs 2.9653
c 0
b 0
f 0
cc 22
eloc 47
nc 534
nop 3

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
        elseif ( !empty( $locale ) && ( $locale != $this->defaultLocale || $this->hideDefaultLocaleInURL() ) ) {
282
            $parsed_url[ 'path' ] = $this->getDefaultLocale() . '/' . ltrim($parsed_url[ 'path' ], '/');
283
        }
284
        $parsed_url[ 'path' ] = ltrim(ltrim($base_path, '/') . '/' . $parsed_url[ 'path' ], '/');
285
286
        //Make sure that the pass path is returned with a leading slash only if it come in with one.
287
        if (starts_with($path, '/') === true) {
288
            $parsed_url['path'] = '/'.$parsed_url['path'];
289
        }
290
        $parsed_url['path'] = rtrim($parsed_url['path'], '/');
291
292
        $url = $this->unparseUrl($parsed_url);
293
294
        if ($this->checkUrl($url)) {
295
            return $url;
296
        }
297
298
        return $this->createUrlFromUri($url);
299
    }
300
301
    /**
302
     * Returns an URL adapted to the route name and the locale given.
303
     *
304
     *
305
     * @param string|bool $locale       Locale to adapt
306
     * @param string      $transKeyName Translation key name of the url to adapt
307
     * @param array       $attributes   Attributes for the route (only needed if transKeyName needs them)
308
     *
309
     * @throws SupportedLocalesNotDefined
310
     * @throws UnsupportedLocaleException
311
     *
312
     * @return string|false URL translated
313
     */
314
    public function getURLFromRouteNameTranslated($locale, $transKeyName, $attributes = [])
315
    {
316
        if (!$this->checkLocaleInSupportedLocales($locale)) {
317
            throw new UnsupportedLocaleException('Locale \''.$locale.'\' is not in the list of supported locales.');
318
        }
319
320
        if (!is_string($locale)) {
321
            $locale = $this->getDefaultLocale();
322
        }
323
324
        $route = '';
325
326
        if (!($locale === $this->defaultLocale && $this->hideDefaultLocaleInURL())) {
327
            $route = '/'.$locale;
328
        }
329
        if (is_string($locale) && $this->translator->has($transKeyName, $locale)) {
330
            $translation = $this->translator->trans($transKeyName, [], $locale);
331
            $route .= '/'.$translation;
332
333
            $route = $this->substituteAttributesInRoute($attributes, $route);
334
        }
335
336
        if (empty($route)) {
337
            // This locale does not have any key for this route name
338
            return false;
339
        }
340
341
        return rtrim($this->createUrlFromUri($route));
342
    }
343
344
    /**
345
     * It returns an URL without locale (if it has it)
346
     * Convenience function wrapping getLocalizedURL(false).
347
     *
348
     * @param string|false $url URL to clean, if false, current url would be taken
349
     *
350
     * @return string URL with no locale in path
351
     */
352
    public function getNonLocalizedURL($url = null)
353
    {
354
        return $this->getLocalizedURL(false, $url);
355
    }
356
357
    /**
358
     * Returns default locale.
359
     *
360
     * @return string
361
     */
362
    public function getDefaultLocale()
363
    {
364
        return $this->defaultLocale;
365
    }
366
367
    /**
368
     * Return an array of all supported Locales.
369
     *
370
     * @throws SupportedLocalesNotDefined
371
     *
372
     * @return array
373
     */
374
    public function getSupportedLocales()
375
    {
376
        if (!empty($this->supportedLocales)) {
377
            return $this->supportedLocales;
378
        }
379
380
        $locales = $this->configRepository->get('laravellocalization.supportedLocales');
381
382
        if (empty($locales) || !is_array($locales)) {
383
            throw new SupportedLocalesNotDefined();
384
        }
385
386
        $this->supportedLocales = $locales;
387
388
        return $locales;
389
    }
390
391
    /**
392
     * Return an array of all supported Locales but in the order the user
393
     * has specified in the config file. Useful for the language selector.
394
     *
395
     * @return array
396
     */
397
    public function getLocalesOrder()
398
    {
399
        $locales = $this->getSupportedLocales();
400
401
        $order = $this->configRepository->get('laravellocalization.localesOrder');
402
403
        uksort($locales, function ($a, $b) use ($order) {
404
            $pos_a = array_search($a, $order);
405
            $pos_b = array_search($b, $order);
406
            return $pos_a - $pos_b;
407
        });
408
409
        return $locales;
410
    }
411
412
    /**
413
     * Returns current locale name.
414
     *
415
     * @return string current locale name
416
     */
417
    public function getCurrentLocaleName()
418
    {
419
        return $this->supportedLocales[$this->getCurrentLocale()]['name'];
420
    }
421
422
    /**
423
     * Returns current locale native name.
424
     *
425
     * @return string current locale native name
426
     */
427
    public function getCurrentLocaleNative()
428
    {
429
        return $this->supportedLocales[$this->getCurrentLocale()]['native'];
430
    }
431
432
    /**
433
     * Returns selected locale native name
434
     * @param  string $locale the localeName you want the native for
435
     *
436
     * @return string selected locale native name
437
     */
438
    public function getLocalizedNative($locale)
439
    {
440
        if ( !$this->checkLocaleInSupportedLocales($locale) )
441
        {
442
            throw new UnsupportedLocaleException('Locale \'' . $locale . '\' is not in the list of supported locales.');
443
        }
444
445
        return $this->supportedLocales[ $locale ][ 'native' ];
446
    }
447
448
    /**
449
     * Returns current locale direction
450
     *
451
     * @return string current locale direction
452
     */
453
    public function getCurrentLocaleDirection()
454
    {
455
        if (!empty($this->supportedLocales[$this->getCurrentLocale()]['dir'])) {
456
            return $this->supportedLocales[$this->getCurrentLocale()]['dir'];
457
        }
458
459
        switch ($this->getCurrentLocaleScript()) {
460
            // Other (historic) RTL scripts exist, but this list contains the only ones in current use.
461
            case 'Arab':
462
            case 'Hebr':
463
            case 'Mong':
464
            case 'Tfng':
465
            case 'Thaa':
466
            return 'rtl';
467
            default:
468
            return 'ltr';
469
        }
470
    }
471
472
    /**
473
     * Returns current locale script.
474
     *
475
     * @return string current locale script
476
     */
477
    public function getCurrentLocaleScript()
478
    {
479
        return $this->supportedLocales[$this->getCurrentLocale()]['script'];
480
    }
481
482
    /**
483
     * Returns current language's native reading.
484
     *
485
     * @return string current language's native reading
486
     */
487
    public function getCurrentLocaleNativeReading()
488
    {
489
        return $this->supportedLocales[$this->getCurrentLocale()]['native'];
490
    }
491
492
    /**
493
     * Returns current language.
494
     *
495
     * @return string current language
496
     */
497
    public function getCurrentLocale()
498
    {
499
        if ($this->currentLocale) {
500
            return $this->currentLocale;
501
        }
502
503
        if ($this->useAcceptLanguageHeader()) {
504
            $negotiator = new LanguageNegotiator($this->defaultLocale, $this->getSupportedLocales(), $this->request);
505
506
            return $negotiator->negotiateLanguage();
507
        }
508
509
        // or get application default language
510
        return $this->configRepository->get('app.locale');
511
    }
512
513
    /**
514
     * Returns current regional.
515
     *
516
     * @return string current regional
517
     */
518
    public function getCurrentLocaleRegional()
519
    {
520
        // need to check if it exists, since 'regional' has been added
521
        // after version 1.0.11 and existing users will not have it
522
        if (isset($this->supportedLocales[$this->getCurrentLocale()]['regional'])) {
523
            return $this->supportedLocales[$this->getCurrentLocale()]['regional'];
524
        } else {
525
            return;
526
        }
527
    }
528
529
    /**
530
     * Returns supported languages language key.
531
     *
532
     * @return array keys of supported languages
533
     */
534
    public function getSupportedLanguagesKeys()
535
    {
536
        return array_keys($this->supportedLocales);
537
    }
538
539
    /**
540
     * Check if Locale exists on the supported locales array.
541
     *
542
     * @param string|bool $locale string|bool Locale to be checked
543
     *
544
     * @throws SupportedLocalesNotDefined
545
     *
546
     * @return bool is the locale supported?
547
     */
548
    public function checkLocaleInSupportedLocales($locale)
549
    {
550
        $locales = $this->getSupportedLocales();
551
        if ($locale !== false && empty($locales[$locale])) {
552
            return false;
553
        }
554
555
        return true;
556
    }
557
558
    /**
559
     * Change route attributes for the ones in the $attributes array.
560
     *
561
     * @param $attributes array Array of attributes
562
     * @param string $route string route to substitute
563
     *
564
     * @return string route with attributes changed
565
     */
566
    protected function substituteAttributesInRoute($attributes, $route)
567
    {
568
        foreach ($attributes as $key => $value) {
569
            $route = str_replace('{'.$key.'}', $value, $route);
570
            $route = str_replace('{'.$key.'?}', $value, $route);
571
        }
572
573
        // delete empty optional arguments that are not in the $attributes array
574
        $route = preg_replace('/\/{[^)]+\?}/', '', $route);
575
576
        return $route;
577
    }
578
579
    /**
580
     * Returns translated routes.
581
     *
582
     * @return array translated routes
583
     */
584
    protected function getTranslatedRoutes()
585
    {
586
        return $this->translatedRoutes;
587
    }
588
589
    /**
590
     * Set current route name.
591
     *
592
     * @param string $routeName current route name
593
     */
594
    public function setRouteName($routeName)
595
    {
596
        $this->routeName = $routeName;
597
    }
598
599
    /**
600
     * Translate routes and save them to the translated routes array (used in the localize route filter).
601
     *
602
     * @param string $routeName Key of the translated string
603
     *
604
     * @return string Translated string
605
     */
606
    public function transRoute($routeName)
607
    {
608
        if (!in_array($routeName, $this->translatedRoutes)) {
609
            $this->translatedRoutes[] = $routeName;
610
        }
611
612
        return $this->translator->trans($routeName);
613
    }
614
615
    /**
616
     * Returns the translation key for a given path.
617
     *
618
     * @param string $path Path to get the key translated
619
     *
620
     * @return string|false Key for translation, false if not exist
621
     */
622
    public function getRouteNameFromAPath($path)
623
    {
624
        $attributes = $this->extractAttributes($path);
625
626
        $path = str_replace(url('/'), '', $path);
627
        if ($path[0] !== '/') {
628
            $path = '/'.$path;
629
        }
630
        $path = str_replace('/'.$this->currentLocale.'/', '', $path);
631
        $path = trim($path, '/');
632
633
        foreach ($this->translatedRoutes as $route) {
634
            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...
635
                return $route;
636
            }
637
        }
638
639
        return false;
640
    }
641
642
    /**
643
     * Returns the translated route for the path and the url given.
644
     *
645
     * @param string $path       Path to check if it is a translated route
646
     * @param string $url_locale Language to check if the path exists
647
     *
648
     * @return string|false Key for translation, false if not exist
649
     */
650
    protected function findTranslatedRouteByPath($path, $url_locale)
651
    {
652
        // check if this url is a translated url
653
        foreach ($this->translatedRoutes as $translatedRoute) {
654
            if ($this->translator->trans($translatedRoute, [], $url_locale) == rawurldecode($path)) {
655
                return $translatedRoute;
656
            }
657
        }
658
659
        return false;
660
    }
661
662
    /**
663
     * Returns the translated route for an url and the attributes given and a locale.
664
     *
665
     *
666
     * @param string|false|null $url        Url to check if it is a translated route
667
     * @param array             $attributes Attributes to check if the url exists in the translated routes array
668
     * @param string            $locale     Language to check if the url exists
669
     *
670
     * @throws SupportedLocalesNotDefined
671
     * @throws UnsupportedLocaleException
672
     *
673
     * @return string|false Key for translation, false if not exist
674
     */
675
    protected function findTranslatedRouteByUrl($url, $attributes, $locale)
676
    {
677
        if (empty($url)) {
678
            return false;
679
        }
680
681
        // check if this url is a translated url
682
        foreach ($this->translatedRoutes as $translatedRoute) {
683
            $routeName = $this->getURLFromRouteNameTranslated($locale, $translatedRoute, $attributes);
684
685
            if ($this->getNonLocalizedURL($routeName) == $this->getNonLocalizedURL($url)) {
686
                return $translatedRoute;
687
            }
688
        }
689
690
        return false;
691
    }
692
693
    /**
694
     * Returns true if the string given is a valid url.
695
     *
696
     * @param string $url String to check if it is a valid url
697
     *
698
     * @return bool Is the string given a valid url?
699
     */
700
    protected function checkUrl($url)
701
    {
702
        return filter_var($url, FILTER_VALIDATE_URL);
703
    }
704
705
    /**
706
     * Returns the config repository for this instance.
707
     *
708
     * @return Repository Configuration repository
709
     */
710
    public function getConfigRepository()
711
    {
712
        return $this->configRepository;
713
    }
714
715
    /**
716
     * Returns the translation key for a given path.
717
     *
718
     * @return bool Returns value of useAcceptLanguageHeader in config.
719
     */
720
    protected function useAcceptLanguageHeader()
721
    {
722
        return $this->configRepository->get('laravellocalization.useAcceptLanguageHeader');
723
    }
724
725
    /**
726
     * Returns the translation key for a given path.
727
     *
728
     * @return bool Returns value of hideDefaultLocaleInURL in config.
729
     */
730
    public function hideDefaultLocaleInURL()
731
    {
732
        return $this->configRepository->get('laravellocalization.hideDefaultLocaleInURL');
733
    }
734
735
    /**
736
     * Create an url from the uri.
737
     *
738
     * @param string $uri Uri
739
     *
740
     * @return string Url for the given uri
741
     */
742
    public function createUrlFromUri($uri)
743
    {
744
        $uri = ltrim($uri, '/');
745
746
        if (empty($this->baseUrl)) {
747
            return app('url')->to($uri);
748
        }
749
750
        return $this->baseUrl.$uri;
751
    }
752
753
    /**
754
     * Sets the base url for the site.
755
     *
756
     * @param string $url Base url for the site
757
     */
758
    public function setBaseUrl($url)
759
    {
760
        if (substr($url, -1) != '/') {
761
            $url .= '/';
762
        }
763
764
        $this->baseUrl = $url;
765
    }
766
767
    /**
768
     * Extract attributes for current url.
769
     *
770
     * @param bool|false|null|string $url    to extract attributes, if not present, the system will look for attributes in the current call
771
     * @param string                 $locale
772
     *
773
     * @return array Array with attributes
774
     */
775
    protected function extractAttributes($url = false, $locale = '')
776
    {
777
        if (!empty($url)) {
778
            $attributes = [];
779
            $parse = parse_url($url);
780
            if (isset($parse['path'])) {
781
                $parse = explode('/', $parse['path']);
782
            } else {
783
                $parse = [];
784
            }
785
            $url = [];
786
            foreach ($parse as $segment) {
787
                if (!empty($segment)) {
788
                    $url[] = $segment;
789
                }
790
            }
791
792
            foreach ($this->router->getRoutes() as $route) {
793
                $path = method_exists($route, 'uri') ? $route->uri() : $route->getUri();
794
795
                if (!preg_match("/{[\w]+}/", $path)) {
796
                    continue;
797
                }
798
799
                $path = explode('/', $path);
800
                $i = 0;
801
802
                $match = true;
803
                foreach ($path as $j => $segment) {
804
                    if (isset($url[$i])) {
805
                        if ($segment === $url[$i]) {
806
                            $i++;
807
                            continue;
808
                        }
809
                        if (preg_match("/{[\w]+}/", $segment)) {
810
                            // must-have parameters
811
                            $attribute_name = preg_replace(['/}/', '/{/', "/\?/"], '', $segment);
812
                            $attributes[$attribute_name] = $url[$i];
813
                            $i++;
814
                            continue;
815
                        }
816
                        if (preg_match("/{[\w]+\?}/", $segment)) {
817
                            // optional parameters
818
                            if (!isset($path[$j + 1]) || $path[$j + 1] !== $url[$i]) {
819
                                // optional parameter taken
820
                                $attribute_name = preg_replace(['/}/', '/{/', "/\?/"], '', $segment);
821
                                $attributes[$attribute_name] = $url[$i];
822
                                $i++;
823
                                continue;
824
                            }
825
                        }
826
                    } elseif (!preg_match("/{[\w]+\?}/", $segment)) {
827
                        // no optional parameters but no more $url given
828
                        // this route does not match the url
829
                        $match = false;
830
                        break;
831
                    }
832
                }
833
834
                if (isset($url[$i + 1])) {
835
                    $match = false;
836
                }
837
838
                if ($match) {
839
                    return $attributes;
840
                }
841
            }
842
        } else {
843
            if (!$this->router->current()) {
844
                return [];
845
            }
846
847
            $attributes = $this->router->current()->parameters();
848
            $response = event('routes.translation', [$locale, $attributes]);
849
850
            if (!empty($response)) {
851
                $response = array_shift($response);
852
            }
853
854
            if (is_array($response)) {
855
                $attributes = array_merge($attributes, $response);
856
            }
857
        }
858
859
        return $attributes;
860
    }
861
862
    /**
863
     * Build URL using array data from parse_url.
864
     *
865
     * @param array|false $parsed_url Array of data from parse_url function
866
     *
867
     * @return string Returns URL as string.
868
     */
869
    protected function unparseUrl($parsed_url)
870
    {
871
        if (empty($parsed_url)) {
872
            return '';
873
        }
874
875
        $url = '';
876
        $url .= isset($parsed_url['scheme']) ? $parsed_url['scheme'].'://' : '';
877
        $url .= isset($parsed_url['host']) ? $parsed_url['host'] : '';
878
        $url .= isset($parsed_url['port']) ? ':'.$parsed_url['port'] : '';
879
        $user = isset($parsed_url['user']) ? $parsed_url['user'] : '';
880
        $pass = isset($parsed_url['pass']) ? ':'.$parsed_url['pass'] : '';
881
        $url .= $user.(($user || $pass) ? "$pass@" : '');
882
883
        if (!empty($url)) {
884
            $url .= isset($parsed_url['path']) ? '/'.ltrim($parsed_url['path'], '/') : '';
885
        } else {
886
            $url .= isset($parsed_url['path']) ? $parsed_url['path'] : '';
887
        }
888
889
        $url .= isset($parsed_url['query']) ? '?'.$parsed_url['query'] : '';
890
        $url .= isset($parsed_url['fragment']) ? '#'.$parsed_url['fragment'] : '';
891
892
        return $url;
893
    }
894
}
895