Laravel Middleware return variable to controller

69,846

Solution 1

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');

Or from request object in laravel 5.5+

 $request->get('myAttribute');

Solution 2

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.

Solution 3

In Laravel >= 5 you can use $request->merge in the middleware.

public function handle($request, Closure $next)
{
    $request->merge(["myVar" => "1234"]);
    
    return $next($request);
}

And in the controller

public function index(Request $request)
{
    $myVar = $request->myVar;
    ...
}

Solution 4

Laravel 5.7

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

and

// to get in controller just use the resolve helper
$myObj = resolve('myObj');

Solution 5

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');
Share:
69,846
Alex
Author by

Alex

Updated on July 08, 2021

Comments

  • Alex
    Alex almost 3 years

    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.

  • Alex
    Alex almost 9 years
    Thanks @norman - thats a good solution and i didn't know you could do it...! I was questioning if i should be using middleware at this point at all, but it seems i should. The documentation does not mention anything of the sort. Thanks again
  • Noman Ur Rehman
    Noman Ur Rehman almost 9 years
    @Alex Yes, I think if its a common piece of code that executes in every controller action, it is not a bad idea to implement it as a middleware.
  • Alex
    Alex over 8 years
    I have changed this to the correct answer. Whilst Norman was right, this seems to adhere to Laravel's best practices. Thanks
  • user985366
    user985366 about 8 years
    How do you then access the attributes within the receiving controller?
  • GWed
    GWed about 8 years
    add request class to controller method arguments (IoC container) or call static class \Request
  • Shawn C.
    Shawn C. about 8 years
    $myAttribute = \Request::get('myAttribute');
  • schellingerht
    schellingerht almost 8 years
    Wow, this solution looks very clean!
  • developernaren
    developernaren over 7 years
    for some reason, $request->attributes->add(['key => 'value'] ); did not work for me but $request->attributes->set('key', 'value') worked, I could fetch the data using $request->get('key'),
  • GWed
    GWed over 7 years
    What version of laravel are you using?
  • Arian Acosta
    Arian Acosta over 7 years
    This is a really good idea, I went ahead and created a Service Provider then registered a Service Container. That way when needed some attributes, I would just inject the dependencies. Much cleaner and transparent. Thanks!
  • Hafiz
    Hafiz over 7 years
    What if someone want to add an object instead of just string value?
  • GWed
    GWed over 7 years
    It's just an array so an object can be added the same way as you do for any array
  • Gediminas
    Gediminas about 7 years
    Can't make it work - value is still empty. Laravel 5.3.4. Trying to use code in answer and @developernaren example :(
  • developernaren
    developernaren about 7 years
    @Gediminas can you post your code snippet somwhere? It is working perfectly for me. Make sure the middleware is called when the controller is called.
  • JCarlosR
    JCarlosR about 7 years
    @ArianAcosta Please, can you elaborate an answer with your way? I mean, how to use dependency injection and how it is associated with the middleware.
  • Arian Acosta
    Arian Acosta about 7 years
    @JCarlos Sure! The idea would be to have a custom Service Container class that holds as internal properties the data that you need to pass around between the middleware and the controller. If you register that Service Container as a singleton with $this->app->singleton(...) then, it will always be the same instance every time you inject it. So, essentially you would first inject it in the middleware (by simply requiring it as an argument), then put the data inside of it, and finally require it in the controller where you can access the data. See laravel.com/docs/5.4/container good luck
  • Vinay Vissh
    Vinay Vissh almost 7 years
    @Gaz_Edge Thanks a lot! Using Laravel 5.4.23 and putting arrays/objects inside attributes works like a charm!
  • jjok
    jjok over 6 years
    Why would you access Request::instance() statically, rather than using $request?
  • Pietro
    Pietro over 6 years
    This is a GREAT answer ... neat! :)
  • jonan.pineda
    jonan.pineda over 6 years
    You can also use $request->request->add(['myAttribute' => 'myValue']); to be able to use the magic getter shorthand $request->myAttribute
  • Serhii Topolnytskyi
    Serhii Topolnytskyi about 5 years
    Remark: in __constructor it doesn't work, because middleware loaded after controller's constructor. But you could use DI in any action of controller.
  • hizmarck
    hizmarck about 4 years
    @SerhiiTopolnytskyi In my case that works in the constructor.
  • Olle Härstedt
    Olle Härstedt over 3 years
    Is this really good praxis? Shouldn't the request object represent only what we got from the browser?
  • Ali
    Ali over 2 years
    this worked,thanks bro