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 (#363)
by
unknown
02:03
created

LaravelLocalization::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 19
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

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