Laravelред рд╕реНрдерд╛рдиреАрдпрдХрд░рдг рд░реВрдЯрд┐рдВрдЧ

KDPV


рдирдорд╕реНрдХрд╛рд░, рд╣реЗрдмреНрд░!


рдпреБрдкреАрдбреА
рдЗрд╕ рд╕рдВрд╕рд╛рдзрди рдкрд░, рд▓реЗрдЦ рдХреА рдкреНрд░рд╛рд╕рдВрдЧрд┐рдХрддрд╛ рд╢реВрдиреНрдп рд╕реЗ рдПрдХ рдЯрд┐рдкреНрдкрдгреА рд╣реЛ рд╕рдХрддреА рд╣реИ ред рд▓реЗрдЦ рдореЗрдВ рд╡рд░реНрдгрд┐рдд рдХрд╛рд░реНрдп рдХреЛ рдорд╕реНрдХрд░рд╛ / рд▓рд╛рд░реНрд╡рд╛-рд╕реНрдерд╛рдиреАрдпрдХрд░рдг рдкреБрд╕реНрддрдХрд╛рд▓рдп рджреНрд╡рд╛рд░рд╛ рдХрдо рджрд░реНрдж рдХреЗ рд╕рд╛рде рд╣рд▓ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
рдЯрд┐рдк DExploN рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж!

рдХреИрдЯ рдиреЗ рдЙрдард╛рдпрд╛ред рд╢реВрдиреНрдп рд╕реЗ рдЧреБрдгрд╛ рдиреАрдЪреЗ рд╣реИред

рдореИрдВ рдЖрдкрдХреЛ рдЗрд╕ рдмрд╛рд░реЗ рдореЗрдВ рдмрддрд╛рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдХрд┐ рдХреИрд╕реЗ рдПрдХ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдореЗрдВ рд░реВрдЯрд┐рдВрдЧ рдХреЗ рд╕рд╛рде рдПрдХ рд╕рдорд╕реНрдпрд╛ рдереА рдФрд░ рд╣рдордиреЗ рдЗрд╕реЗ рдХреИрд╕реЗ рд╣рд▓ рдХрд┐рдпрд╛ред


рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдорд╛рд░реА рдкрд░рд┐рдпреЛрдЬрдирд╛ рд╕рдмрд╕реЗ рдЖрдо рд╕рд╛рдЗрдЯ рдереАред рд╕рд╛рдЗрдЯ рд╡рд┐рдХрд╕рд┐рдд рд╣реЛ рд░рд╣реА рдереА, рджрд░реНрд╢рдХреЛрдВ рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░ рд╣реЛ рд░рд╣рд╛ рдерд╛, рдФрд░ рдЖрд╡рд╢реНрдпрдХрддрд╛ рдмрд╣реБрднрд╛рд╖рд┐рдХрддрд╛ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдиреЗ рдХреА рдереАред рдпрд╣ рдкрд░рд┐рдпреЛрдЬрдирд╛ рд▓рд╛рд░рд╡реЗрд▓ рдврд╛рдВрдЪреЗ рдкрд░ рдЖрдзрд╛рд░рд┐рдд рдереА рдФрд░ рдмрд╣реБрднрд╛рд╖рд╛рд╡рд╛рдж рдХреЗ рд╕рд╛рде рдХреЛрдИ рд╕рдорд╕реНрдпрд╛ рдирд╣реАрдВ рдереА (рд╕рддреНрд░ рд╕реЗ рд╡рд╛рдВрдЫрд┐рдд рднрд╛рд╖рд╛ рдЦреАрдВрдЪреА рдЧрдИ рдереА, рдпрд╛ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдХреЛ рд▓рд┐рдпрд╛ рдЧрдпрд╛ рдерд╛)ред рд╣рдордиреЗ рд╣рд╛рд░реНрдбрдХреЛрдб рдХрд┐рдП рдЧрдП рд╡рд╛рдХреНрдпрд╛рдВрд╢реЛрдВ рдХреЗ рдмрдЬрд╛рдп рдЕрдиреБрд╡рд╛рдж, рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдЕрдиреБрд╡рд╛рдж рдХреБрдВрдЬрд┐рдпрд╛рдВ рд▓рд┐рдЦреАрдВ, рдФрд░ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╡рд┐рд╢реЗрд╖рддрд╛рдПрдВ рд▓реАрдВред


рд╕рдорд╕реНрдпрд╛


