Laravel Middleware将变量返回给控制器

Ale*_*lex 66 php laravel laravel-5 laravel-middleware

我正在对用户执行权限检查以确定他们是否可以查看页面.这涉及首先通过一些中间件传递请求.

我遇到的问题是我在将数据返回到视图本身之前,在中间件和控制器中复制相同的数据库查询.

以下是设置示例;

- routes.php

Route::get('pages/{id}', [
   'as' => 'pages',
   'middleware' => 'pageUser'
   'uses' => 'PagesController@view'
]);
Run Code Online (Sandbox Code Playgroud)

- PageUserMiddleware.php(类PageUserMiddleware)

public function handle($request, Closure $next)
    {
        //get the page
        $pageId = $request->route('id');
        //find the page with users
        $page = Page::with('users')->where('id', $pageId)->first();
        //check if the logged in user exists for the page
        if(!$page->users()->wherePivot('user_id', Auth::user()->id)->exists()) {
            //redirect them if they don't exist
            return redirect()->route('redirectRoute');
        }
        return $next($request);
    }
Run Code Online (Sandbox Code Playgroud)

- PagesController.php

public function view($id)
{
    $page = Page::with('users')->where('id', $id)->first();
    return view('pages.view', ['page' => $page]);
}
Run Code Online (Sandbox Code Playgroud)

如您所见,Page::with('users')->where('id', $id)->first()中间件和控制器都重复了这一过程.我需要将数据从一个传递到另一个,所以不要重复.

Gaz*_*dge 113

我相信正确的方法(在Laravel 5.x中)是将自定义字段添加到attributes属性.

从源代码注释中,我们可以看到属性用于自定义参数:

 /**
 * Custom parameters.
 *
 * @var \Symfony\Component\HttpFoundation\ParameterBag
 *
 * @api
 */
public $attributes;
Run Code Online (Sandbox Code Playgroud)

所以你要按如下方式实现:

$request->attributes->add(['myAttribute' => 'myValue']);
Run Code Online (Sandbox Code Playgroud)

然后,您可以通过调用以下方法检索属性

\Request::get('myAttribute');
Run Code Online (Sandbox Code Playgroud)

  • $ myAttribute =\Request :: get('myAttribute'); (7认同)
  • 哇,这个解决方案看起来很干净! (2认同)
  • 您也可以使用$ request-> request-> add(['myAttribute'=>'myValue']);;来使用神奇的getter简写方式$$ quest-> myAttribute (2认同)

cri*_*hoj 22

您可以遵循控制反转模式并使用依赖项注入,而不是自定义请求参数.

在您的中间件中,注册您的Page实例:

app()->instance(Page::class, $page);

然后声明您的控制器需要一个Page实例:

class PagesController 
{
    protected $page;

    function __construct(Page $page) 
    {
        $this->page = $page;
    }
}
Run Code Online (Sandbox Code Playgroud)

Laravel将自动解析依赖关系并使用Page绑定在中间件中的实例实例化控制器.

  • @JCarlos当然可以!我们的想法是拥有一个自定义Service Container类,它将您需要在中间件和控制器之间传递的数据保存为内部属性.如果您使用$ this-> app-> singleton(...)将该Service Container注册为单例,那么每次注入它时它将始终是相同的实例.所以,基本上你首先将它注入中间件(通过简单地将其作为参数),然后将数据放入其中,最后在控制器中将其需要它来访问数据.请参阅https://laravel.com/docs/5.4/container祝您好运 (4认同)
  • 这是一个很好的答案。:) (2认同)
  • 备注:在__constructor中它不起作用,因为中间件在控制器的构造函数之后加载。但是您可以在控制器的任何动作中使用DI。 (2认同)

Vin*_*ius 16

在laravel> = 5中,您可以$request->merge在中间件中使用:

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

    $request->merge(array("myVar" => "1234"));

    return $next($request);
}
Run Code Online (Sandbox Code Playgroud)

在控制器中:

public function index(Request $request)
{

    $myVar = $request->instance()->query('myVar');
    ...
}
Run Code Online (Sandbox Code Playgroud)

  • 为什么要静态访问`Request :: instance()`,而不是使用`$ request`? (10认同)

Иль*_*ько 7

Laravel 5.7

// in Middleware register instance
app()->instance('myObj', $myObj);
Run Code Online (Sandbox Code Playgroud)

// to get in controller just use the resolve helper
$myObj = resolve('myObj');
Run Code Online (Sandbox Code Playgroud)


Nom*_*man 6

我确信如果可以将数据从中间件传递到控制器,那么它将在Laravel文档中.

看看这个,它可能会有所帮助.

简而言之,您可以将数据存储在传递给中间件的请求对象上.Laravel身份验证外观也是如此.

因此,在您的中间件中,您可以:

$request->myAttribute = "myValue";
Run Code Online (Sandbox Code Playgroud)


小智 6

这很简单:

下面是中间件代码:

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

    $request->merge(array("customVar" => "abcde"));

    return $next($request);
}
Run Code Online (Sandbox Code Playgroud)

这是控制器代码:

$request->customVar;
Run Code Online (Sandbox Code Playgroud)


Tar*_*han 5

如上面对laravel 5.3.x的评论之一所述

$request->attributes->add(['key => 'value'] ); 
Run Code Online (Sandbox Code Playgroud)

不起作用 但是在中间件中像这样设置变量是可行的

$request->attributes->set('key', 'value');
Run Code Online (Sandbox Code Playgroud)

我可以在控制器中使用它来获取数据

$request->get('key');
Run Code Online (Sandbox Code Playgroud)