Conditions Overview
Refine is a paid package. To purchase, head to hammerstone.dev.
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:
class EmployeeFilter extends Filter{ public function initialQuery() { return Employee::query(); } public function conditions() { return [ TextCondition::make('name'), NumericCondition::make('start_year'), DateCondition::make('birthday'), ]; }}
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:
class EmployeeFilter extends Filter{ public function conditions() { return [ // Instantiated Class TextCondition::make('name'), // Fully Qualifed Class Name NameCondition::class, ]; }}
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
.
TextCondition::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:
new 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:
TextCondition::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:
TextCondition::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:
public function conditions(){ return [ TextCondition::make('name')->display('Employee Name') ];}
you can create a dedicated class:
class EmployeeNameCondition extends TextCondition{ public $id = 'name'; public $attribute = 'name'; public $display = 'Employee Name';}
and then add it via it's class name or as an instantiated object
public function conditions(){ return [ // Either EmployeeNameCondition::class, // Or new EmployeeNameCondition, ];}
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.