简体   繁体   English

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

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

I'm trying to set a handful of default route parameters that will work globally in my application regardless of context.我正在尝试设置一些默认路由参数,无论上下文如何,它们都将在我的应用程序中全局工作。 In the documentation for URL generation the example given is using middleware which is fine for HTTP, but won't get called during non-HTTP contexts.URL 生成文档中,给出的示例使用的是适用于 HTTP 的中间件,但不会在非 HTTP 上下文中被调用。 I also need this to work when called from the CLI.当从 CLI 调用时,我也需要它来工作。

My first idea is to have a Service Provider that calls the defaults method on boot:我的第一个想法是让服务提供者在启动时调用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',
        ]);
    }
}

But this does not work for HTTP requests:但这不适用于 HTTP 请求:

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

Outputs []输出[]

I believe this is because in the UrlGenerator , the setRequest method unconditionally sets the routeGenerator property to null .我相信这是因为在UrlGeneratorsetRequest方法无条件地将routeGenerator属性设置为null My Service Provider's boot method is called during the bootstrapping process, but then the request is set afterwards clobbering my defaults.我的服务提供商的引导方法在引导过程中被调用,但随后在破坏我的默认值之后设置了请求。

//Illuminate/Routing/UrlGenerator.php

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

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

Dumping the UrlGenerator during boot and then again in my routes file can demonstrate this:boot期间转储UrlGenerator然后在我的路由文件中再次转储可以证明这一点:

网址生成器

As you can see, the UrlGenerator instance is the same both times, but the RouteUrlGenerator on the routeGenerator property has changed.正如你所看到的, UrlGenerator实例两次相同,但RouteUrlGeneratorrouteGenerator属性已更改。

I am unsure of a better way to set these defaults.我不确定设置这些默认值的更好方法。

Not sure why this is getting attention almost a year later, but I ended up finding a solution by myself.不知道为什么这会在将近一年后引起关注,但我最终自己找到了解决方案。

To add a bit more information to the original question, the purpose of this was to allow us to have the same instance of the code powering both our live and sandbox application.为了向原始问题添加更多信息,这样做的目的是让我们拥有相同的代码实例来支持我们的实时应用程序和沙盒应用程序。 There's more involved to get this working, but this issue was just about URL generation for links in views.需要更多的工作来让这个工作,但这个问题只是关于视图中链接的 URL 生成。 All links generated always both a subdomain and tld, so this code injects these values always.生成的所有链接始终是子域和 tld,因此此代码始终注入这些值。

These views are rendered both as a response to a HTTP request, eg in our client areas, but also as part of a non HTTP request, eg a scheduled task generating invoices and emailing them to clients.这些视图既作为对 HTTP 请求的响应(例如在我们的客户区)呈现,也作为非 HTTP 请求的一部分呈现,例如生成发票并将其通过电子邮件发送给客户的计划任务。

Anyway, the solution:无论如何,解决方案:

For non HTTP contexts, a service provider can set the defaults:对于非 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());
    }
}

Since the there's no routing going on to cause the problem I asked originally, this just works.由于没有路由继续导致我最初问的问题,这只是有效。

For HTTP contexts, the RouteMatched event is listened for and the defaults injected then:对于 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 is just a simple class that returns an array: 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'),
        ];
    }
}

So digging into the source for routing classes a bit more, there's a defaults() method on the UrlGenerator class, but it's not a singleton, so any defaults you set in a service provider aren't persisted.因此,深入研究路由类的源代码,UrlGenerator 类上有一个 defaults() 方法,但它不是单例,因此您在服务提供者中设置的任何默认值都不会持久化。

I seem to have got it working by setting the defaults in some middleware:我似乎通过在一些中间件中设置默认值来让它工作:

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

A possible work around would be to have the route point to a PHP page that has a range of redirects based upon a token you pass. 可能的解决方法是让路由指向一个PHP页面,该页面具有一系列基于您传递的令牌的重定向。 See this Stackoverflow post as an example: 请参阅此Stackoverflow帖子作为示例:

PHP multiple redirects PHP多重重定向

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

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