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

时间:2017-10-25 12:11:27

标签: php laravel laravel-5.5

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

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

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

我现在有一个需要的控制器'这些信息有两种方法。所以我的想法是将它添加到控制器的构造中,并将其作为受保护的var添加到整个控制器中:

// 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()返回null而不是give模型。

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

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

返回模型;正如所料。

为什么会这样?看起来中间件在构造控制器时没有运行....有没有办法绕过它? 或者我在这里错过了明显的......

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

3 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:1)

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

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

答案 2 :(得分:1)

由于我目前尚不清楚的原因,在请求更改反映在请求对象之前构造控制器对象。简而言之,在构造控制器时,不认为请求是正确构造的。 This post似乎意味着这一点。

有两种方法可以解决这个问题(如果一秒钟我们忽略了你正在尝试做的事情)。

  1. 使用请求依赖注入

    public function index(Request $request)
    {
        $compary = $request->attributes->get('company'); 
    }
    
  2. 这不是真的WET,因为你只是用$this->company$request->attributes->get('company')交换它只是一个重构。无论如何,您应该在控制器操作中注入请求,如果您不想这样做,可以使用request()帮助程序。

    1. 在构造函数中使用回调中间件(Maraboc的回答解释了如何)
    2. 现在,如果您想要一个更具体案例的解决方案,尽管您可以使用特定于案例的依赖注入:

      如果您需要将模型绑定到特定路由参数,可以使用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
      }