【问题标题】:Default value for route params in generated url生成的 url 中路由参数的默认值
【发布时间】:2016-01-20 18:44:16
【问题描述】:

我有一个本地化为多种语言的网站。每个公共路由都以语言环境键为前缀(例如/{locale}/foo/bar),中间件会捕获并应用它。

在生成指向其他页面的 URL 时,我最终需要将当前语言环境提供给每个 url,如下所示:

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

否则输出 url 将包含%7Blocale%7D,这会破坏它。这让我觉得不必要的冗长。是否没有办法为给定的命名参数指定默认值,这样如果没有为'locale' 显式提供值,则可以将其默认为当前区域设置?

我已经检查了 UrlGenerator 类,但我没有看到任何效果。

Route 类有一个 defaults 属性,但它似乎只用作将路由绑定到当前请求的一部分。

最终,这不是一个大问题,只是想知道是否有人对节省一点理智的方法有任何想法。

【问题讨论】:

    标签: php laravel laravel-5


    【解决方案1】:

    您也可以在中间件中使用 URL 默认值:

       use Illuminate\Support\Facades\URL;
    
         URL::defaults(
           [
                'locale' =>  $locale 
           ] 
        );
    

    【讨论】:

      【解决方案2】:

      当你定义你的路由时,使用带有默认值的可选变量:

      路线:

      Route::get('{locale?}/foo/bar', 'Controller@fooBar');
      

      控制器:

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

      或者:

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

      无论您在哪里调用您的路线:

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

      您可以选择将构造函数放入所有其他控制器扩展的 BaseController 类中。

      可能有更好的方法可以做到这一点,但这将使您不必在调用路线的任何地方都包含语言环境。

      【讨论】:

      • 为了规范化,URL 应始终包含语言环境 slug(不希望同时具有 /en/foo/bar 和 /foo/bar)。必须将 null 显式传递给每个路由调用也不理想。
      【解决方案3】:

      没有任何内置方法可以做到这一点,但我设法通过扩展 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') 将自动将当前语言环境绑定到路由,除非明确提供另一个。

      【讨论】:

        猜你喜欢
        • 2021-01-08
        • 2020-05-17
        • 1970-01-01
        • 1970-01-01
        • 2021-01-17
        • 1970-01-01
        • 2017-01-17
        • 2020-02-07
        • 1970-01-01
        相关资源
        最近更新 更多