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

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