no, no
only return a relationship in the model you cannot run queries inside a relationship definition
Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.
When using the Eloquent with function to eager loading with when function where is user role check, it is always true because Eloquent get always the first record of the roles table (that this user is admin). This is not the problem when eager loading is not used and lazy load is used.
Steps To Reproduce: Models to simulate this issue is below, also using spatie/laravel-permission role system. But this is not with the role system, because I test it on any other relationship with the user and there is the same issue.
User.php
class User extends Authenticatable implements MustVerifyEmail
{
use HasRoles, HasFactory, Notifiable;
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* Send the email reset notification
* @param string $token
*/
public function sendPasswordResetNotification($token)
{
$this->notify(new ResetPasswordNotification($token));
}
/**
* Send the email verification notification.
*
* @return void
*/
public function sendEmailVerificationNotification()
{
$this->notify(new VerifyEmailNotification());
}
}
Product.php
class Product extends Model
{
use HasFactory, Searchable;
protected $table = 'products';
public function offers() {
return $this->hasMany(Offer::class)->whereHas('shop', function ($query) {
$query->where('is_active', '=', true);
$user = auth()->user();# Could be also User::find(136);, but not working too
$query->when($user != null && ($user->hasRole('admin')), function ($query) use ($user) {
$query->orWhere('name', '=', 'adminshop');
});
return $query;
});
}
}
Offer.php
class Offer extends Model
{
use HasFactory, SoftDeletes;
protected $table = 'offers';
public $dates = ['created_at', 'updated_at', 'deleted_at', 'last_seen_at'];
public function shop() {
return $this->belongsTo(Shop::class);
}
public function product() {
return $this->belongsTo(Product::class);
}
public function price() {
return $this->hasOne(OfferPrice::class)->orderByDesc('created_at');
}
public function getLastPrice() {
$price = $this->price;
if($price == null) {
return 0;
} else {
return $price->price;
}
}
}
Category.php
class Category extends Model
{
use HasFactory, Searchable;
protected $table = 'categories';
public function products() {
return $this->belongsToMany(Product::class);
}
}
When running the code below, it shows also offers from adminshop even when the user is not an admin.
$category->products()->with(['offers', 'offers.price']);
When using dd to dump data, the user is ok:
#original: array:16 [▼
"id" => 136
"nickname" => "moderated"
"name" => null
"surname" => null
"avatar" => null
"email" => "moderated"
"email_verified_at" => "2022-01-03 14:49:57"
"password" => "moderated"
"remember_token" => "moderated"
"created_at" => "2022-01-03 14:47:00"
"updated_at" => "2022-01-03 14:49:57"
]
but the relationships (this is the roles table - but it same for all relationships) are wrong because are not for that user!
#original: array:8 [▼
"id" => 1
"name" => "admin"
"guard_name" => "web"
"created_at" => "2021-12-01 13:38:53"
"updated_at" => "2021-12-01 13:38:53"
"pivot_model_id" => 1 #<- THIS IS WRONG! supposed to be 136 or no result found
"pivot_role_id" => 1
"pivot_model_type" => "App\Models\User"
]
When loading lazy load relationships there is no problem and data is loaded correctly. When using edger loading, always is dumped the first rows in the relationships tables, but why?
For anyone who has this issue with creating relationships with the condition, make only the relation definition of that model. For this example:
class Product extends Model
{
public function offers() {
return $this->hasMany(Offer::class);
}
}
then in the controller, check if it is admin and create a query
$isAdmin = auth()->user() != null && auth()->user()->hasRole('admin');
$sets = $category->products()->with(['offers' => function($q) use ($isAdmin ) {
$q->where('offers.last_seen_at', '>', Carbon::now()->addDays(-1));
$q->whereHas('shop', function ($query) use ($isAdmin ) {
$query->where('is_active', '=', true);
$query->when($isAdmin, function ($query) use ($isAdmin ) {
$query->orWhere('shops.name', '=', 'adminshop');
});
return $query;
});
}, 'offers.price']);
Please or to participate in this conversation.