2016-01-20 91 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传递给每个路由调用也不是理想的。 –