SearchBuilder Extension
Let users compose grouped search conditions
When To Use
Use SearchBuilder when users need to combine several conditions, such as “age over 50 and city is Paris, or name starts with Al”, without a dedicated filter form.
Minimal Example
namespace App\DataTable;
use App\Entity\Employee;
use Pentiminax\UX\DataTables\Attribute\AsDataTable;
use Pentiminax\UX\DataTables\Model\AbstractDataTable;
use Pentiminax\UX\DataTables\Model\DataTable;
#[AsDataTable(Employee::class)]
final class EmployeeDataTable extends AbstractDataTable
{
public function configureDataTable(DataTable $table): DataTable
{
return $table->searchBuilder();
}
}
searchBuilder() registers the extension and adds the searchBuilder feature to the top1 layout
row. Pass position: 'topStart' to place it elsewhere, or declare Feature::SEARCH_BUILDER in
layout() yourself and register the extension with
addExtension(new SearchBuilderExtension()). A layout that places the feature without the
extension is deprecated since 1.3 and throws in 2.0.
Advanced Example
use Pentiminax\UX\DataTables\Enum\SearchBuilderLogic;
$dataTable->searchBuilder(
columns: [1, 2, 3],
depthLimit: 2,
logic: SearchBuilderLogic::Or,
preDefined: [
'criteria' => [['data' => 'Age', 'condition' => '>', 'value' => [50]]],
'logic' => 'AND',
],
);
Only options that differ from the DataTables defaults reach the browser (an empty payload for
searchBuilder() without arguments). filterChanged is a
JavaScript callback and cannot be configured from PHP.
Date Columns
SearchBuilder needs the DataTables DateTime extension as soon as the table has a date column. The
bundle loads datatables.net-datetime with SearchBuilder, but not its stylesheet, so import it once
to style the date picker:
// assets/app.js
import 'datatables.net-datetime/dist/dataTables.dateTime.min.css'
With AssetMapper, run
php bin/console importmap:require datatables.net-datetime datatables.net-datetime/dist/dataTables.dateTime.min.css
first. With Webpack Encore, import datatables.net-datetime/css instead.
Server-Side Processing
On server-side tables the bundle reads the searchBuilder request parameter and ANDs the result
with the other filters. Conditions supported: =, !=, <, <=, >=, >, between,
!between, null, !null, starts, !starts, contains, !contains, ends and !ends.
The parameter is validated strictly. An unknown logic or condition, a malformed node, more than 5 nesting levels or 50 nodes, or more than 2 values per criterion answers HTTP 400 rather than an unfiltered table. Incomplete criteria (a blank field or value) are skipped, as in the browser.
columnsonly limits what the browser offers. The server accepts any searchable column, so callsetSearchable(false)on a column to block it: the builder leaves it out, and a request naming it or an unknown column answers HTTP 400.- The
withoutcondition is hidden, because the server cannot apply it. - A criterion whose value cannot be bound to the field type (for example text for an integer
column, or
2.5for an integer) matches nothing instead of raising a database error. - Dates compare by whole day, and negated conditions keep rows where the field is
NULL. - API Platform tables cannot apply SearchBuilder criteria: rendering throws a
LogicException.ArrayDataProviderrejects them with HTTP 400. LIKEconditions are case-insensitive and escape%and_.- Select-based conditions fall back to text inputs, and custom conditions are not supported.
Frequent Pitfalls
- Expecting
arrayconditions (without) to work server-side: the builder hides them. - Hiding a column from the table but leaving it searchable: it still appears in the builder
unless you restrict
columnsor callsetSearchable(false).