Refine will be launching soon 🎉 Sign up for the early access list to stay up to date.
Refine for Laravel
A package by Hammerstone

Conditions Overview

Hammerstone Refine has not launched yet. Sign up for the early access list to stay up to date!

Conditions are the fundamental building block of filters. Every filter defines a set of conditions that your users can use to build up their perfect criteria.

Every condition is entirely encapsulated, supplies its own configuration options, its own validation logic, and its own method to apply the user's data to the query.

Imagine you wanted build a filter for Employee records that let your users filter on the employee's name, birthday, and start year. In that case, you would make an Employee filter, with conditions for name, birthday and start year.

We can build this hypothetical filter pretty easily:

1class EmployeeFilter extends Filter
2{
3 public function initialQuery()
4 {
5 return Employee::query();
6 }
7 
8 public function conditions()
9 {
10 return [
11 TextCondition::make('name'),
12 NumericCondition::make('start_year'),
13 DateCondition::make('birthday'),
14 ];
15 }
16}

With just a few lines of code in this tiny class, you've given your users the power to build totally custom queries that perfectly suite their needs. If HR needed a report of "Employees that started this year and have a birthday in the next 30 days", they could build it themselves without ever reaching out to a developer!

For your convenience, we provide a number of common conditions out of the box:

  • Boolean - filter on boolean attributes.
  • Date - filter on date attributes.
  • Date with Time - filter on attributes that have a date and time.
  • UNIX Timestamp - filter on UNIX timestamp attributes.
  • Numeric - filter on a numeric attribute.
  • Option - filter on an attribute given from a defined set of options.
  • Deferred Option - filter on an attribute given from a defined set of options retrieved via AJAX.
  • Relationship - filter on the presence or absence of a relationship.
  • Text - filter on a text attribute.
  • Presence - filter on the presence or absence of an attribute.

This should cover the vast majority of needs in most applications. Of course if you need to build out a custom condition with special logic, you're able to do that as well.

Defining a Filter's Conditions

Every Filter class must implement a conditions method which returns the array of available conditions. You are welcome to build that array in any way you want, but usually it makes sense to just return an array, as in our example above.

Each condition in the array must extend the abstract Hammerstone\Refine\Conditions\Condition class and can either be an instantiated class or a fully qualified class name.

I.e. both of the following would work:

1class EmployeeFilter extends Filter
2{
3 public function conditions()
4 {
5 return [
6 // Instantiated Class
7 TextCondition::make('name'),
8 
9 // Fully Qualifed Class Name
10 NameCondition::class,
11 ];
12 }
13}
Code highlighting powered by torchlight.dev, a Hammerstone product.

By far the easiest way to start is by calling the static make method on one of the out-of-the-box conditions provided by the package. This will instantiate the condition and give you a whole host of fluent methods with which you can work.

IDs

The first argument passed to the static make call is always the ID of the condition. The ID is the unique identifier of an individual condition; it should never change. The ID is how the frontend and backend and know that they're talking about the same thing. Each ID needs to be unique per filter.

In the following bit of code, we're making a TextCondition that has an ID of name.

1TextCondition::make('name');

In this example the backend is telling the frontend: "hey, there is a text condition called 'name' that you can use." The frontend then says: "ok, for that condition called 'name'... here is the data the user entered." Everything is linked together via ID.

The ID of the condition does not have to match your database column name, but often times it does. The ID of the condition is totally up to you and is not linked to the rest of your application in any way at all.

PS: The static make method is just a developer convenience for a constructor, so it is no different from:

1new TextCondition('name');

Pretty Display / Label

In addition to an ID, every condition has a "Label" (or "Display") that's a prettier, human-readable label to be used on the frontend.

By default, we'll take the id that you pass in and try to "prettify" it for the end user. We'll replace underscores with spaces, and call Str::title on the result. If you don't like this default, you're welcome to pass in a second parameter:

1TextCondition::make('name', 'Employee Name');

In this example, had we not passed in a second parameter the user would be presented with a condition of "Name". This is probably fine, but in our example we've decided that "Employee Name" is more clear, so we override the default.

The fluent display method is available to you as well:

1TextCondition::make('name')->display('Employee Name');

Custom Classes

All of the conditions we provide out of the box include fluent methods to help you build up your conditions without having to create multiple custom classes. This is usually perfect for about 95% of the cases.

If you encounter a situation where the fluent methods are more confusing or aren't powerful enough, you're free to create dedicated classes.

For example, instead of adding a condition like this:

1public function conditions()
2{
3 return [
4 TextCondition::make('name')->display('Employee Name')
5 ];
6}

you can create a dedicated class:

1class EmployeeNameCondition extends TextCondition
2{
3 public $id = 'name';
4 public $attribute = 'name';
5 public $display = 'Employee Name';
6}
Code highlighting powered by torchlight.dev, a Hammerstone product.

and then add it via it's class name or as an instantiated object

1public function conditions()
2{
3 return [
4 // Either
5 EmployeeNameCondition::class,
6 
7 // Or
8 new EmployeeNameCondition,
9 ];
10}

This is a very simplistic example, but keep this in mind if you find yourself struggling to get your conditions configured just right. To read more about creating a custom condition, visit the "creating custom conditions" page.

Extending Standard Conditions

Most of the time it's easiest to extend a standard condition instead of creating a new one from scratch. We have a whole section on extending standard conditions that covers that in more detail.