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:45
created

LaravelLocalization::getLocalizedNative()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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