Trait for user Model
Hi there , I have a multi tenant project the tenants are restaurant name and users belong to one restaurant. I want to show all the users from the user resource when the logged in user has a Admin role. Otherwise, managers can only see restaurants belonging to the user , restaurant_id.
I was able to write a trait that works great when i have users logged in. Once I sign out the user I get the following message.
the code of the trait is:
<?php
namespace App\Traits;
use Illuminate\Database\Eloquent\Builder;
trait FilterByRestaurant
{
protected static function boot(): void
{
parent::boot();
$restaurantId = auth()->user()->restaurant_id;
self::creating(function($model) use ($restaurantId){
$model->restaurant_id=$restaurantId;
});
if ( ! auth()->user()->hasRole('Admin')) {
self::addGlobalScope(function(Builder $builder) use($restaurantId){
$builder->where('restaurant_id',$restaurantId);
});
}
}
}
Can you please help me to figure out what my issue is?
Thanks
18 Replies
Not sure why you wouldn't just put the auth check in the global scope directly.
But yeah, if you aren't logged in, auth()->user() returns null. So you'd have to nullsafe it like ...
$restaurantId = auth()->user()?->restaurant_id;
... then test for restaurantId being null and do whatever you need for that situation.Thanks Hugh, I did what you recommended but im getting the same error
Did you do like this?
VP,
I did it but now im getting
You need to put
if ( ! auth()->user()->hasRole('Admin')) {
inside if ($restaurantId)
also. the error came because you don't have auth()->user()
<?php
namespace App\Traits;
use Illuminate\Database\Eloquent\Builder;
trait FilterByRestaurant
{
protected static function boot(): void
{
parent::boot();
$restaurantId = auth()->user()?->restaurant_id;
if ($restaurantId){
self::creating(function($model) use ($restaurantId){
$model->restaurant_id=$restaurantId;
});
}
if ( ! auth()->user()->hasRole('Admin')) {
if($restaurantId){
self::addGlobalScope(function(Builder $builder) use($restaurantId){
$builder->where('restaurant_id',$restaurantId);
});
}
}
still get the error
Same problem, you aren't nullsafing your second call to auth()->user().
And I'm still really confused by the approach you are taking. COnditionally adding a scope, rather than just having a global scope which itself tests the user's role.
the reason im doing it this way is because i only want managers to see only the users corresponding to the restaurant where the belong to and the admins to see all of them. Im open to adding the global scope but not really sure where to define that
https://laravel.com/docs/10.x/eloquent#global-scopes
Then just do your testing for restaurant_id / hasRole in the apply() method.
Laravel - The PHP Framework For Web Artisans
Laravel is a PHP web application framework with expressive, elegant syntax. We’ve already laid the foundation — freeing you to create without sweating the small things.
Thanks Hugh, I will investigate this approach
Your use case is exactly what global scopes are for.
Or, you could add a local scope to the model, and include it in the table query on your resource.
But in a tenancy environment, it usually belongs globally.
Additionally, you can always ->withoutGlobalScope / Scopes() if needed in an exceptional case.
Should probably also read up on policies, so non admins can't edit resources they don't own by just changing an ID on an edit link.
Thanks All , I was able to figure out a solution
So how did you do it in the end?
Hugh, I did try the global scope and didn't work either. My code in the scope was $restaurantId = auth()->user()->restaurant_id;
$builder->where('restaurant_id','=',$restaurantId);
however all I got was a white screen. What I did was to add this code to the user resource / listuser page protected function getTableQuery():Builder{
$restaurantId = auth()->user()->restaurant_id;
return User::
where('restaurant_id', '=', $restaurantId);
}
this way i was able to filter the users per restaurant. I created a table in the dashboard to see all the users for all restaurants when an admin was logged in.
not the most elegant solution but for my use does the job.
thanks all for your input
I also tried to add a when statement to the protected function getTableQuery() but it seems its not allowed with that function. Hence the table in the dashboard
An update, I was finally able to make it work with the original trait. The issue was the exclamation mark in the code.