Datadimension
Datadimension

Reputation: 1045

Laravel 7 User data in __construct

Using Laravel 7. In the controller constructor, I then hoped to get access to the current user details so I could load main site widgets (buttons links etc) and custom user widgets in to one to be displayed in the view

use Illuminate\Support\Facades\Auth;

...

    $widgets = Cache::get("widgets");
    $usersdata = Cache::get("userdata");
    $this->middleware('auth');
    $widgets = array_merge($widgets, $usersdata[Auth::user()->id]["widgets"]);
    View::share([
        "widgets" => json_encode($widgets)
    ]);

however at this stage from research the user data is not available (even after authentication ?). Not sure of best way to access this, or better practice might be to override the middleware auth (where?) so that it could return user id or something eg:

$userid=$this->middleware('auth');

I would like this in the constructor so the same method is in place for all controllers which extend this main controller.

Upvotes: 2

Views: 1840

Answers (1)

Remul
Remul

Reputation: 8252

This is intended behavior from laravel, you can read more about it here.

Laravel collects all route specific middlewares first before running the request through the pipeline, and while collecting the controller middleware an instance of the controller is created, thus the constructor is called, however at this point the request isn’t ready yet.

You can find Taylor's reasoning behind it here:

It’s very bad to use session or auth in your constructor as no request has happened yet and session and auth are INHERENTLY tied to an HTTP request. You should receive this request in an actual controller method which you can call multiple times with multiple different requests. By forcing your controller to resolve session or auth information in the constructor you are now forcing your entire controller to ignore the actual incoming request which can cause significant problems when testing, etc.

So one solution would be to create a new middleware and then apply it to all routes, something like this, where widgets is your new middleware:

Route::group(['middleware' => ['auth', 'widgets']], function () {
    // your routes
});

But if you really want to keep it in the constructor you could implement the following workaround:

class YourController extends Controller
{
    public function __construct(Request $request)
    {
        $this->middleware('auth');
        $this->middleware(function ($request, $next) {
            $widgets = Cache::get("widgets");
            $usersdata = Cache::get("userdata");
            $widgets = array_merge($widgets, $usersdata[$request->user()->id]["widgets"]);

            View::share([
                "widgets" => json_encode($widgets)
            ]);

            return $next($request);
        });
    }
}

Upvotes: 2

Related Questions