Any way to change the user instance returned by Auth::user(), what I want is to eager load some relations with it, so i don't have to keep typing it every time:
from
Auth::user();
to
Auth::user()->with('company')->first();
and every time I request the Auth::user() I get the Auth::user()->with('company')->first() returned.
One way of doing it is to edit your before filter (app/filters.php).
App::before(function($request)
{
if (Auth::check())
{
Auth::setUser(Auth::user()->with('company')->first());
}
});
That way you can still use Auth::user() wherever you need.
One method which I follow is to set the Auth::user() in the BaseController and it will beaccessible in all the controllers. If you are using in Views you can View::share() to make it available in all views. Here you can eager load your relationships.
class BaseController extends Controller {
protected $currentUser;
public function __construct() {
$this->currentUser = Auth::user(); // You can eager load here. This is will null if not logged in
}
protected function setupLayout()
{
if ( ! is_null($this->layout))
{
$this->layout = View::make($this->layout);
}
View::share('currentUser', $this->currentUser);
}
Related
How do you use the show function relationships? i know this works:
public show ($id) {
Model::with('relationship')->find($id);
}
but with the new format
public show(Model $model) {
}
how do you include the relationship?
i've tried
$model->with('relationship')->get();
but it changes the value from an object to an array, what would be the proper way to do this?
Lets lazy eager load that:
public show(Model $model) {
$model->load('relationship');
}
That's not a "new format". That's in fact Route model binding which is a convenient way to work as an API. https://laravel.com/docs/9.x/routing#route-model-binding
When you have a route such as
Route::get('/users/{user}', [UserController::class, 'show']);
Your controller will receive the model already fetched from database.
If you need to use additional relationships you have 2 options (let's assume that user has a profile relationship):
Eager load on controller
public show(User $user) {
$user->load('profile');
return $user;
}
Or eager load in your RouteServiceProvider.php by using explicit binding. https://laravel.com/docs/9.x/routing#explicit-binding
/**
* Define your route model bindings, pattern filters, etc.
*
* #return void
*/
public function boot()
{
Route::bind('user', function ($value) {
return User::with('profile')->findOrFail($value);
});
}
Therefore you will have the user with it's profile in your controller
Can I access session data from Controller, without passing the request from MyController?
class Controller extends BaseController
{
public function __construct()
{
// ** next line throws error:
// "Session store not set on request."
$userdata = request()->session()->get('userdata');
// I want to inject `userdata` into every template without
// passing data from child controllers.
view()->share(['userdata' => $userdata);
}
}
class MyController extends Controller
{
public function __construct(Request $request)
{
// This works, so the data is in fact in the session.
// I don't want to pass it, or `$request` to the parent from here.
$userdata = $request->session()->get('userdata');
...
}
}
The reason it won't be working in your __construct() method is because the StartSession middleware won't have been run yet.
To get around this you can simply use the middleware() method on the controller:
public function __construct()
{
$this->middleware(function ($request, $next) {
$userdata = $request->session()->get('userdata');
view()->share(compact('userdata'));
return $next($request);
});
}
Laravel 5.3 Upgrade guide (Scroll down the Controllers section)
In Laravel 5.3, you can't access the session or authenticated user in your controller's constructor because the middleware has not run yet.
As an alternative, you may define a Closure based middleware directly in your controller's constructor.
We have decided to use Laravel for a project as a test run for future frameworks and are really enjoying it. There is one issue we are having though.
We use the trait Illuminate\Foundation\Auth\AuthenticatesUsers which handles user authentication. It works well. However, we have a column in the database called userstatus which could be a 0 or a 1.
How do we inject this where clause into the Illuminate\Foundation\Auth\AuthenticatesUsers trait?
I was thinking maybe something here (in my LoginController):
public function authenticated($request , $user){
//if $user->userstatus != 1 logout and redirect to start page
}
But I dont know how to logout (im looking into that now) .
your logic is right, you should redefine login and authenticated methods within LoginController.
your methods should be like below:
this method should be within your LoginController.php:
class LoginController extends Controller
{
use AuthenticatesUsers {
login as public loginParent;
}
protected function login(Request $request){
$default = '/';
$user = User::where('email', $request->get('email'))->NotActive->first();
if($user){
return redirect()->intended($default);
}
return $this->loginParent($request);
}
protected function authenticated(Request $request, $user)
{
if($user->not_active) {
$this->logout($request);
}
}
}
then we should create ScopeNotActive method within User.php Model as Local Scope:
//User.php
public function ScopeNotActive($query){
return $query->where('userStatus', '!=', 1);
}
and a Mutator to check if the user is not active:
// User.php
public function getNotActiveAttribute(){
return $this->userStatus != 1;
}
I would like to use a User class throught the application. So, I would like to create CustomUser and then inject it into controllers that need it (it would be most of them).
Now, I create an empty instance in serviceprovider. Next, I want to fill it with data that are already saved in Auth::user(). After long time I have not found where to do it.
Auth::user() is empty in middlewares, but is filled with the user data in controllers. I am missing the step where Laravel queries the database and fills Auth:user() with data. I want to avoid making the same query again.
Thanks for any help!
You can use base controller with __get() method. For example:
class Controller
{
public function __get(string $name)
{
if($name === 'user'){
return Auth::user();
}
return null;
}
}
And in the child controllers can call $this->user
Since Laravel 5.3, you do not have access to sessions in controller constructors. This is because the middleware has not been run yet. I know it's difficult to locate, but in the migration documentation from 5.2 > 5.3 (you're probably on 5.4), it shows that the proper way to resolve data from sessions (which auth() is just a wrapper around a session() call to get the user), is to use the following method:
class MyController extends Controller {
protected $user;
public function __construct() {
$this->middleware(function ($request, $next) {
$this->user= auth()->user();
return $next($request);
});
}
}
Then $this->user will reference the auth user to any methods inside of this controller.
Hopefully his helps.
In Laravel 5.6 i used this
$this->middleware(function ($request, $next) {
$id = Auth::user()->id;
$res = $this->validateAnyFunction($id);
if(!$res){
//to redirect to any other route
return $next(redirect()->route("any")->with("failed","Invalid")->send());
}
//this is used to proccess futher funcitons of controller
return $next($request);
});
I have two View composers in my AppServiceProvider class, below:
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
View::composer('left', function ($view)
{
if (Auth::check())
{
$user = Auth::user();
// Gets a list of the people the user is following
$usersFollowing = Following::where('user_id', $user->id)
->get();
// More queries here
View::share('usersFollowing', $usersFollowing);
}
});
View::composer('right', function ($view)
{
if (Auth::check())
{
$user = Auth::user();
// Gets a list of the people the user is following
$usersFollowing = Following::where('user_id', $user->id)
->get();
// More queries here
View::share('usersFollowing', $usersFollowing);
}
});
}
}
As you can see, both composers request the same query data ($usersFollowing). Both of these layouts (left.blade.php and right.blade.php) are called on all of my pages (by including them in the base layout).
The problem with this is that the page is requesting $usersFollowing twice on a single page load. It's calling the query once for left.blade.php and once for right.blade.php.
I'm also calling Auth::user() twice, once in each composer.
How can I prevent these queries from being called twice for the same request, and only call it once?
I think it is simple to move your queries to top of your method and use them inside both View composers. This way your query would only run once.
Here is my proposed way of doing this;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
$user = Auth::user();
// Gets a list of the people the user is following
$usersFollowing = Following::where('user_id', $user->id)
->get();
// You can use `use` keyword to access external variables inside callback function.
//Both of these variables will be accessible inside callback
View::composer('left', function ($view) use ($usersFollowing,$user)
{
if (Auth::check())
{
// More queries here
View::share('usersFollowing', $usersFollowing);
}
});
View::composer('right', function ($view) use ($usersFollowing,$user)
{
if (Auth::check())
{
// More queries here
View::share('usersFollowing', $usersFollowing);
}
});
}
}
I hope this can be helpful and you can generalize this method to any other situations where you need this kind of functionality.