UPDATE (SOLUTION)
->user
relationship from one of the $image
inside $user->images
, then $user
variable is already available cause you loaded the ->images
from it!protected $with
Eloquent property. It's an anti-pattern.ORIGINAL
I'm running into what I believe is a simple problem:
User
object that has many Image
sImage
belongs to User
... (inverse relation)My problem is that I want to eager load both the images()
on the User
model and the user()
on the Image
model. To do so, I just setup a $with
property as explained in the docs.
My User
model:
class User extends EloquentModel {
protected $with = ['images'];
public function images()
{
return $this->hasMany(Image::class);
}
}
My Image
model:
class Image extends EloquentModel {
protected $with = ['user'];
public function user()
{
return $this->belongsTo(User::class);
}
}
But when performing:
$user = User::find(203);
This results in an infinite loop (php segmentation fault). There must be some kind of circular reference that I am not able to locate:
[1] 85728 segmentation fault
EDIT 2016/02
This is the simplest "Workaround" I found:
// User.php
public function setRelation($relation, $value)
{
if ($relation === 'images') {
foreach ($value as $image) {
$image->setUser($this);
}
}
return parent::setRelation($relation, $value);
}
Eager loading is the process whereby a query for one type of entity also loads related entities as part of the query. Eager loading is achieved by the use of the Include method. It means that requesting related data be returned along with query results from the database.
While lazy loading delays the initialization of a resource, eager loading initializes or loads a resource as soon as the code is executed. Eager loading also involves pre-loading related entities referenced by a resource.
Eager loading is super simple using Laravel and basically prevents you from encountering the N+1 problem with your data. This problem is caused by making N+1 queries to the database, where N is the number of items being fetched from the database.
Relationship Methods Vs.Dynamic properties are "lazy loading", meaning they will only load their relationship data when you actually access them. Because of this, developers often use eager loading to pre-load relationships they know will be accessed after loading the model.
There is a without()
method: https://laravel.com/api/5.8/Illuminate/Database/Eloquent/Builder.html#method_without
Placing without()
on both sides of a relationship worked.
class Property extends EloquentModel {
protected $with = ['images'];
public function images()
{
return $this->hasMany(Image::class)->without('property');
}
}
class Image extends EloquentModel {
protected $with = ['property'];
public function property()
{
return $this->belongsTo(Property::class)->without('images');
}
public function getAlt()
{
return $this->property->title;
}
}
UPDATE:
Even though using without()
easily avoid the infinite loop issue, through years of experience with Laravel I realize it is bad practice to set $with
in the model as it causes relationships to always load. Hence leading to circular reference/infinite loop
Rather, always use with()
to explicitly specify necessary relationships to be eager loaded, however deep necessary (relationship of relationship)
For example:
$user = User::with('images' => function ($query) {
$query->with('property' => function ($query) {
$query->with('deeperifneeded' => function ($query) {
//...
});
});
]);
Note: May need to remove without()
When you try to find a Property, that property eager loads all the images it has and every Image eager loads the property it belongs to, which is the property you try to find, which will again start to eager load all the images it has. etc...
The way I would resolve this problem is by not eager loading inside the models, but by eager loading when calling the models.
so using the following:
$prop = Property::with('images')->find(203);
while removing this line in the Property model:
protected $with = ['images'];
And this line in the Image model:
protected $with = ['property'];
I hope this solution works for you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With