рдХреБрдЫ рдмрд┐рдВрджреБ рдкрд░, рдПрд╕рдИрдУ рдЯреАрдо рдиреЗ рдорд╣рд╕реВрд╕ рдХрд┐рдпрд╛ рдХрд┐ рдпрд╣ рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╕рд╛рдЗрдЯ рдХреА рд░реИрдВрдХрд┐рдВрдЧ рдореЗрдВ рд╣рд╕реНрддрдХреНрд╖реЗрдк рдХрд░рддрд╛ рд╣реИред рддрдм рд╡рд┐рдХрд╛рд╕ рдЯреАрдо рдХреЛ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рднрд╛рд╖рд╛ рдХреЛ рдЫреЛрдбрд╝рдХрд░, URL рдореЗрдВ рднрд╛рд╖рд╛ рд╕рдмрдлрд╝реЛрд▓реНрдбрд░ рдЬреЛрдбрд╝рдиреЗ рдХреА рдЖрдЬреНрдЮрд╛ рдорд┐рд▓реАред рд╣рдорд╛рд░реЗ рдорд╛рд░реНрдЧреЛрдВ рдиреЗ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдлреЙрд░реНрдо рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд▓рд┐рдпрд╛:


рдкреЗрдЬрд░реВрдЯ рдЖрд░рдпреВ (рдбрд┐рдлрд╝реЙрд▓реНрдЯ рднрд╛рд╖рд╛)рдорд╛рд░реНрдЧ рдПрдирд░рд╛рдЙрдд рдлреНрд░
рд╣рдорд╛рд░реЗ рдмрд╛рд░реЗ рдореЗрдВ/o-nas/en/about-us/fr/a-propos-de-nous
рд╕рдВрдкрд░реНрдХ рд╡рд┐рд╡рд░рдг/kontakty/en/contacts/fr/coordonnees
рд╕рдорд╛рдЪрд╛рд░/novosti/en/news/fr/les-nouvelles

рд╕рдм рдХреБрдЫ рдЬрдЧрд╣ рдореЗрдВ рдЧрд┐рд░ рдЧрдпрд╛ рдФрд░ рд╣рдордиреЗ рдлрд┐рд░ рд╕реЗ рдирдИ рд╕реБрд╡рд┐рдзрд╛рдУрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд┐рдпрд╛ред
рдереЛрдбрд╝реА рджреЗрд░ рдмрд╛рдж, рдХрдИ рдбреЛрдореЗрди рдкрд░ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рддреИрдирд╛рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдереАред рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░, рдЗрди рд╕рд╛рдЗрдЯреЛрдВ рдореЗрдВ рдПрдХ рдбреЗрдЯрд╛рдмреЗрд╕ рд╣реЛрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдХреБрдЫ рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдбреЛрдореЗрди рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рднрд┐рдиреНрди рд╣реЛ рд╕рдХрддреА рд╣реИрдВред
рдХреБрдЫ рд╕рд╛рдЗрдЯреЗрдВ рдмрд╣реБрднрд╛рд╖реА рд╣реЛ рд╕рдХрддреА рд╣реИрдВ (рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рднрд╛рд╖рд╛рдУрдВ рдХреЗ рдПрдХ рд╕реАрдорд┐рдд рд╕реЗрдЯ рдХреЗ рд╕рд╛рде, рдФрд░ рд╕рднреА рд╕рдорд░реНрдерд┐рдд рд▓реЛрдЧреЛрдВ рдХреЗ рд╕рд╛рде рдирд╣реАрдВ), рдХреБрдЫ - рдХреЗрд╡рд▓ рдПрдХ рднрд╛рд╖рд╛ред


рдпрд╣ рдПрдХ рдЖрд╡реЗрджрди рдХреЗ рд╕рд╛рде рд╕рднреА рдбреЛрдореЗрди рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓рд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ (nginx рд╕рднреА рдбреЛрдореЗрди рдХреЛ рдПрдХ рдЕрдкрд╕реНрдЯреНрд░реАрдо рдореЗрдВ рд╕рдореАрдк рдХрд░рддрд╛ рд╣реИ)ред


рдХрд┐рд╕реА рд╡рд┐рд╢реЗрд╖ рд╕рд╛рдЗрдЯ рджреНрд╡рд╛рд░рд╛ рд╕рдорд░реНрдерд┐рдд рднрд╛рд╖рд╛рдУрдВ рдХреЗ рд╕реЗрдЯ рдФрд░ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рднрд╛рд╖рд╛ рдХреЛ рд╡реНрдпрд╡рд╕реНрдерд╛рдкрдХ рдкреИрдирд▓ рдореЗрдВ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП, рдЬреЛ рдХрд┐ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ / рдПрдирд╡реА рдЪрд░ рдХреЗ рд╣реИрдХ рдХрд┐рдП рдЧрдП рд╕рдВрд╕реНрдХрд░рдг рдХреА рдЬрдбрд╝ рд╣реИред рдпрд╣ рд╕реНрдкрд╖реНрдЯ рд╣реЛ рдЧрдпрд╛ рдХрд┐ рд╡рд░реНрддрдорд╛рди рд╕рдорд╛рдзрд╛рди рд╣рдорд╛рд░реА рд╡рд┐рд╢рд▓рд┐рд╕реНрдЯ рдХреЛ рд╕рдВрддреБрд╖реНрдЯ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред


