Laravel中间件将变量返回给控制器
Laravel中间件将变量返回给控制器
我正在对用户进行权限检查,以确定他们是否可以查看页面。这涉及首先通过一些中间件来传递请求。\n我遇到的问题是我在中间件和控制器中重复了相同的数据库查询,然后才将数据返回到视图本身。\n以下是设置的示例:\n-- routes.php\n
Route::get('pages/{id}', [ 'as' => 'pages', 'middleware' => 'pageUser' 'uses' => 'PagesController@view' ]);
\n-- PageUserMiddleware.php(PageUserMiddleware类)\n
public function handle($request, Closure $next) { //获取页面 $pageId = $request->route('id'); //找到带有用户的页面 $page = Page::with('users')->where('id', $pageId)->first(); //检查登录的用户是否存在于页面中 if(!$page->users()->wherePivot('user_id', Auth::user()->id)->exists()) { //如果不存在,将其重定向 return redirect()->route('redirectRoute'); } return $next($request); }
\n-- PagesController.php\n
public function view($id) { $page = Page::with('users')->where('id', $id)->first(); return view('pages.view', ['page' => $page]); }
\n正如您所看到的,在中间件和控制器中都重复了Page::with(\'users\')->where(\'id\', $id)->first()
。我需要将数据从一个传递到另一个,以避免重复。
Laravel中的中间件(Middleware)是一种用于处理HTTP请求的机制,它可以在请求到达控制器之前或之后执行一些操作。在Laravel 5及以上的版本中,我们可以使用$request->merge
方法在中间件中返回变量给控制器。
下面的代码演示了如何在中间件中使用$request->merge
方法返回变量给控制器:
public function handle($request, Closure $next) { $request->merge(["myVar" => "1234"]); return $next($request); }
上述代码将在请求中添加一个名为myVar
的变量,并将其值设为1234
,然后将请求传递给下一个中间件或控制器。
在控制器中,我们可以通过$request->myVar
来获取这个变量的值:
public function index(Request $request) { $myVar = $request->myVar; ... }
上述代码将获取到中间件中设置的myVar
的值。
为什么会有人使用Request::instance()
静态方法访问请求实例,而不是使用$request
参数呢?这并不是一个好的解决方法,它可能导致意外的副作用。有关更多细节,请查看下面的回答:stackoverflow.com/a/73131117/8485567。
我们可以通过在中间件中使用$request->merge
方法返回变量给控制器。这种方式可以方便地在请求处理过程中传递数据,并且不会引起意外的副作用。相比于静态访问请求实例,使用$request
参数更加安全可靠。
问题: Laravel中的中间件将变量返回给控制器的原因和解决方法
在Laravel中,我们可以使用依赖注入来避免使用自定义请求参数。以下是使用依赖注入的示例:
首先,在中间件中注册Page
实例:
app()->instance(Page::class, $page);
然后,声明控制器需要一个Page
实例:
class PagesController { protected $page; function __construct(Page $page) { $this->page = $page; } }
Laravel将自动解析依赖关系,并使用在中间件中绑定的Page
实例来实例化控制器。
有人提出了一个很好的想法,他创建了一个服务提供者,并注册了一个服务容器。这样,当需要某些属性时,只需注入依赖项即可。更加简洁和透明。谢谢!
请问,你能详细解释一下你的方法吗?也就是说,如何使用依赖注入,以及它与中间件的关联。
当然!你可以创建一个自定义的服务容器类,将需要在中间件和控制器之间传递的数据作为内部属性保存在其中。如果你将该服务容器注册为单例(singleton)$this->app->singleton(...)
,那么每次注入它时都将得到同一个实例。因此,你可以首先在中间件中注入它(只需将其作为参数),然后将数据放入其中,并最后在控制器中引用它以访问这些数据。详见laravel.com/docs/5.4/container,祝你好运!
这是一个很好的答案...简洁! 🙂
备注:在__constructor中可能不起作用,因为中间件在控制器的构造函数之后加载。但你可以在控制器的任何动作中使用依赖注入。
在我的情况下,在构造函数中也可以正常工作。
Laravel Middleware return variable to controller
在Laravel中,如何将Middleware中的变量传递给Controller?这个问题的出现的原因是由于需要在Middleware中处理一些逻辑,并将处理结果传递给Controller进一步处理。下面是解决这个问题的方法:
在Laravel 5.x中,正确的方法是将自定义字段添加到attributes属性中。在源代码的注释中,我们可以看到attributes属性用于自定义参数。你可以按照以下方式实现:
$request->attributes->add(['myAttribute' => 'myValue']);
你可以通过调用以下代码来获取这个属性:
\Request::get('myAttribute');
或在Laravel 5.5+中,可以从request对象中获取:
$request->get('myAttribute');
你可以将请求类添加到Controller方法的参数(IoC容器)中,或者调用静态类\Request来访问属性:
$myAttribute = \Request::get('myAttribute');
这种解决方法非常简洁!
如果在Middleware中使用`$request->attributes->add(['key' => 'value']);`无法生效,可以尝试使用`$request->attributes->set('key', 'value')`来设置属性,并使用`$request->get('key')`来获取数据。
对于Laravel 5.3.4版本,如果无法使其工作,请确保在调用Controller时Middleware也被调用。
如果想要添加一个对象而不仅仅是一个字符串值,可以像对待任何数组一样将对象添加到属性中。因为这只是一个数组。
在Laravel 5.4.23中,也可以使用`$request->request->add(['myAttribute' => 'myValue']);`来添加属性,并且可以使用魔术访问器的简写形式`$request->myAttribute`来访问。
但是,是否应该将这些属性添加到请求对象中是一个需要考虑的问题。请求对象应该只表示从浏览器获得的数据。
总结上述内容,我们可以通过将自定义字段添加到attributes属性中,然后使用`\Request::get('myAttribute')`或`$request->get('myAttribute')`来访问这些属性,从而在Laravel中实现将Middleware中的变量传递给Controller的功能。