2016-01-20 43 views
2

我有一個網站已被本地化爲幾種語言。每條公共路線都以區域設置密鑰(例如/{locale}/foo/bar)爲前綴,由中間件捕獲並應用。生成的URL中的路由參數的默認值

當生成的URL指向其他網頁,我最終需要當前區域送入每個URL,就像這樣:

<a href={{ route('foo.bar', ['locale' => app()->getLocale()]) }}">Foo Bar</a> 

否則輸出網址將包含%7Blocale%7D,它打破它。這讓我感到不必要的冗長。是否沒有辦法爲給定的命名參數指定默認值,例如,如果沒有爲'locale'明確提供值,那麼它可以默認爲當前的語言環境是什麼?

我檢查了UrlGenerator類,但我沒有看到任何效果。

Route類有一個defaults屬性,但似乎只用作綁定路由到當前請求的一部分。

最終,不是一個大問題,只是想知道如果有人有任何想法來保存一些理智的方法。

回答

0

沒有任何建立在這樣的手段,但我設法通過延長UrlGenerator

<?php 

namespace App\Services; 

use Illuminate\Routing\UrlGenerator as BaseGenerator; 
use Illuminate\Support\Arr; 

class UrlGenerator extends BaseGenerator 
{ 
    protected $default_parameters = []; 

    public function setDefaultParameter($key, $value){ 
     $this->default_parameters[$key] = $value; 
    } 

    public function removeDefaultParameter($key){ 
     unset($this->default_parameters[$key]); 
    } 

    public function getDefaultParameter($key){ 
     return isset($this->default_parameters[$key]) ? $this->default_parameters[$key] : null; 
    } 

    protected function replaceRouteParameters($path, array &$parameters) 
    { 
     if (count($parameters) || count($this->default_parameters)) { 
      $path = preg_replace_sub(
       '/\{.*?\}/', $parameters, $this->replaceNamedParameters($path, $parameters) 
      ); 
     } 
     return trim(preg_replace('/\{.*?\?\}/', '', $path), '/'); 
    } 

    protected function replaceNamedParameters($path, &$parameters) 
    { 
     return preg_replace_callback('/\{(.*?)\??\}/', function ($m) use (&$parameters) { 
      return isset($parameters[$m[1]]) ? Arr::pull($parameters, $m[1]) : ($this->getDefaultParameter($m[1]) ?: $m[0]); 
     }, $path); 
    } 
} 

然後重新綁定我們的子類到服務容器

class RouteServiceProvider extends ServiceProvider 
{ 
    public function register(){ 
     parent::register(); 

     //bind our own UrlGenerator 
     $this->app['url'] = $this->app->share(function ($app) { 
      $routes = $app['router']->getRoutes(); 
      $url = new UrlGenerator(
       $routes, $app->rebinding(
        'request', function ($app, $request) { 
         $app['url']->setRequest($request); 
        } 
       ) 
      ); 
      $url->setSessionResolver(function() { 
       return $this->app['session']; 
      }); 
      $app->rebinding('routes', function ($app, $routes) { 
       $app['url']->setRoutes($routes); 
      }); 

      return $url; 
     }); 
    } 

    //... 
} 

,以達到預期的效果然後,我需要做的就是將默認語言環境從Locale中間件注入UrlGenerator中

public function handle($request, Closure $next, $locale = null) { 
    //... 

    $this->app['url']->setDefaultParameter('locale', $locale); 

    return $next($request); 
} 

現在,route('foo.bar')會自動將當前語言環境綁定到路由,除非明確提供另一個語言環境。

0

當你定義你的路由,請使用默認設置可選變量:

路線:

Route::get('{locale?}/foo/bar', '[email protected]'); 

控制器:

public function __construct() 
{ 
    $this->locale = session()->has('locale') ? session('locale') : 'en'; 
} 

public function fooBar($locale = null) 
{ 
    $locale = $locale ?: $this->locale; 
} 

OR:

public function fooBar($locale = 'en') 
{ 
    $locale = $locale ?: $this->locale; 
} 

無論你打電話你的路線:

<a href="{{ route('foo.bar', null) }}">Foo Bar</a> 

你可以任意把構造的BaseController類,所有其他控制器擴展。

可能有更好的方法來做到這一點,但是這會讓你無需在任何你稱之爲路由的地方包含語言環境。

+0

爲了規範化,URL總是應該包含locale slug(不想同時擁有/ en/foo/bar和/ foo/bar)。不得不明確地將null傳遞給每個路由調用也不是理想的。 –