I'm creating an API for a blog using Laravel and in my UserController, for some routes, I get the currently authenticated user as seen below:
public function getUser() {
$user = auth()->user();
return response()->json($user, 200);
}
This returns a json object of the user. I get the user in other functions in the same way. I wanted to move this line into a wider scope so I could access it in all functions so I placed it in the constructor:
class UserController extends Controller {
protected $user;
public function __construct() {
$this->user = auth()->user();
}
}
I refactored getUser to look like this;
public function getUser() {
return response()->json($this->user, 200);
}
Now it just returns an empty object and the 200 status code. Why does making it a class property no longer return the object?
The session middleware has not ran yet; the Controller is instantiated before the Request goes through the middleware stack, so you won't have access to session based authentication at that point (so auth()->user() would be null). You can use a Controller middleware to do this though:
class UserController extends Controller
{
protected $user;
public function __construct()
{
$this->middleware(function ($request, $next) {
$this->user = $request->user();
return $next($request);
});
}
}
This middleware will run after the other middleware in the stack so you will have access to the session at that point.
Related
This is a part of the code.
class StudentController extends Controller
{
public function __construct(Request $request)
{
$school = session('school_data');
$this->middleware($school);
}
}
Now, I've also tried checking the $school by using dd($school) but it returns null
NOTE: The session variable works in other functions inside the same controller.
your sessions are not ready yet.
if you want to use them, use like below:
class StudentController extends Controller
{
public function __construct(Request $request)
{
$this->middleware(function ($request, $next) {
// fetch session and use it in entire class with constructor
$this->school_data = session()->get('school_data');
return $next($request);
});
}
}
from here: laravel - Can't get session in controller constructor
We want to pass data from controller to another controller in Laravel (framework). In our Controller.php we got a middleware code in the __construct function, which sets a environment and person.
Code in Controller.php
public function __construct()
{
$this->middleware(function ($request, $next) {
$this->environment = session()->get('environment');
$this->person = session()->get('person');
return $next($request);
});
}
In a different controller we pass 2 parameters (Request data) and (id of data) to another controller function. We tried many ways for pass data. On this moment we lost our $this data like environment and person, the variables environment and person are exists but empty.
We tried with:
$postController = new \App\Http\Controllers\Publication\Post\IndexController();
$postController->duplicate($request, data_get($publication, 'id'));
Or
app('App\Http\Controllers\Publication\Post\IndexController')->duplicate($request, data_get($publication, 'id'))
In Post\IndexController#duplicate we lose our $this data (empty).
We tried to get data like $this->enviroment but this variables are empty.
Anyone has any idea how to pass data with the variables filled by the middleware?
You can use the power of Container
Code in Controller.php
public function __construct()
{
$this->middleware(function ($request, $next) {
app()->instance('person', session()->get('person'));
app()->instance('environment', session()->get('environment'));
return $next($request);
});
}
In another controller:
<?php
namespace App\Http\Controllers;
class DupeController extends Controller
{
public function index()
{
dd(app('person'));
}
}
Just make sure if the "another controller" has it's own constructor, call the parent constructor, you your 'person' and 'environment' instance would be available in that controller.
<?php
namespace App\Http\Controllers;
class DupeController extends Controller
{
public function __construct()
{
parent::__construct();
// DO MAGIC
}
public function index()
{
dd(app('person'));
}
}
But I gotta tell you the truth, this is a bad practice. I just want to show you that something bad like this is possible. Try another approach like service injection to the controller using dependency injection technique and mark that service as a singleton, so container will resolve the same instance for every resolution (one instance per request).
I use Laravel 5.4.36.
When I use Auth::user()->id on constructor method show me this error
(1/1) ErrorException
Trying to get property of non-object
in UserController.php (line 25)
My controller:
public function __construct()
{
echo Auth::user()->id;
}
But when I use Auth::user()->id on index method show me 2
public function index()
{
echo Auth::user()->id;
}
result is : 2
And When I test it on AppServiceProvider.php boot method show me this error again
The problem is session is still not started in constructor. It will be registered once all middleware will be registered from your app/Http/Kernel.php and what your are trying to fetch will give value only if user session has started.
So in constructer you have to override the middleware function. In your controller file, you can access user session data like this
private $userId;
$this->middleware(function ($request, $next) {
// fetch your session here
$this->userId = Auth::user()->id;
return $next($request);
});
In your index method of that controller
public function index()
{
echo $this->userId;
}
Also make sure user has logged in, otherwise session will not exist for user.
Hope this will help :)
In Laravel 5.3 and later, the session is not available in controller constructors because the framework invokes these before running the middleware, so auth services have not been initialized.
The documentation suggests the following pattern when we need to use sessions or auth in controller constructors:
class ProjectController extends Controller
{
protected $currentUserId;
public function __construct()
{
$this->middleware(function ($request, $next) {
$this->currentUserId = Auth::user()->id;
return $next($request);
});
}
}
This adds a middleware callback to the end of the middleware chain which sets the value of the current user after the session middleware executes. Then we can use $this->currentUserId from the other controller methods.
This object is not available in the constructor.
You can use Midelware or use it in other methods
I'm getting the user_id from the session and using it quite a bit throughout my contrpller. So am looking at ways of retrieving that variable.
I have set everything up to get it (How I understand) but the Variable is returning
null
My Controller looks as follows :
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\VideoLog;
class VideoController extends Controller
{
private $user_id;
public function __construct(Request $request)
{
$user_id = session('id');
$this->user_id = $user_id;
}
public function log_watched(Request $request)
{
dd($this->user_id);
// See If Video Has Been Watched Before....
$video_watched = VideoLog::where('user_id', $this->user_id);
}
}
Is it something to do with the session?
How would I retrieve it?
The reason you're having this issue is because the controller __construct method is run before the middleware that starts the session.
(more information here)
As the post says, you can get round this issue by using the middleware method in the controller's __construct method:
public function __construct()
{
$this->middleware(function ($request, $next) {
$this->user_id = session('id');
return $next($request);
});
}
This will allow you to set the user_id on the controller.
Hope this helps!
Is it bad practice for me to set the auth user inside my base controller as follows:
abstract class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
protected $user;
public function __construct()
{
$this->middleware(function ($request, $next) {
$this->user = Auth::user();
view()->share('signedIn', Auth::check());
view()->share('user', $this->user);
return $next($request);
});
}
}
Or should I be accessing the auth user inside my controller methods as follows:
public function index()
{
$user = Auth::user();
}
I'm asking based on taylors comments (https://laravel-news.com/controller-construct-session-changes-in-laravel-5-3)
However Jeffery Way seems to be setting this in the constructor as demonstrated in a number of lessons on Laracast?
In newer versions, you can't work with session inside controller constructor as you could in 5.2. You're just watching old lessons.
Also, define middleware in its own class, not in a controller.