如何在Laravel的容器中重新绑定?

How to rebind in Laravel’s container?

我正在尝试在 Laravel 的 Request class.

中添加类似于用户解析器的功能

我有一个 SaaS 应用程序。我创建了一个中间件 class 来查看请求主机并根据域获取相应的帐户。它看起来像这样:

public function handle($request, Closure $next)
{
    $host = $request->getHost();

    $domain = Domain::whereName($host)->firstOrFail();

    return $next($request);
}

我已经在我的应用程序中扩展了 Request class,并更新了 public/index 中的引用。php 使用这个新的 class。我还添加了三个新方法:

public function account()
{
    return call_user_func($this->getAccountResolver());
}

public function getAccountResolver()
{
    return $this->accountResolver ?: function () {};
}

public function setAccountResolver(Closure $callback)
{
    $this->accountResolver = $callback;

    return $this;
}

我的想法是,我希望能够像获取当前登录用户一样从请求中获取帐户:

$user = $request->user();
$account = $request->account(); // My new method

我查看了 Laravel 代码库,他们似乎使用重新绑定来添加用户解析器。来自 AuthServiceProvider class:

$this->app->rebinding('request', function ($app, $request) {
    $request->setUserResolver(function () use ($app) {
        return $app['auth']->user();
    });
});

所以我在我的中间件方法中复制了这个:

$this->app->rebinding('request', function ($app, $request) use ($domain) {
    $request->setAccountResolver(function () use ($app, $domain) {
        return $domain->account; // Domain belongs to an Account
    });
});

但这似乎没有被触发。如果我在中间件中 运行 dd($request) 我可以看到 $accountResolver 属性 是 Closure (我的回调)的一个实例,但是当我 dd($request) 中间件class(比如一个控制器动作)之后,$accountResolver方法又回到了null

如何让我的帐户解析器在我的中间件之后持续存在,以便我可以调用 $request->account() 并在我的应用程序中获得一个 Account 实例?

我在谷歌搜索这个问题后在另一个项目中解决了这个问题,具有讽刺意味的是我自己的问题结束了!

在我的 AppServiceProviderregister() 方法中,我有以下代码:

$this->app->rebinding('request', function ($app, $request) {
    $request->setUserResolver(function () {
        // Customer user resolving logic here
    });
}

在我的控制器中,如果我键入提示 Request class...

public function index(Request $request)
{
    //
}

…然后对 $request->user() 的任何调用都会使用我的自定义逻辑解决用户问题。

只需将 app('auth')->resolveUsersUsing(fn () => $domain->account); 放在中间件句柄方法上即可。