Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Constantinff's avatar

Lazy Eager Loading with condition on current model

I got relation between two models which depends on a value from current model

With the example of docs:

$books = App\Book::all();
$books->load('author', 'publisher');

Books model:

    public function author()
    {
    // here I expected to have access to `$this->author_type` and add some conditions to the relation
    // but `$this` is empty model
        return $this->belongsTo('Author');
    }

lazy loading accessing $books->first()->author works as expected

0 likes
9 replies
ajithlal's avatar

you can check the condition while fetching books.

$books = App\Book::with('author','publisher')
                 ->whereHas('author', function($query) {
            //you can check your conditions here like:
            $query->where('book.author_type', '=', "your value");
        });

hope this will help you.

Constantinff's avatar

The value I need to compare is a Book model attribute, that is why cant do it with eager load.

Also I have simplified the given example, and it can not be solved with some extra query.

Nakov's avatar

@constantinff but author_type is property of the Books model, or part of the Author?

If it is part of the Author, then the query should be appended to the relationship I think:

public function author()
{
    return $this->belongsTo('Author')->where('author_type', 'Poems');
}

Are you looking for this or?

Constantinff's avatar

I will extend a bit the example

Book:

- id: 1
- title: Measure for Measure
- author_type: stories

And I have Authors records

- id: 1
- name: William Shakespeare (Poems)

-id: 2
- name: William Shakespeare (Stories)

and I need to add a condition to the Book -> Author relation

Books model:

    public function author()
    {
        return $this->belongsTo('Author')->where('name', 'like', '%(' . ucfirst($this->author_type) . ')');
    }

(this is just abstract example with books -> author)

$book = Book::find(1);

$book->load('author'); // does not work because it does not add the proper condition

$book->author; // works

rodrigo.pedra's avatar

As eager load will perform a separate query you don't have direct access to the parent table, so you need to join it.

    public function author()
    {
        return $this->belongsTo(Author::class)
            ->selectRaw('authors.*')
            ->join('books', 'authors.id', '=', 'books.author_id')
            ->whereRaw("authors.name LIKE CONCAT('%', books.author_type, '%')");
    }

What I don't quite understand is how this is going to be different from not applying the condition as this is a belongs to relation, so each book is already bound to one author.

1 like
Constantinff's avatar

@rodrigo.pedra thank you for your answer

eager load will perform a separate query you don't have direct access to the parent table

This is what I needed to know.

Another solution might be:

            $books->each(function ($book) {
                $book->load(['author' => function ($query) use ($book) {
                    $query->where('name', 'like', '%(' . ucfirst($book->author_type) . ')');
                }]);
            });

just instead single query, it it makes one per $book

rodrigo.pedra's avatar

Sure,if you have few books, maybe after filtering for some other field, that won't be a problem. But in general it is a good idea to avoid making a query for each model (called N+1 problem).

Please or to participate in this conversation.