将变量从中间件传递到控制器 __construct 以防止重复自己

Passing variable from middleware to controllers __construct to prevent repeating myself

我正在通过检查路由参数在中间件中进行存在性检查。 如果检查成功,我将把它的模型附加到请求中,以使其在请求周期的其余部分可用,即应用程序。

// App\Http\Middleware\CheckForExistence.php:
...
public function handle($request, Closure $next)
{
    // some checks...

    // success
    $request->attributes->add([
       'company' => $someModel
    ]);
}

我现在有一个控制器,可以通过几种方法 'needs' 此信息。所以我的想法是将它添加到控制器的构造中并将其作为受保护的变量添加到整个控制器中:

// App\Http\Controllers\MyController.php
<?php
use Illuminate\Http\Request;
class MyController extends Controller
{
   protected $company;

   public function __construct(Request $request)
   {
      $this->company = $request->attributes->get('company');
   }

   public function index() 
   {
     dd($this->company); // returns null
   }

}

此控制器 index() returns null 而不是给定模型。

如果我将 index() 方法更改为:

public function index(Request $request)
{
    return $request->attributes->get('company');
}

本returns模特;正如预期的那样。

为什么会这样?貌似构造controller的时候中间件不是运行....有没有办法规避? 还是我错过了这里显而易见的东西......

我当然可以在每种方法中重复自己;但这不是很干 ;)

控制器构造函数将在中间件执行之前初始化。

您可以在控制器函数中从 Injected $request 对象获取数据。

您无法在控制器的构造函数中访问会话或经过身份验证的用户,因为中间件还没有 运行,因此您可以这样做:

public function __construct()
{
   $this->middleware(function ($request, $next) {
        $this->company = $request->attributes->get('company');
        return $next($request);
    });
}

由于我目前不清楚的原因,控制器对象是在请求更改反映在请求对象中之前构造的。简而言之,在构建控制器时,请求未被正确构建。 This post 似乎暗示了。

有两种方法可以解决这个问题(如果我们暂时忽略您正在尝试做的事情)。

  1. 使用请求依赖注入

    public function index(Request $request)
    {
        $compary = $request->attributes->get('company'); 
    }
    

这并不是真正的 WET,因为您只是将 $this->company$request->attributes->get('company') 交换,这只是一个重构。无论如何,你应该在控制器操作中注入请求,如果你不想这样做,你可以使用 request() 助手。

  1. 在构造函数中使用回调中间件(Maraboc 的回答解释了如何)

现在,如果您想要更具体案例的解决方案,尽管您可以使用案例特定依赖项注入:

如果您需要将模型绑定到特定的路由参数,您可以使用 route model binding 并在您的 RouteServiceProvider(或任何提供商)中添加以下内容。

Route::bind("companyAsARouteVarName", function () {
   // this is why more details in the question are invaluable. I don't know if this is the right way for you.
     //checks
     // success
      return $someModel;

});

然后您将您的路线注册为:

Route::get("/something/{companyAsARouteVarName}", "SomeController@index");

您的控制器将是:

public function index(Company $companyAsARouteVarName) {
        //Magic
}