Lazy Eager Loading in Laravel
Sometimes you may need to eager load a relationship after the parent model has already been retrieved. For example, this may be useful if you need to dynamically decide whether to load related models:
$books = App\Models\Book::all();
if ($someCondition) {
$books->load('author', 'publisher');
}
If you need to set additional query constraints on the eager loading query, you may pass an array keyed by the relationships you wish to load. The array values should be Closure
instances which receive the query instance:
$author->load(['books' => function ($query) {
$query->orderBy('published_date', 'asc');
}]);
To load a relationship only when it has not already been loaded, use the loadMissing
method:
public function format(Book $book)
{
$book->loadMissing('author');
return [
'name' => $book->name,
'author' => $book->author->name,
];
}
Nested Lazy Eager Loading & morphTo
If you would like to eager load a morphTo
relationship, as well as nested relationships on the various entities that may be returned by that relationship, you may use the loadMorph
method.
This method accepts the name of the morphTo
relationship as its first argument, and an array of model / relationship pairs as its second argument. To help illustrate this method, let's consider the following model:
<?php
use Illuminate\Database\Eloquent\Model;
class ActivityFeed extends Model
{
/**
* Get the parent of the activity feed record.
*/
public function parentable()
{
return $this->morphTo();
}
}
In this example, let's assume Event
, Photo
, and Post
models may create ActivityFeed
models. Additionally, let's assume that Event
models belong to a Calendar
model, Photo
models are associated with Tag
models, and Post
models belong to an Author
model.
Using these model definitions and relationships, we may retrieve ActivityFeed
model instances and eager load all parentable
models and their respective nested relationships:
$activities = ActivityFeed::with('parentable')
->get()
->loadMorph('parentable', [
Event::class => ['calendar'],
Photo::class => ['tags'],
Post::class => ['author'],
]);