Search on Eloquent Relationships

Mostly we use filters and scopes directly on our eloquent model. Also, it’s possible we want to return a dataset based on the relationships connected our model. In this post, we want to review a basic concept of “nested” search on eloquent relationships.

The Basic Concept

Let’s say we have a ticket reservation system. We have two primary models, the User, and the Ticket models. We want to execute the search only on the tickets, but with the User’s name, who bought the ticket. So the question is, how can we return a dataset of tickets by searching the user’s name?

Setting Up the Relationship

A user owns a ticket, in other words, it belongs to a user. Let’s create the relationship between the models.

public function user()
{
    return $this->belongsTo(User::class);
}

Now we can perform a query on the User model trough the Ticket model.

Perform the Nested Query

Let’s say we want to filter the results in our TicketsController. All we have to do is to implement the functionality we want to use. But as we said, we want to apply our criteria on our User model through our Ticket model.

Laravel provides a nice way to use “nested” queries, with the whereHas and the orWhereHas methods. With the help of this, we can easily do what we want now:

// TicketsController.php

public function index(Request $request)
{
    $tickets = Ticket::whereHas('user', function ($query) use ($request) {
        $query->where('name', 'like', "%{$request->name}%");
    });

    return view('tickets.index', compact('tickets));
}

Summary

This approach can be a very nice and clean way when we work with models what contains less relevant data for the user, but still, want to access to it directly by a relationship’s condition.

Our job is not more, but define the relationship, then use the whereHas, orWhereHas, whereDoesntHave methods on our model. We reference the relationship as the first parameter, then pass the condition as the second.

Nice and clean, still dominant feature of the Laravel framework!