Reputation: 907
I have a DB table that stores my job titles so as not to duplicate them, and the Job model has relationships internally, so when I use the Eloquent Model I have to always call or load the JobTitles model over and over again. Is there a way to always use the Job Model with pre-loaded JobTitles inside?
class Job extends Model
{
use Notifiable;
protected $fillable = [ ... ];
protected $hidden = [
'token',
];
public function title()
{
return $this->belongsTo('App\Models\JobTitle','job_title_id');
}
public function people()
{
return $this->belongsToMany('App\Models\Person','job_person','job_id','person_id');
}
}
This is JobTitle model
class JobTitle extends Model
{
use Notifiable;
protected $table = "job_titles";
protected $primaryKey = 'job_title_id';
protected $fillable = [
'name',
];
protected $hidden = [
'token',
];
public function jobs()
{
return $this->hasMany('App\Models\Job','job_title_id');
}
}
Now my code inside of the controller looks like this:
$job = Job::all()->load('title');
It is working fine but when I am calling jobs from people
$personJobs = Person::find(1)->jobs()->load('title')->get();
gives error, Any ideas how this is done?
Upvotes: 0
Views: 1975
Reputation: 140
To always use the Job Model with pre-loaded JobTitles inside. you can add $with
attribute in your job model:
class Job extends Model
{
use Notifiable;
protected $with = ['title'];
}
Upvotes: 1
Reputation: 17206
When calling a relation by the method $person->jobs()
you will end up with a query builder, so you can't call the model methods like load()
since you dont have an instance of a model.
It would be more efficient to call for the relations before getting the first result (nested eager loading)
$person = Person::with('jobs.title')->find(1);
$personJobs = $person->jobs;
If you dont want to query the person data from the database you should use whereHas
$personJobs = Job::whereHas('people', function($personQueryBuilder) {
$personQueryBuilder->where('id',1);
})->with('title')->get();
Upvotes: 1
Reputation: 93
load()
is executed after the query has been executed. It's called lazy-loading. Eager loading is using with()
.
Eager loading is generally faster than lazy loading (I could be wrong on this one, correct me if I'm wrong).
Also, using jobs()
or any other relationship, this will return the relationship object itself, while accessing it via ->Jobs
will execute the relationship query and will return a collection (if many) or model (if one).
The reason why $personJobs = Person::find(1)->jobs()->load('title')->get();
doesn't work is because you're essentially saying "The jobs hasMany relationship will load the "title" which won't work because hasMany
doesn't have the load()
function.
So if you want to solve this, you can do Person::with('jobs.title')->find(1)
or Person::find(1)->load('jobs.title')
Upvotes: 1