Reputation: 427
I have an Attachment model which uses the morphs table and morphTo function. I have several models but the main ones include Client, Job, Project and Notes (which is also polymorphic) which can contain several Attachments.
A client is the top-level model. A Client has many Jobs. A Job has many Projects.
I am struggling with a single way to return all attachments of a client, including attachments of each Job, Project, and notes of each job/project under a client.
I currently am running several foreach loops and have a working way, but the queries on the page load range from 60-100 depending on the amount of jobs/projects/notes for each client. I run through each job to check if it has an attachment, if so, I loop through them. Then, I run through $job->notes->attachments
and display those. From there, I dive into another foreach loop pulling all the job's projects, pulling the attachments from each project and then pulling all the notes and looping through that.
Is there a way within Laravel to get all of the Attachments that are somehow attached to a single Client without looping through the way I have? If not, is there a way I can optimize my loops so I don't have to request the attachments for each job/job's notes/project/project's notes?
Upvotes: 0
Views: 563
Reputation: 9171
My advice is to use eloquent-has-many-deep. As example of you can do with that library you can look at the code of three models related with many to many:
class Role extends Model
{
public function users()
{
return $this->belongsToMany('App\Models\User')->withTimestamps();
}
public function permissions()
{
return $this->belongsToMany('App\Models\Permission')->withTimestamps();
}
}
class Permission extends Model
{
use \Staudenmeir\EloquentHasManyDeep\HasRelationships;
public function roles()
{
return $this->belongsToMany('App\Models\Role')->withTimestamps();
}
public function users()
{
return $this->hasManyDeep('App\Models\User', ['permission_role', 'App\Models\Role', 'role_user']);
}
}
class User extends Authenticatable
{
use \Staudenmeir\EloquentHasManyDeep\HasRelationships;
public function roles()
{
return $this->belongsToMany('App\Models\Role')->withTimestamps();
}
public function permissions()
{
return $this->hasManyDeep('App\Models\Permission', ['role_user', 'App\Models\Role', 'permission_role']);
}
}
With these relationships in place and 5 tables involved: users
, role_user
, roles
, permission_role
and permissions
you can retrieve all the permissions of a User model with a call to $user->permissions
, that resolves to only one query with all the joins needed.
Upvotes: 0
Reputation: 2743
I do this all the time. You just need a way to
"...get all of the Attachments that are somehow attached to a single Client without looping through..."
You must consider custom joins, using Laravel Eloquent:
//client_id input here
$client_id = 10;
$att_from_client = Attachment::join('note', function ($join) {
$join->on('note.id', '=', 'attachment.object_id')
->where('attachment.object_type', 'App\\Note');
})
->join('project', 'project.id', '=', 'note.project_id')
->join('job', 'job.id', '=', 'project.job_id')
->join('client', 'client.id', '=', 'job.client_id')
->where('client.id', $client_id)
->get();
dd($att_from_client);
Upvotes: 0