I have a problem that I have been stuck with for days, I'd appreciate any help from you guys.
I have a projects table that either can be assigned to a user or a team, this is the structure:
id
assignable_id
assignable_type
class Project extends Model {
public function assignable(): MorphTo
{
return $this->morphTo();
}
}
and my team table contains members with a pivot table:
id
class Team extends Model {
public function users(): BelongsToMany
{
return $this->belongsToMany(User::class);
}
public function projects(): MorphMany
{
return $this->morphMany(Project::class, 'assignable');
}
}
// team_user table
team_id
user_id
and finally my user table:
id
class User extends Model {
public function teams(): BelongsToMany
{
return $this->belongsToMany(Team::class);
}
public function projects(): MorphMany
{
return $this->morphMany(Project::class, 'assignable');
}
}
Now the problem is I want to get all projects that have been assigned to a user either directly or through a team, as expected $user()->projects return the ones that directly have been assigned to the user.
I tried many solutions but none has worked for me yet.
Thanks in advance...
CodePudding user response:
So you actually need something like this:
public function project()
{
return $this->hasManyThrough('App\Project', 'App\User', 'assignable_id')
->where(
'assignable_type',
array_search(static::class, Relation::morphMap()) ?: static::class
);
}
or
public function project()
{
return $this->belongsToMany(Project::class, 'assignable', 'assignable_id', 'project_id')
->where('assignable_type', static::class);
}
Ref: Laravel Polymorphic Relations Has Many Through
Your working solution:
public function projects() {
return $this->hasManyThrough(
Project::class,
User::class,
'id',
'assignable_id',
)->where(
'assignable_type', User::class
)->orWhere(function ($q) {
$q->where('assignable_type', Team::class)
->whereIn('assignable_id', $this->teams->pluck('id'));
});
}
CodePudding user response:
Use whereHasMorph
:
$user = ...
$projects = Project::whereHasMorph(
'assignable',
[Team::class, User::class],
function ($query, $type) use($user) {
if($type === Team::class){
$query->whereRelation('users', 'id', $user->id);
}else{
$query->where('id', $user->id);
}
}
)->get();
Or split into 2 queries and merge together:
$projects = $user->projects;
$teams = $user->teams()->with('projects')->get();
$teams_projects = $teams->pluck('projects')->collapse();
$projects = $projects->merge($teams_projects);