本文主要学习总结下Route,Middleware,Controller间参数传递。开发时经常碰到类似场景:有时需要在Middleware中读取Route中设置的middleware parameter和route parameter,有时也需要在Controller@Action中读取Middleware中设置的参数。
先假设路由是:
Route::group(['prefix' => 'route', 'namespace' => 'RouteParameter'], function () {
Route::group(['middleware' => 'route.parameter'], function () {
Route::resource('user.role', 'RouteParameterToMiddlewareController');
});
Route::group(['middleware' => 'middleware.parameter:advisor,show,comment'], function () {
Route::resource('advisor', 'MiddlewareParameterToMiddlewareController');
});
Route::group(['middleware' => 'middleware.controller:client'], function () {
Route::resource('controller', 'MiddlewareToController');
});
});
路由对应的控制器是:
namespace App\Http\Controllers\RouteParameter;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class RouteParameterToMiddlewareController extends Controller
{
public function show($user, $role)
{
}
}
namespace App\Http\Controllers\RouteParameter;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class MiddlewareParameterToMiddlewareController extends Controller
{
public function index()
{
return 'All';
}
}
并且在Kernel.php中注册中间件:
$routeMiddlewares = []
...
'route.parameter' => \App\Http\Middleware\RouteParameter::class,
'middleware.parameter' => \App\Http\Middleware\MiddlewareParameter::class,
'middleware.controller' => \App\Http\Middleware\ControllerParameter::class,
;
Passing Route Parameters to Middleware
在中间件route.parameter
中读取路由参数有三种方式:$request->route($parameter_name)
;$request->route()->parameter($parameter_name)
;$request->route()->parameters()
,代码如下:
<?php
namespace App\Http\Middleware;
use Closure;
class RouteParameter
{
public function handle($request, Closure $next)
{
$user = $request->route()->parameter('user');
$role = $request->route()->parameter('role');
dd($user, $role);
$parameters = $request->route()->parameters();
dd($parameters['user'], $parameters['role']);
return $next($request);
}
}
Passing Middleware Parameters to Middleware
在中间件middleware.parameter
中读取中间件参数只需要在handle()
中映射上对应的参数变量就行,就和在Controller@Action
中获取路由参数一样:
namespace App\Http\Middleware;
use Auth;
use Closure;
use Illuminate\Http\Response;
class MiddlewareParameter
{
public function handle($request, Closure $next, $role, $action, $data)
{
dd($role, $action, $data);
if (Auth::check() && (Auth::user()->type === $role)) {
return $next($request);
}
return abort(Response::HTTP_UNAUTHORIZED, 'You must log in to access the resource.', [
'Set-Cookie' => 'Laravel=0; path=/; Expires=Thu, 01-Jan-1970 00:00:00 GMT; Secure',
]);
}
}
Passing Parameters in Middleware to Controller
有时需要在中间中把参数传递到控制器中,则可以通过Request
对象作为传输管道,代码如:
namespace App\Http\Middleware;
use Closure;
class ControllerParameter
{
public function handle($request, Closure $next, $role)
{
$request->attributes->add(compact('role'));
return $next($request);
}
}
控制器中使用Request对象获取$role参数:
namespace App\Http\Controllers\RouteParameter;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class MiddlewareToController extends Controller
{
public function index(Request $request)
{
dd($request->get('role'));
}
}
总结:Route,Middleware,Controller之间传递参数这个知识点会经常在设计代码时用到,还有从Route中传递参数到Controller中,这个就更是经常要用到的,也简单。总结下这几个知识点,便于查阅。
RightCapital招聘Laravel DevOps
来自 https://laravel-china.org/topics/3092/laravel-learning-notes-of-route-middleware-and-controller-parameter-passing
I am carrying out a permissions check on a user to determine whether they can view a page or not. This involves passing the request through some middleware first.
The problem I have is I am duplicating the same database query in the middleware and in the controller before returning the data to the view itself.
Here is an example of the setup;
-- routes.php
Route::get('pages/{id}', [
'as' => 'pages',
'middleware' => 'pageUser'
'uses' => 'PagesController@view'
]);
-- PageUserMiddleware.php (class 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);
}
-- PagesController.php
public function view($id)
{
$page = Page::with('users')->where('id', $id)->first();
return view('pages.view', ['page' => $page]);
}
As you can see, the Page::with('users')->where('id', $id)->first()
is repeated in both the middleware and controller. I need to pass the data through from one to the other so an not to duplicate.
asked May 13 '15 at 10:38
I believe the correct way to do this (in Laravel 5.x) is to add your custom fields to the attributes property.
From the source code comments, we can see attributes is used for custom parameters:
/**
* Custom parameters.
*
* @var \Symfony\Component\HttpFoundation\ParameterBag
*
* @api
*/
public $attributes;
So you would implement this as follows;
$request->attributes->add(['myAttribute' => 'myValue']);
You can then retrieved the attribute by calling:
\Request::get('myAttribute');
answered Jul 16 '15 at 12:22
Instead of custom request parameters, you can follow the inversion-of-control pattern and use dependency injection.
In your middleware, register your Page
instance:
app()->instance(Page::class, $page);
Then declare that your controller needs a Page
instance:
class PagesController
{
protected $page;
function __construct(Page $page)
{
$this->page = $page;
}
}
Laravel will automatically resolve the dependency and instantiate your controller with the Page
instance that you bound in your middleware.
answered Oct 23 '15 at 8:15
In laravel >= 5 you can use $request->merge
in the middleware:
public function handle($request, Closure $next)
{
$request->merge(array("myVar" => "1234"));
return $next($request);
}
And in the controller:
public function index(Request $request)
{
$myVar = Request::instance()->query('myVar');
...
}
answered Nov 7 '15 at 13:50
I am sure if it was possible to pass data from a middleware to a controller then it would be in the Laravel documentation.
Have a look at this and this, it might help.
In short, you can piggy back your data on the request object which is being passed to the middleware. The Laravel authentication facade does that too.
So, in your middleware, you can have:
$request->myAttribute = "myValue";
answered May 13 '15 at 12:33
As mentioned in one of the comments above for laravel 5.3.x
$request->attributes->add(['key => 'value'] );
Doesn't work. But setting the variable like this in the middleware works
$request->attributes->set('key', 'value');
I could fetch the data using this in my controller
$request->get('key');
answered Sep 27 '17 at 15:30
$request is the array so that we can just add value and key to the array and get the $request with this key in the controller.
$request['id'] = $id;
answered Nov 15 '17 at 10:54
i don't speak english, so... sorry for possible errors.
You can use the IoC binding for this. In your middleware you can do this for binding $page instance:
\App::instance('mi_page_var', $page);
After, in your controller you call that instance:
$page = \App::make('mi_page_var');
The App::instance not re-instance the class, instead return the instance previusly binding.
answered Aug 18 '15 at 10:03