I have a situation where I need to iterate through a models relationships (1 to many) and call a function on the children. i.e.
$parent = ParentClass::find(1)
$children = $parent->children;
foreach($children as $child)
{
$child->function();
}
The function inside the child needs to access fields from the parent model. i.e.
public function function()
{
if($this->parent->attribute)
return "True!";
return "False";
}
Executing this as above, ends up with an N+1 query problem. Each child ends up executing "SELECT * FROM parents WHERE id = 1".
I've had 3 thoughts on how to fix this, though two of them feel awful, and the last one just doesn't seem great to me, so I'm asking is there a better solution to this than what I have considered?
Solution 1: Eager load the parent onto the child models. i.e.
...
$children = $parent->children;
$children->load('parent');
foreach($children as $child)
...
I think it's pretty obvious why this would be awful, this would be a tremendous memory hog to have the parent model stored in memory N+1 times.
Solution 2: Pass the parent to the child as an argument, i.e.
...
foreach($children as $child)
{
$child->function($parent);
}
...
Avoids the memory issue of 1, but it still feels ugly. I would think the child should know it's parent, and not need to be told it through the method args.
Solution 3: Add remember() to the child's parent relationship i.e.
public function parent()
{
return $this->hasOne('Parent')->remember(1);
}
Since all the children have the same parent, this will cache the query, and avoid calling it for every child. This seems the best of these 3 solutions, but I don't like the idea of having this be something that becomes mandatory on the relationship.
Is there a better approach to this that I am not considering? Maybe a better place to include the remember function?
Thank you, -Wally