Refine for Laravel
A package by Hammerstone

Relationship Condition

Refine is a paid package. To purchase, head to hammerstone.dev.

The Relationship Condition is an extension of the Numeric Condition and is for querying against the count of a related model.

RelationshipCondition::make('comment_count', 'Number of Comments')
->relationship('comments');

This condition has an id of comment_count, a display of Number of Comments and operates against the comments relationship of the model your initial query is based on.

With this condition in place, the user will now be able to select e.g. [Number of Comments] [is greater than] [5].

Adding Query Restrictions

In the scenario where you want to scope your relationship down, you can pass a closure to the restrict method.

RelationshipCondition::make('approved_comments', 'Number of Approved Comments')
->relationship('comments')
->restrict(function($query) {
$query->where('approved', 1);
});
Code highlighting powered by torchlight.dev, a Hammerstone product.

Now instead of counting every related comment, it will only count comments where approved = 1.

You can use this to create multiple instances of the same relationship with slight variations:

// Approved
RelationshipCondition::make('approved_comments', 'Number of Approved Comments')
->relationship('comments')
->restrict(function($query) {
$query->where('approved', 1);
});
 
// Pending
RelationshipCondition::make('pending_comments', 'Number of Pending Comments')
->relationship('comments')
->restrict(function($query) {
$query->whereNull('approved');
});
 
// Denied
RelationshipCondition::make('denied_comments', 'Number of Denied Comments')
->relationship('comments')
->restrict(function($query) {
$query->where('approved', 0);
});

Using the Database Builder

The most common scenario for most filters is to return an instance of Eloquent\Builder from your initialQuery method. This is the class you get when you call e.g. Post::query().

If you are using the underlying Database\Builder class as your initial query you'll also need to set the model where the relationship can be found.

Let's take a look:

class PostsFilter extends Filter
{
public function initialQuery()
{
// If you're returning an instance of Database\Builder...
return DB::table('posts');
}
 
public function conditions()
{
return [
RelationshipCondition::make('comment_count', 'Number of Comments')
->relationship('comments')
// Then you need to tell Refine that the `comments`
// relationship you're referencing can be found
// on the `Post` Eloquent model.
->on(Post::class)
];
}
}

By calling the on method of the Relationship Condition, you're informing Refine that the comments relationship lives on the Post model. Refine will then be able to use that information to derive the correct query and apply it to your base query.