рдирд┐рд░реНрдгрдп


рддрд╕реНрд╡реАрд░ рдХреЛ рд╕рд░рд▓ рдмрдирд╛рдиреЗ рдФрд░ рд╕рдорд╛рдзрд╛рди рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рд▓рд╛рд░реНрд╡рд╛рд▓ рд╕рдВрд╕реНрдХрд░рдг 6.2 рдкрд░ рдПрдХ рдирдИ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЛ рддреИрдирд╛рдд рдХрд┐рдпрд╛ рдФрд░ рдбреЗрдЯрд╛рдмреЗрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рд╕реЗ рдЗрдирдХрд╛рд░ рдХрд░ рджрд┐рдпрд╛ред рд╕рдВрд╕реНрдХрд░рдг 5.x рдореЗрдВ, рдЕрдВрддрд░ рдорд╛рдореВрд▓реА рд╣реИрдВ (рд▓реЗрдХрд┐рди рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдореИрдВ рдЙрдиреНрд╣реЗрдВ рдЪрд┐рддреНрд░рд┐рдд рдирд╣реАрдВ рдХрд░реВрдВрдЧрд╛)ред

GitHub рдкрд░ рдЙрдкрд▓рдмреНрдз рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдХреЛрдб

рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдореЗрдВ рд╕рднреА рд╕рдорд░реНрдерд┐рдд рднрд╛рд╖рд╛рдУрдВ рдореЗрдВ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдореЗрдВ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред


