中间件中的 Laravel 依赖注入

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35439234/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 13:14:46  来源:igfitidea点击:

Laravel Dependency Injection in Middleware

phplaravelioc-containermiddleware

提问by ajon

I am using Laravel-5.0's default AuthenticationMiddleware, but I changed the signature of the handle function to have:

我使用的是 Laravel-5.0 的默认Authentication中间件,但我将句柄函数的签名更改为:

public function handle($request, Closure $next, AuthClientInterface $authClient)

I also registered AuthClientInterfacein a Service Provider with:

我还在AuthClientInterface服务提供商处注册了:

public function register()
{
    $this->app->bind('App\Services\Contracts\AuthClientInterface', function()
    {
        return new AuthClient(
            env('AUTH_SERVER_URL'),
            env('AUTH_SESSION_URL'),
            env('AUTH_CLIENT_ID')
        );
    });
}

However, despite this, I am see the following error:

但是,尽管如此,我还是看到了以下错误:

Argument 3 passed to HelioQuote\Http\Middleware\Authenticate::handle() 
must be an instance of 
HelioQuote\Services\Contracts\HelioAuthClientInterface, none given, 
called in C:\MyApp\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php on line 125 and defined...

Can anyone see what I am doing wrong?

谁能看到我做错了什么?

EDIT: I did get it working by passing the HelioAuthClientInterface into the constructor of the middleware. However I thought the IoC container would also inject the dependency to methods in addition to the constructor.

编辑:我确实通过将 HelioAuthClientInterface 传递给中间件的构造函数来使其工作。但是我认为 IoC 容器除了构造函数之外还会注入对方法的依赖。

回答by Francis.TM

You cannot do dependency injection at handlemethod in a Request directly, do that in a constructor.

您不能handle直接在请求中的方法中进行依赖注入,而是在构造函数中进行。

Middleware is invoked by call_user_func, so any injection here will not be work.

中间件由 调用call_user_func,因此这里的任何注入都不起作用。

<?php

namespace App\Http\Middleware;

use Closure;
use App\Foo\Bar\AuthClientInterface; # Change this package name

class FooMiddleware
{
  protected $authClient;

  public function __construct(AuthClientInterface $authClient)
  {
    $this->authClient = $authClient;
  }

  public function handle(Request $request, Closure $next)
  {
    // do what you want here through $this->authClient
  }
}

回答by patricus

Laravel's IoC only handles constructor method injection for all objects by default. The IoC will only inject dependencies into functions/methodshandled by the router. The can be a closure used to handle a route, or more commonly, Controller methods used to handle routes.

Laravel 的 IoC 默认只处理所有对象的构造方法注入。IoC 只会将依赖项注入到由路由器处理的函数/方法中。可以是用于处理路由的闭包,或者更常见的是用于处理路由的 Controller 方法。

The IoC does not do methoddependency injection for any other object by default. You can call methods yourself through the IoC and have it resolve dependencies, but the framework only does this itself for route handlers. You can take a look at this question/answer for a little more information on using method dependency injection outside of a controller: can I use method dependency injection outside of a controller?.

默认情况下,IoC 不会对任何其他对象进行方法依赖注入。您可以通过 IoC 自己调用方法并让它解析依赖项,但框架本身只为路由处理程序执行此操作。您可以查看此问题/答案,了解有关在控制器外部使用方法依赖注入的更多信息:我可以在控制器外部使用方法依赖注入吗?.

Handling this by injecting your dependency through your constructor is the correct way to go, if you want to continue to use dependency injection.

如果你想继续使用依赖注入,通过你的构造函数注入你的依赖来处理这个是正确的方法。

回答by The Alpha

You are not allowed to change the method signature here. Simply you may use something like this:

此处不允许更改方法签名。简单地你可以使用这样的东西:

public function handle($request, Closure $next) {

    // Get the bound object to this interface from Service Provider
    $authClient = app('App\Services\Contracts\AuthClientInterface');

    // Now you can use the $authClient
}

Also, you may use a __constructmethod to achieve that, check the answer given by - Francis.TM.

此外,您可以使用一种__construct方法来实现这一点,请检查 - 给出的答案Francis.TM

回答by Romain 'Maz' BILLtheitroad

The accepted answer doesn't work anymore since Laravel 5.3.4. See complain on GitHuband upgrade guidewhich provide an alternative.

自 Laravel 5.3.4 以来,已接受的答案不再有效。 请参阅 GitHub 上的抱怨和提供替代方案的升级指南

For example, a snippet from what I implemented to solve the current problem:

例如,我为解决当前问题而实现的片段:

<?php

namespace App\Http\Middleware;

use Closure;
use App\Models\Website;
use \Illuminate\Http\Request;

class CheckPropertyOfWebsite
{

    protected $website_owner_id;

    public function __construct(Request $request)
    {
        $this->website_owner_id = Website::findOrFail($request->website)->first()->user_id;
    }

    public function handle($request, Closure $next)
    {
        if ($request->user()->id !== $this->website_owner_id) {
            return response(null, 500);
        }
        return $next($request);
    }
}