\Request::getSession() returns NULL in Controller construct - laravel

I want to get the session id of the user each time a page is loaded so I use \Request::getSession()->getId() in the controller construct but I get this error
Call to a member function getId() on null
If I use same code in any of the route methods, it works.
How can I solve this?

Try use Illuminate\Support\Facades\Auth; Auth::getSession()->getId();

This is the default functionality of Laravel. Session data is no longer available in the constructor. See:
laravel - Can't get session in controller constructor

Taylor's word about it :
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.

This worked for me:
public function __construct()
{
// No session access from constructor work around
$this->middleware(function ($request, $next) {
\Request::getSession()->getId();
return $next($request);
});
}

Related

Which HTTP request should I use while using updateOrCreate() method in Laravel?

I'm using updateOrCreate but should I use Post Http Request or Put request while I'm using it?
We doesn't know your architecture so it's difficult to give you an appropriate answer.
But, speaking in general termes, A CRUD use the methods as follow:
GET index()
GET create()
POST store()
GET edit($id)
PATCH update($id)
DELETE destroy($id)
In your scenario, I assume you doesn't know the ID of your resource.
In that case it can't be a PATCH (or PUT). The left over would be POST.

Laravel middleware is "bypassed" when i submit the invalid token, but when it is a valid token, the middleware is executed

all my fellow friends, i have a question.
Route::group([
'middleware' => ['ensure.role:store', 'auth:api']
]
For simplification,
i have two roles : ADMIN and STORE
I have created a middleware that will validate user role, and if the user role is correct, then will allow the user to access the route.
It works fine.
I tried using ADMIN Jwt Token to access STORE routes, and rightfully i am kicked out, and vice versa.
But now, if i modify the token, lets say i add a string to any part of the token, and try to access any route, actually i am allowed to.
I tried var_dump and print something on the related middleware, and here are my observation.
1. If the token is VALID as one of the user role, then
the var_dump is executed, (means the middleware is executed)
2. if the token is INVALID as in i add / modify the original
token, then the var_dump is not executed, and so are the
others route middleware.
I am wondering what causes this behavior, and what could be the fix for this issue, as i need to throw 401 unauthenticated in any token invalid case.
Thank you
I figured it out.
After series of testing and reading, i found out that after laravel 5.3 and above, constructor is called before middleware. And because in my constructor i am using an user object before i am authenticated by the middleware, i encountered constructor error, because user is null.
Of course it is a bad practice to use user object in the construct, however due to the convenience of usage, i still decided to use it.
It sounds complex to use closure based middleware as alternative solution
So i use a workaround to do it.
I create a helper function that return me true if there is an user object or return abort(401); if there is no user object, then add this one line to all the constructors.
$this->checkAccess = EnsureRoleUtil::check('admin');
After that, i just do my next constructor as normally
public function __construct() {
$this->checkAccess = EnsureRoleUtil::check('admin');
$this->user = Auth::user();
$this->categoryM = new CategoryManager($this->user);
}
However, to be noted, it is not a good practice, it is just a hack / workaround.

Laravel register extra fields placement

I have some extra fields that need to be filled right after a user is registered.
Right now I've done it with an Event and couple of Listeners but I can't seem to find an elegant way to carry the data from the Registration page to the Listener so it can insert it in.
Should I use Events/Listeners or is there a better way (without changing the registerController).
I was thinking of getting rid of the Events and redirecting to another form right after registering where the other data to be inserted, but it's just couple of fields, so if there's a better way I would appreciate you sharing it.
Latest Laravel version with the default Auth installed.
I know you said without changing the RegisterController, but this way it doesn't change any of the logic inside it:
class RegisterController extends Controller
{
use RegistersUsers;
protected function registered(Request $request, $user)
{
// ... your code here
return redirect($this->redirectPath());
}
}
If your class has a registered() method it will be called right after a successful registration, so you can save the additional data there and then redirect the user.

Laravel 5 - Middleware get user ID and send to controllers

Hello guys !
I'm working on an API that has a middleware authenticating the user with a unique ID. After making sure that this user exists, I want to send his database ID to the controller coming next, whichever it is.
Is that a good idea ? Or should I get that ID somehow after the middleware finished ?
How do I do that ?
Thanks !
Is that a good idea ? Or should I get that ID somehow after the middleware finished ?
It depends on what you want to do and how you routes are declared.
The routing is one of the first thing initialized by Laravel. You cannot pass parameter at run time (correct me if I'm wrong).
Plus, the controllers called after all midlewares has done their work.
I cannot garanty it's the more "beautiful" way to do this, but what i'm use to do is using Session::flash() or Session::put() when I want to pass parameters to my controllers at run time.
I use Session::flash() if the parameter has a one request life time, and Session::put() when I want the variable be more 'consistent' across the whole application.
I don't know if I am clear or not, tell me :)
Well, as long as you don't send that ID passing through the HTTP protocol, you should be fine since the user won't be able to tamper with the data.
That said, if you are using Laravel's built-in Auth module, you should just do an Auth::user() call at the other controller and it will give you the authenticated user.
If that isn't an option, you should create a function in the other controller that accepts $id as a parameter. You can call that function from within the first controlling by constructing the second controller throug $secondController = App->make(SecondController) and then $secondController->receiverFunction($id)
If you want the currently-authenticated user available in your application, just add it your base controller:
<?php namespace App\Http\Controllers;
use Illuminate\Contracts\Auth\Guard;
abstract class Controller {
protected $auth;
protected $currentUser;
public function __construct(Guard $auth)
{
$this->auth = $auth;
$this->currentUser = $this->auth->user();
}
}

Test route dispatch

I have an API with a scenario that forwards a request onto another controller.
ie:
$request = Request::create'/new/resource', 'POST');
Route::dispatch($request);
How would I write a test to verify this dispatch happens as I expect? (I know I'm not supposed to mock the 'Request' facade)
ie:
class MyTest extends TestCase {
public function myTestShouldForwardRequestCorrectly()
{
// Once for initial request, and once for fwd request?
// Maybe also test w/ mockery spy which resource the Request is going to?
$m = Route::shouldReceive('dispatch')->times(2);
.... setup test ...
$this->call('POST', '/initial/resource', $parameters);
}
}
You dont have to mock Request - just verify that it is beeing sent. Dispacth will be verified upon controller action. When you call:
$this->call("POST","/path",$params);
You are triggering route collection which act as a lookup table. That collection is storing all predefined routes. So you will have to hook into that collection, to verify your own dispatch. Whole response process ih handled by TTPKernelInterface, and act like a stack - which returns response to user. To test, you will have to do a lot of mocking, because of dependencies. You may take a look at core Laravel tests directory. There you can find how Taylor Otwell tested whole framework without application - by simulating request. I learned a lot from there.

Resources