config / app.php
 <?php return [ // ... 'locale' => 'en', 'fallback_locale' => 'en', 'supported_locales' => [ 'en', 'ru', 'de', 'fr', ], // ... ]; 

рд╣рдореЗрдВ рд╕рд╛рдЗрдЯ рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдХрд╛ рдирд┐рд░реНрдзрд╛рд░рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП Site рд╕рд╛рдЗрдЯ рдХрд╛ рд╕рд╛рд░ рдФрд░ рд╕реЗрд╡рд╛ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред


app / рд╕рдВрд╕реНрдерд╛рдУрдВ / Site.php
 <?php declare(strict_types=1); namespace App\Entities; class Site { /** * @var string   */ private $domain; /** * @var string    */ private $defaultLanguage; /** * @var string[]    */ private $supportedLanguages = []; /** * @param string $domain  * @param string $defaultLanguage    * @param string[] $supportedLanguages    */ public function __construct(string $domain, string $defaultLanguage, array $supportedLanguages) { $this->domain = $domain; $this->defaultLanguage = $defaultLanguage; if (!in_array($defaultLanguage, $supportedLanguages)) { $supportedLanguages[] = $defaultLanguage; } $this->supportedLanguages = $supportedLanguages; } /** *    * * @return string */ public function getDomain(): string { return $this->domain; } /** *       * * @return string */ public function getDefaultLanguage(): string { return $this->defaultLanguage; } /** *      * * @return string[] */ public function getSupportedLanguages(): array { return $this->supportedLanguages; } /** *     * * @param string $language * @return bool */ public function isLanguageSupported(string $language): bool { return in_array($language, $this->supportedLanguages); } /** * ,      * * @param string $language * @return bool */ public function isLanguageDefault(string $language): bool { return $language === $this->defaultLanguage; } } 

рдПрдкреНрд▓рд┐рдХреЗрд╢рди / рдЕрдиреБрдмрдВрдз / SiteDetector.php
 <?php declare(strict_types=1); namespace App\Contracts; use App\Entities\Site; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; interface SiteDetector { /** *     * * @param string $host  * * @return Site   * * @throws NotFoundHttpException     */ public function detect(string $host): Site; } 

app / Services / SiteDetector / FakeSiteDetector.php
 <?php declare(strict_types=1); namespace App\Services\SiteDetector; use App\Contracts\SiteDetector; use App\Entities\Site; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** *      . *       ,      . */ class FakeSiteDetector implements SiteDetector { /** * @var Site[]  */ private $sites; public function __construct() { $sites = [ 'localhost' => [ //   'default' => 'en', 'support' => ['ru', 'de', 'fr'], ], 'site-all.local' => [ //   'default' => 'en', 'support' => ['ru', 'de', 'fr'], ], 'site-ru.local' => [ //   'default' => 'ru', 'support' => [], ], 'site-en.local' => [ 'default' => 'en', //   'support' => [], ], 'site-de.local' => [ 'default' => 'de', //   'support' => [], ], 'site-fr.local' => [ 'default' => 'fr', //   'support' => [], ], 'site-eur.local' => [ //    'default' => 'de', 'support' => ['fr'], ], ]; foreach ($sites as $domain => $site) { $default = $site['default']; $support = array_merge([$default], $site['support']); $this->sites[$domain] = new Site($domain, $default, $support); } } public function detect(string $host): Site { $host = trim(mb_strtolower($host)); if (!array_key_exists($host, $this->sites)) { throw new NotFoundHttpException(); } return $this->sites[$host]; } } 

рдХрдВрдЯреЗрдирд░ рдореЗрдВ рд╣рдорд╛рд░реА рд╕реЗрд╡рд╛ рдЬреЛрдбрд╝реЗрдВ


рдПрдкреНрд▓рд┐рдХреЗрд╢рди / рдкреНрд░рджрд╛рддрд╛ / AppServiceProvider.php
 <?php namespace App\Providers; use App\Contracts\SiteDetector; use App\Services\SiteDetector\FakeSiteDetector; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider { // ... /** * Register any application services. * * @return void */ public function register() { // ... /* *  . */ $this->app->singleton(FakeSiteDetector::class, function () { return new FakeSiteDetector(); }); /* *   */ $this->app->bind(SiteDetector::class, FakeSiteDetector::class); // ... } // ... } 

рдЕрдм рдорд╛рд░реНрдЧреЛрдВ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░реЗрдВред


рдорд╛рд░реНрдЧреЛрдВ / web.php
 <?php // ... Route::get('/', 'DemoController@home')->name('web.home'); Route::get('/--about--', 'DemoController@about')->name('web.about'); Route::get('/--contacts--', 'DemoController@contacts')->name('web.contacts'); Route::get('/--news--', 'DemoController@news')->name('web.news'); // ... 

рд╕реНрдерд╛рдиреАрдпрдХреГрдд рдХрд┐рдП рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рдорд╛рд░реНрдЧреЛрдВ рдХреЗ рд╣рд┐рд╕реНрд╕реЛрдВ рдХреЛ рджреЛрд╣рд░реЗ minuses ( -- ) рджреНрд╡рд╛рд░рд╛ рддреИрдпрд╛рд░ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред рдпреЗ рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрди рдХреЗ рд▓рд┐рдП рдореБрдЦреМрдЯреЗ рд╣реИрдВред рдЕрдм рдЗрди рдорд╛рд╕реНрдХ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░реЗрдВред


config / рдорд╛рд░реНрдЧреЛрдВ .php
 <?php return [ 'web.about' => [ //   'about' => [ //     'de' => 'uber-uns', //  =>  'en' => 'about-us', 'fr' => 'a-propos-de-nous', 'ru' => 'o-nas', ], ], 'web.news' => [ 'news' => [ 'de' => 'nachrichten', 'en' => 'news', 'fr' => 'nouvelles', 'ru' => 'novosti', ], ], 'web.contacts' => [ 'contacts' => [ 'de' => 'kontakte', 'en' => 'contacts', 'fr' => 'contacts', 'ru' => 'kontakty', ], ], ]; 

рднрд╛рд╖рд╛ рдЪрдпрди рдШрдЯрдХ рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдХреЗрд╡рд▓ рдЙрди рднрд╛рд╖рд╛рдУрдВ рдХреЛ рдЯреЗрдореНрдкрд▓реЗрдЯ рдореЗрдВ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛ рдЬреЛ рд╕рд╛рдЗрдЯ рджреНрд╡рд╛рд░рд╛ рд╕рдорд░реНрдерд┐рдд рд╣реИрдВред рдЖрдЗрдП рдЗрд╕рдХреЗ рд▓рд┐рдП рдПрдХ рдорд┐рдбрд▓рд╡реЗрдпрд░ рд▓рд┐рдЦреЗрдВ ...


Http / рдорд┐рдбрд▓рд╡реЗрдпрд░ / ViewData.php
 <?php namespace App\Http\Middleware; use App\Contracts\SiteDetector; use Closure; use Illuminate\Contracts\View\Factory as ViewFactory; use Illuminate\Contracts\View\View; use Illuminate\Http\Request; class ViewData { /** * @var ViewFactory */ private $view; /** * @var SiteDetector */ private $detector; public function __construct(ViewFactory $view, SiteDetector $detector) { $this->view = $view; $this->detector = $detector; } public function handle(Request $request, Closure $next) { /* *   */ $site = $this->detector->detect($request->getHost()); /* *        */ $languages = []; foreach ($site->getSupportedLanguages() as $language) { $url = '/'; if (!$site->isLanguageDefault($language)) { $url .= $language; } $languages[$language] = $url; } $this->view->composer(['components/languages'], function(View $view) use ($languages) { $view->with('languages', $languages); }); return $next($request); } } 

рдЕрдм рдЖрдкрдХреЛ рд░рд╛рдЙрдЯрд░ рдХреЛ рдХрд╕реНрдЯрдорд╛рдЗрдЬрд╝ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдмрд▓реНрдХрд┐, рд░рд╛рдЙрдЯрд░ рд╣реА рдирд╣реАрдВ, рдмрд▓реНрдХрд┐ рдорд╛рд░реНрдЧреЛрдВ рдХрд╛ рдПрдХ рд╕рдВрдЧреНрд░рд╣ ...


рдПрдкреНрд▓рд┐рдХреЗрд╢рди / рдХрд╕реНрдЯрдо / рдкреНрд░рдмреБрджреНрдз / рд░реВрдЯрд┐рдВрдЧ / RouteCollection.php
 <?php namespace App\Custom\Illuminate\Routing; use Illuminate\Routing\Route; use Illuminate\Routing\RouteCollection as BaseRouteCollection; use Serializable; class RouteCollection extends BaseRouteCollection implements Serializable { /** * @var array   . */ private $config; private $localized = []; public function setConfig(array $config) { $this->config = $config; } /** *    . * * @param string $language  */ public function localize(string $language) { $this->flushLocalizedRoutes(); foreach ($this->config as $name => $placeholders) { if (!$this->hasNamedRoute($name) || empty($placeholders)) { continue; } /* *    */ $route = $this->getByName($name); /* *  */ $this->localized[$name] = $route; /* *     */ $this->removeRoute($route); /* *   */ $new = clone $route; $uri = $new->uri(); foreach ($placeholders as $placeholder => $paths) { if (!array_key_exists($language, $paths)) { continue; } $value = $paths[$language]; $uri = str_replace('--' . $placeholder . '--', $value, $uri); } $new->setUri($uri); $this->add($new); } /* *   */ $this->refreshNameLookups(); $this->refreshActionLookups(); } private function removeRoute(Route $route) { $uri = $route->uri(); $domainAndUri = $route->getDomain().$uri; foreach ($route->methods() as $method) { $key = $method.$domainAndUri; if (array_key_exists($key, $this->allRoutes)) { unset($this->allRoutes[$key]); } if (array_key_exists($uri, $this->routes[$method])) { unset($this->routes[$method][$uri]); } } } private function flushLocalizedRoutes() { foreach ($this->localized as $name => $route) { /* *    */ $old = $this->getByName($name); /* *     */ $this->removeRoute($old); /* *   */ $this->add($route); } } /** * @inheritDoc */ public function serialize() { return serialize([ 'routes' => $this->routes, 'allRoutes' => $this->allRoutes, 'nameList' => $this->nameList, 'actionList' => $this->actionList, ]); } /** * @inheritDoc */ public function unserialize($serialized) { $data = unserialize($serialized); $this->routes = $data['routes']; $this->allRoutes = $data['allRoutes']; $this->nameList = $data['nameList']; $this->actionList = $data['actionList']; } } 

..., рдЖрд╡реЗрджрди рдХрд╛ рдореБрдЦреНрдп рд╡рд░реНрдЧ ...


рдПрдкреНрд▓рд┐рдХреЗрд╢рди / рдХрд╕реНрдЯрдо / рдкреНрд░рдмреБрджреНрдз / рдлрд╛рдЙрдВрдбреЗрд╢рди / Application.php
 <?php namespace App\Custom\Illuminate\Foundation; use App\Custom\Illuminate\Routing\RouteCollection; use App\Exceptions\UnsupportedLocaleException; use Illuminate\Contracts\Config\Repository; use Illuminate\Foundation\Application as BaseApplication; use Illuminate\Routing\UrlGenerator; class Application extends BaseApplication { private $isLocaleEstablished = false; private $cachedRoutes = []; public function __construct($basePath = null) { parent::__construct($basePath); } public function setLocale($locale) { /* *       ,  . */ if ($this->getLocale() === $locale && $this->isLocaleEstablished) { return; } /** @var Repository $config */ $config = $this->get('config'); $urlGenerator = $this->get('url'); $defaultLocale = $config->get('app.fallback_locale'); $supportedLocales = $config->get('app.supported_locales'); /* *     */ if (!in_array($locale, $supportedLocales)) { throw new UnsupportedLocaleException(); } /* *         */ if ($defaultLocale !== $locale && $urlGenerator instanceof UrlGenerator) { $request = $urlGenerator->getRequest(); $rootUrl = $request->getSchemeAndHttpHost() . '/' . $locale; $urlGenerator->forceRootUrl($rootUrl); } /* *      */ parent::setLocale($locale); /* *     */ if (array_key_exists($locale, $this->cachedRoutes)) { $fn = $this->cachedRoutes[$locale]; $this->get('router')->setRoutes($fn()); } else { $this->get('router')->getRoutes()->localize($locale); } $this->isLocaleEstablished = true; } public function bootstrapWith(array $bootstrappers) { parent::bootstrapWith($bootstrappers); /** *         *       * * @var RouteCollection $routes */ $routes = $this->get('router')->getRoutes(); $routes->setConfig($this->get('config')->get('routes')); if ($this->routesAreCached()) { /** @noinspection PhpIncludeInspection */ $this->cachedRoutes = require $this->getCachedRoutesPath(); } $this->setLocale($this->getLocale()); } } 

... рдФрд░ рд╣рдорд╛рд░реЗ рдХрд╕реНрдЯрдо рдХрдХреНрд╖рд╛рдУрдВ рдХреЛ рдмрджрд▓реЗрдВред


рдмреВрдЯрд╕реНрдЯреНрд░реИрдк / app.php
 <?php // $app = new Illuminate\Foundation\Application($_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)); $app = new App\Custom\Illuminate\Foundation\Application($_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)); $app->get('router')->setRoutes(new App\Custom\Illuminate\Routing\RouteCollection()); // ... 

рдЕрдЧрд▓рд╛ рдХрджрдо URL рдкрддреЗ рдХреЗ рдкрд╣рд▓реЗ рднрд╛рдЧ рд╕реЗ рднрд╛рд╖рд╛ рдХреЛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдирд╛ рд╣реИред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдкреНрд░реЗрд╖рдг рд╕реЗ рдкрд╣рд▓реЗ, рд╣рдо рдЗрд╕рдХрд╛ рдкрд╣рд▓рд╛ рдЦрдВрдб рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВрдЧреЗ, рдЗрд╕ рддрд░рд╣ рдХреА рднрд╛рд╖рд╛ рдХреЗ рд▓рд┐рдП рд╕рд╛рдЗрдЯ рдХреЗ рд╕рдорд░реНрдерди рдХреА рдЬрд╛рдБрдЪ рдХрд░реЗрдВ, рдФрд░ рдЗрд╕ рдЦрдВрдб рдХреЗ рдмрд┐рдирд╛ рдПрдХ рдирдП рдЕрдиреБрд░реЛрдз рдХреЗ рд╕рд╛рде рднреЗрдЬрдирд╛ рд╢реБрд░реВ рдХрд░реЗрдВред рдЖрдЗрдП рдХреНрд▓рд╛рд╕ App\Http\Kernel рдереЛрдбрд╝рд╛ рдареАрдХ рдХрд░реЗрдВ, рдФрд░ рдПрдХ рд╣реА рд╕рдордп рдореЗрдВ рд╣рдорд╛рд░реЗ рдорд┐рдбрд▓рд╡реЗрдпрд░ App\Http\Middleware\ViewData рдХреЛ web рд╕рдореВрд╣ рдореЗрдВ рдЬреЛрдбрд╝реЗрдВ


app / Http / рдХрд░реНрдиреЗрд▓.php
 <?php namespace App\Http; // ... use App\Contracts\SiteDetector; use App\Http\Middleware\ViewData; use Closure; use Illuminate\Foundation\Http\Kernel as HttpKernel; use Illuminate\Http\Request; // ... class Kernel extends HttpKernel { // ... /** * The application's route middleware groups. * * @var array */ protected $middlewareGroups = [ // ... 'web' => [ // ... ViewData::class, ], // ... ]; // ... /** * Get the route dispatcher callback. * * @return Closure */ protected function dispatchToRouter() { return function (Request $request) { /* *   */ /** @var SiteDetector $siteDetector */ $siteDetector = $this->app->get(SiteDetector::class); $site = $siteDetector->detect($request->getHost()); /* *     */ $segment = (string)$request->segment(1); /* *           ,    */ if ($segment && $site->isLanguageSupported($segment)) { $language = $segment; } else { $language = $site->getDefaultLanguage(); } /* *      */ $this->app->get('config')->set('app.supported_locales', $site->getSupportedLanguages()); /* *      */ $this->app->get('config')->set('app.fallback_locale', $site->getDefaultLanguage()); /* *    */ $this->app->setLocale($language); /* *           */ if (!$site->isLanguageDefault($language)) { /* *      . */ $server = $request->server(); $server['REQUEST_URI'] = mb_substr($server['REQUEST_URI'], mb_strlen($language) + 1); $request = $request->duplicate( $request->query->all(), $request->all(), $request->attributes->all(), $request->cookies->all(), $request->files->all(), $server ); } /* *   */ $this->app->instance('request', $request); return $this->router->dispatch($request); }; } } 

рдпрджрд┐ рдЖрдк рдорд╛рд░реНрдЧреЛрдВ рдХреЛ рдХреИрд╢ рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдЖрдк рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдХрд╛рдо рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд▓реЗрдХрд┐рди рдХреИрд╢ рдХреЗ рдмрд┐рдирд╛ рд▓рдбрд╝рд╛рдИ рдореЗрдВ, рд╡рд┐рдЪрд╛рд░ рд╕рдмрд╕реЗ рдЕрдЪреНрдЫреЗ рдореЗрдВ рд╕реЗ рдПрдХ рдирд╣реАрдВ рд╣реИред рд╣рдордиреЗ рдЕрдкрдиреЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдХреИрд╢ рд╕реЗ рд░реВрдЯ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд╣рд▓реЗ рд╣реА рд╕рд┐рдЦрд╛ рджрд┐рдпрд╛ рд╣реИ, рдЕрдм рд╣рдореЗрдВ рдпрд╣ рд╕рд┐рдЦрд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдХрд┐ рдЗрд╕реЗ рд╕рд╣реА рддрд░реАрдХреЗ рд╕реЗ рдХреИрд╕реЗ рдмрдЪрд╛рдпрд╛ рдЬрд╛рдПред рдХрдВрд╕реЛрд▓ рдХрдорд╛рдВрдб route:cache рдХрд╕реНрдЯрдорд╛рдЗрдЬрд╝ рдХрд░реЗрдВ route:cache


рдПрдкреНрд▓рд┐рдХреЗрд╢рди / рдХрд╕реНрдЯрдо / рдкреНрд░рдмреБрджреНрдз / рдлрд╛рдЙрдВрдбреЗрд╢рди / рдХрдВрд╕реЛрд▓ / рд░реВрдЯрдЪреЗрдХрдХрдорд╛рдВрдбред рдПрдлрдкреА
 <?php declare(strict_types=1); namespace App\Custom\Illuminate\Foundation\Console; use App\Custom\Illuminate\Routing\RouteCollection as CustomRouteCollection; use Illuminate\Routing\Route; use Illuminate\Routing\RouteCollection; use Illuminate\Foundation\Console\RouteCacheCommand as BaseCommand; class RouteCacheCommand extends BaseCommand { /** * Execute the console command. * * @return void */ public function handle() { /* *     */ $this->call('route:clear'); /* *     */ $routes = $this->getFreshApplicationRoutes(); if (count($routes) === 0) { $this->error("Your application doesn't have any routes."); return; } /* *     */ $this->files->put( $this->laravel->getCachedRoutesPath(), $this->buildRouteCacheFile($routes) ); $this->info('Routes cached successfully!'); return; } protected function buildRouteCacheFile(RouteCollection $base) { /* *        . * *   - ,  - ,    Illuminate\Routing\RouteCollection */ $code = '<?php' . PHP_EOL . PHP_EOL; $code .= 'return [' . PHP_EOL; $stub = ' \'{{key}}\' => function() {return unserialize(base64_decode(\'{{routes}}\'));},'; foreach (config('app.supported_locales') as $locale) { /** @var CustomRouteCollection|Route[] $routes */ $routes = clone $base; $routes->localize($locale); foreach ($routes as $route) { $route->prepareForSerialization(); } $line = str_replace('{{routes}}', base64_encode(serialize($routes)), $stub); $line = str_replace('{{key}}', $locale, $line); $code .= $line . PHP_EOL; } $code .= '];' . PHP_EOL; return $code; } } 

route:clear рдХрдорд╛рдВрдб рдХреЗрд╡рд▓ рдХреИрд╢ рдлрд╝рд╛рдЗрд▓ рдХреЛ рд╣рдЯрд╛ рджреЗрддреА рд╣реИ, рд╣рдордиреЗ рдЗрд╕реЗ рдирд╣реАрдВ рдЫреБрдЖ рд╣реИред рд▓реЗрдХрд┐рди route:list рдЖрджреЗрд╢ рдЕрдм locale рд╡рд┐рдХрд▓реНрдк рдХреЗ рд╕рд╛рде рд╣рд╕реНрддрдХреНрд╖реЗрдк рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред


рдПрдкреНрд▓рд┐рдХреЗрд╢рди / рдХрд╕реНрдЯрдо / рдкреНрд░рдмреБрджреНрдз / рдлрд╛рдЙрдВрдбреЗрд╢рди / рдХрдВрд╕реЛрд▓ / рд░реВрдЯрд▓рд┐рд╕реНрдЯрд╕реНрдЯреИрдВрдбреИрдВрдбред рдПрдлрдкреА
 <?php declare(strict_types=1); namespace App\Custom\Illuminate\Foundation\Console; use Illuminate\Foundation\Console\RouteListCommand as BaseCommand; use Symfony\Component\Console\Input\InputOption; class RouteListCommand extends BaseCommand { /** * Execute the console command. * * @return void */ public function handle() { $locales = $this->option('locale'); /* *       */ foreach ($locales as $locale) { if ($locale && in_array($locale, config('app.supported_locales'))) { $this->output->title($locale); $this->laravel->setLocale($locale); $this->router = $this->laravel->get('router'); parent::handle(); } } } protected function getOptions() { /* *     */ $all = config('app.supported_locales'); /* *     */ $result = parent::getOptions(); /* *    */ $result[] = ['locale', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Locales', $all]; return $result; } } 

рдЕрдм рд╣рдореЗрдВ рдЗрди рдХрдорд╛рдВрдбреЛрдВ рдХреЛ рдХрд╛рдо рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдЕрдм рд╡реЗрдВрдбрд░ рдЯреАрдореЗрдВ рдХрд╛рдо рдХрд░реЗрдВрдЧреАред рдХрдВрд╕реЛрд▓ рдХрдорд╛рдВрдб рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЛ рдмрджрд▓рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдЙрд╕ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ рдПрдХ рд╕реЗрд╡рд╛ рдкреНрд░рджрд╛рддрд╛ рдХреЛ рд╢рд╛рдорд┐рд▓ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ рдЬреЛ Illuminate\Contracts\Support\DeferrableProvider ред provides() рд╡рд┐рдзрд┐ рдЖрджреЗрд╢реЛрдВ рдХреЗ рд╡рд░реНрдЧреЛрдВ рдХреЗ рдЕрдиреБрд░реВрдк рдХрдВрдЯреЗрдирд░ рдХреБрдВрдЬрд┐рдпреЛрдВ рдХреА рдПрдХ рд╕рд░рдгреА рд▓реМрдЯрдирд╛ рдЪрд╛рд╣рд┐рдПред


рдПрдкреНрд▓рд┐рдХреЗрд╢рди / рдкреНрд░рджрд╛рддрд╛ / CommandsReplaceProvider.php
 <?php declare(strict_types=1); namespace App\Providers; use App\Custom\Illuminate\Foundation\Console\RouteCacheCommand; use App\Custom\Illuminate\Foundation\Console\RouteListCommand; use Illuminate\Contracts\Foundation\Application; use Illuminate\Contracts\Support\DeferrableProvider; use Illuminate\Support\ServiceProvider; class CommandsReplaceProvider extends ServiceProvider implements DeferrableProvider { /** * Register any application services. * * @return void */ public function register() { $this->app->singleton('command.route.cache', function (Application $app) { return new RouteCacheCommand($app->get('files')); }); $this->app->singleton('command.route.list', function (Application $app) { return new RouteListCommand($app->get('router')); }); $this->commands($this->provides()); } public function provides() { return [ 'command.route.cache', 'command.route.list', ]; } } 

рдФрд░ рд╣рд╛рдВ, рд╣рдо рдкреНрд░рджрд╛рддрд╛ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдореЗрдВ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВред


config / app.php
 <?php return [ // ... 'providers' => [ App\Providers\CommandsReplaceProvider::class, ], // ... ]; 

рдЕрдм рд╕рдм рдХреБрдЫ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ!


 user@host laravel-localized-routing $ ./artisan route:list en == +--------+----------+----------+--------------+-------------------------+------------+ | Domain | Method | URI | Name | Action | Middleware | +--------+----------+----------+--------------+-------------------------+------------+ | | GET|HEAD | / | web.home | DemoController@home | web | | | GET|HEAD | about-us | web.about | DemoController@about | web | | | GET|HEAD | contacts | web.contacts | DemoController@contacts | web | | | GET|HEAD | news | web.news | DemoController@news | web | +--------+----------+----------+--------------+-------------------------+------------+ ru == +--------+----------+----------+--------------+-------------------------+------------+ | Domain | Method | URI | Name | Action | Middleware | +--------+----------+----------+--------------+-------------------------+------------+ | | GET|HEAD | / | web.home | DemoController@home | web | | | GET|HEAD | kontakty | web.contacts | DemoController@contacts | web | | | GET|HEAD | novosti | web.news | DemoController@news | web | | | GET|HEAD | o-nas | web.about | DemoController@about | web | +--------+----------+----------+--------------+-------------------------+------------+ de == +--------+----------+-------------+--------------+-------------------------+------------+ | Domain | Method | URI | Name | Action | Middleware | +--------+----------+-------------+--------------+-------------------------+------------+ | | GET|HEAD | / | web.home | DemoController@home | web | | | GET|HEAD | kontakte | web.contacts | DemoController@contacts | web | | | GET|HEAD | nachrichten | web.news | DemoController@news | web | | | GET|HEAD | uber-uns | web.about | DemoController@about | web | +--------+----------+-------------+--------------+-------------------------+------------+ fr == +--------+----------+------------------+--------------+-------------------------+------------+ | Domain | Method | URI | Name | Action | Middleware | +--------+----------+------------------+--------------+-------------------------+------------+ | | GET|HEAD | / | web.home | DemoController@home | web | | | GET|HEAD | a-propos-de-nous | web.about | DemoController@about | web | | | GET|HEAD | contacts | web.contacts | DemoController@contacts | web | | | GET|HEAD | nouvelles | web.news | DemoController@news | web | +--------+----------+------------------+--------------+-------------------------+------------+ 

рд╡рд╣ рд╕рдм рд╣реИред рдЖрдкрдХрд╛ рдзреНрдпрд╛рди рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж!

Source: https://habr.com/ru/post/hi481726/


All Articles