I am working on a hybrid app build with Laravel and Vue. I have a use case where not all users have certain relations. For example a client can have a Domain and Multiple Business Units.
Currently i have set it up like this:
<?php
namespace App\Models;
use Laravel\Sanctum\HasApiTokens;
use Spatie\MediaLibrary\HasMedia;
use Illuminate\Notifications\Notifiable;
use Lab404\Impersonate\Models\Impersonate;
use Spatie\MediaLibrary\InteractsWithMedia;
use Illuminate\Database\Eloquent\Casts\AsArrayObject;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements HasMedia
{
use Traits\BaseModelTrait;
use Traits\ActiveTrait;
use InteractsWithMedia;
use Impersonate;
use HasApiTokens;
use Notifiable;
use HasFactory;
protected $hidden = [
'password', 'remember_token',
];
protected $fillable = [
'name', 'email', 'password', 'avatar',
];
protected $casts = [
'settings' => AsArrayObject::class,
'is_admin' => 'boolean',
];
protected $with = [
'domain',
'BusinessUnits'
];
public function scopeAdmin($query)
{
return $query->where('is_admin', true);
}
public function scopeEmployee($query)
{
return $query->whereNull('domain_id');
}
public function scopeClient($query)
{
return $query->whereNotNull('domain_id');
}
public function BusinessUnits()
{
return $this->belongsToMany(BusinessUnit::class, 'users_business_units_pivot');
}
public function Domain()
{
return $this->belongsTo(Domain::class);
}
}
The "problem" with this approach is that for every request 2 queries are executed for each user. I want the relations eager loaded only if the "domain_id" is not null (scopeClient). For normal "models" i can select per page what models should be loaded etc., but for the authenticated user this is not really possible as i know.
I think i am looking for something like this:
protected $with = [
(!$this->domain_id) ? 'domain' : null,
(!$this->domain_id) ? 'BusinessUnits' : null
];
This currently generates an error: "Constant expression contains invalid operations."
Any advice and or ideas to tackle this would be appreciated!
CodePudding user response:
You can try using events:
// this code should be inside your model
public static function boot()
{
parent::boot();
self::retrieved(function($model){
if($model->domain_id !== null)
{
$model->load('domain', 'BusinessUnits');
}
});
}
and obviously, you have to remove those relations from $with
CodePudding user response:
To get all the user that has domains, use whereHas()
$users = User::whereHas('Domain')->with(['Domain', 'BusinessUnits'])->get();
it will lauch 3 queries, one for the users, one for the domains and one for the business units.