Laravel Middleware return variable to controller

2019-01-13 05:15发布

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.

10条回答
别忘想泡老子
2楼-- · 2019-01-13 05:42

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');
    ...
}
查看更多
该账号已被封号
3楼-- · 2019-01-13 05:45

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.

查看更多
家丑人穷心不美
4楼-- · 2019-01-13 05:46

Laravel 5.7

// in Middleware register instance
app()->instance('myObj', $myObj);

and

// to get in controller just use the resolve helper
$myObj = resolve('myObj');
查看更多
爷的心禁止访问
5楼-- · 2019-01-13 05:47

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.

查看更多
神经病院院长
6楼-- · 2019-01-13 05:50

It is very simple:

Here is middleware code:

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

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

    return $next($request);
}

and here is controller code:

$request->customVar;
查看更多
闹够了就滚
7楼-- · 2019-01-13 05:56

I was able to add values to the Request-object with:

$request->attributes->set('key', 'value');

and get them back at a later point with:

$request->attributes->get('key');

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.

查看更多
登录 后发表回答