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.
In laravel >= 5 you can use
$request->merge
in the middleware:And in the controller:
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:Laravel will automatically resolve the dependency and instantiate your controller with the
Page
instance that you bound in your middleware.Laravel 5.7
and
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:
After, in your controller you call that instance:
The App::instance not re-instance the class, instead return the instance previusly binding.
It is very simple:
Here is middleware code:
and here is controller code:
I was able to add values to the Request-object with:
and get them back at a later point with:
This is possible because laravels Request extends symfonys Request which has the attribute "$attributes" of type ParameterBag that is intended to hold custom parameters.
I think this should be Best Practice to pass data to subsequent Middleware, Controllers or any other place where it's possible to access the Request-object.
Tested with Laravel 5.6, but probably also working with other versions.