pbocian
pbocian

Reputation: 21

How to get filtered Laravel relationship models?

is it possible in Laravel 8.0 to get filtered relationship models?

Example: In the controller I have

 $thread = Thread::find(1);

 // example logic between getting the thread and passing to JsonResponse
 $thread->messages = $thread->messages->filter(function (Message $message) {
     return $message->type_id === 3;
 });

 return new JsonResponse($thread);

Thanks to call $thread->messages I have lazy loaded messages in the response, but it lazy load all messages that belongs to that thread and I just want to get filtered ones. How can I achive that?

Thread model

public function messages(): HasMany
{
    return $this->hasMany(Message::class);
}

Message model

public function type(): HasOne
{
    return $this->hasOne(MessageType::class, 'id', 'type_id');
}

Upvotes: 0

Views: 62

Answers (2)

IGP
IGP

Reputation: 15786

You could pass a Closure to the load method to lazy load them.

$thread = Thread::find(1);

$thread->load(['messages' => function ($message) {
    return $message->where('type_id', 3);
}]);

return new JsonResponse($thread);

or do the same using the with method.

$thread = Thread::with(['messages' => function ($message) {
    return $message->where('type_id', 3);
}])->find(1);

return new JsonResponse($thread);

Short-hand Closure (PHP version >= 7.4)

$thread = Thread::with(['messages' => fn ($m) => $m->where('type_id', 3)])->find(1);
$thread = Thread::find(1);

$thread->load(['messages' => fn ($m) => $m->where('type_id', 3)]);

Separate relationship

# Thread model
// or whatever name makes sense in your application
public function active_messages() 
{
    return $this->hasMany(Message::class)->where('type_id', 3);
}
$thread = Thread::with('active_messages')->find(1);
$thread = Thread::find(1);

$thread->load('active_messages');

In terms of queries, all options are the same.

Upvotes: 2

Yves Kipondo
Yves Kipondo

Reputation: 5603

You can pass a function in which you will perform some check before eager loader message which are related to the thread like this

Thread::with(["messages" => function($query){
    $query->where("type_id", 3);
})->find(1);

Upvotes: 1

Related Questions