繁体   English   中英

Laravel:如何设置全局可用的默认路由参数

[英]Laravel: How to set globally available default route parameters

我正在尝试设置一些默认路由参数,无论上下文如何,它们都将在我的应用程序中全局工作。 URL 生成文档中,给出的示例使用的是适用于 HTTP 的中间件,但不会在非 HTTP 上下文中被调用。 当从 CLI 调用时,我也需要它来工作。

我的第一个想法是让服务提供者在启动时调用defaults方法:

<?php

namespace App\Providers;

use Illuminate\Routing\UrlGenerator;
use Illuminate\Support\ServiceProvider;

class UrlDefaults extends ServiceProvider
{
    public function boot(UrlGenerator $urlGenerator): void
    {
        $urlGenerator->defaults([
            'foo' => 'abc',
            'bar' => 'xyz',
        ]);
    }
}

但这不适用于 HTTP 请求:

Route::get('test', function (\Illuminate\Routing\UrlGenerator $urlGenerator) {
    dump($urlGenerator->getDefaultParameters());
});

输出[]

我相信这是因为在UrlGeneratorsetRequest方法无条件地将routeGenerator属性设置为null 我的服务提供商的引导方法在引导过程中被调用,但随后在破坏我的默认值之后设置了请求。

//Illuminate/Routing/UrlGenerator.php

    public function setRequest(Request $request)
    {
        $this->request = $request;

        $this->cachedRoot = null;
        $this->cachedSchema = null;
        $this->routeGenerator = null;
    }

boot期间转储UrlGenerator然后在我的路由文件中再次转储可以证明这一点:

网址生成器

正如你所看到的, UrlGenerator实例两次相同,但RouteUrlGeneratorrouteGenerator属性已更改。

我不确定设置这些默认值的更好方法。

不知道为什么这会在将近一年后引起关注,但我最终自己找到了解决方案。

为了向原始问题添加更多信息,这样做的目的是让我们拥有相同的代码实例来支持我们的实时应用程序和沙盒应用程序。 需要更多的工作来让这个工作,但这个问题只是关于视图中链接的 URL 生成。 生成的所有链接始终是子域和 tld,因此此代码始终注入这些值。

这些视图既作为对 HTTP 请求的响应(例如在我们的客户区)呈现,也作为非 HTTP 请求的一部分呈现,例如生成发票并将其通过电子邮件发送给客户的计划任务。

无论如何,解决方案:

对于非 HTTP 上下文,服务提供者可以设置默认值:

<?php namespace App\Providers;

use App\Support\UrlDefaults;
use Illuminate\Routing\UrlGenerator;
use Illuminate\Support\ServiceProvider;

class UrlDefaultsServiceProvider extends ServiceProvider
{
    public function boot(UrlGenerator $urlGenerator): void
    {
        $urlGenerator->defaults(UrlDefaults::getDefaults());
    }
}

由于没有路由继续导致我最初问的问题,这只是有效。

对于 HTTP 上下文,会监听RouteMatched事件,然后注入默认值:

<?php namespace App\Listeners;
use App\Support\UrlDefaults;
use Illuminate\Routing\Router;
use Illuminate\Routing\UrlGenerator;

/**
 * Class SetUrlDefaults
 *
 * This class listeners for the RouteMatched event, and when it fires, injects the route paramaters (subdomain, tld,
 * etc) into the defaults of the UrlGenerator
 *
 * @package App\Listeners
 */
class SetUrlDefaults
{
    private $urlGenerator;
    private $router;

    public function __construct(UrlGenerator $urlGenerator, Router $router)
    {
        $this->urlGenerator = $urlGenerator;
        $this->router       = $router;
    }

    public function handle(): void
    {
        $paramaters = array_merge(UrlDefaults::getDefaults(), $this->router->current()->parameters);
        $this->urlGenerator->defaults($paramaters);
    }
}

UrlDefaults只是一个返回数组的简单类:

<?php namespace App\Support;

class UrlDefaults
{
    public static function getDefaults(): array
    {
        return [
            'tld' => config('app.url.tld'),
            'api' => config('app.url.api'),
            'foo' => config('app.url.foo'),
            'bar' => config('app.url.bar'),
        ];
    }
}

因此,深入研究路由类的源代码,UrlGenerator 类上有一个 defaults() 方法,但它不是单例,因此您在服务提供者中设置的任何默认值都不会持久化。

我似乎通过在一些中间件中设置默认值来让它工作:

   Route::domain('{domain}')->middleware('route.domain')->group(function () {
    //
  });

  namespace App\Http\Middleware;
  use Illuminate\Contracts\Routing\UrlGenerator;

  class SetRouteDomain
  {
    private $url;

    public function __construct(UrlGenerator $url)
    {
      $this->url = $url;
    }

   public function handle($request, Closure $next)
   {
     $this->url->defaults([
        'domain' => $request->getHost(),
     ]);

    return $next($request);
   }
  }

可能的解决方法是让路由指向一个PHP页面,该页面具有一系列基于您传递的令牌的重定向。 请参阅此Stackoverflow帖子作为示例:

PHP多重重定向

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM