生成的URL中路由参数的默认值

时间:2016-01-20 18:44:16

标签: php laravel laravel-5

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

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

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

否则输出网址将包含%7Blocale%7D,这会打破它。这让我感到不必要的冗长。是否没有办法为给定的命名参数指定默认值,这样如果没有为'locale'显式提供任何值,它可以默认为当前语言环境的任何值?

我已经检查过UrlGenerator类,但是我没有看到任何相关效果。

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

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

3 个答案:

答案 0 :(得分:0)

定义路线时,请使用默认值为的可选变量:

路线:

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;
}

OR:

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

无论您何处致电路线:

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

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

可能有更好的方法可以做到这一点,但这样可以避免在任何调用路径的地方都包含语言环境。

答案 1 :(得分:0)

没有内置的方法可以做到这一点,但我设法通过扩展UrlGenerator来实现所需的结果

for($i = 1; $i <= 10; $i++) {
    for($j = 0; $j < 20; $j++)
        echo $j . ' ' . $i . '<br>';

    echo '<br>';
}

然后将我们的子类重新绑定到服务容器

<?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);
    }
}

然后我需要做的就是从Locale中间件将默认语言环境注入UrlGenerator

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;
        });
    }

    //...
}

现在public function handle($request, Closure $next, $locale = null) { //... $this->app['url']->setDefaultParameter('locale', $locale); return $next($request); } 会自动将当前区域设置绑定到路由,除非明确提供另一个区域设置。

答案 2 :(得分:0)

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

$date = date('2018-01-01');
$date_today = new DateTime($date);
$curr_weeknr = $date_today->format("W");
$six_weeks_ago = $curr_weeknr - 6;