Skip to content

Commit 85599c1

Browse files
Improve README with comprehensive usage examples
Add documentation for all three builder types (QueryBuilder, TableBuilder, ReportBuilder), the new GroupBy feature, column types, conditions, filters, and relationship support. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 8f76b2b commit 85599c1

1 file changed

Lines changed: 238 additions & 17 deletions

File tree

README.md

Lines changed: 238 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,62 @@
1-
# A drop in query builder for Laravel models.
1+
# Query Builder for Laravel
22

3-
Add a query builder and report table for youir models.
3+
Drop-in Livewire components for building query builders, tables, and reports on Eloquent models.
44

55
## Installation
66

7-
You can install the package via composer:
8-
97
```bash
108
composer require act-training/query-builder
119
```
1210

13-
Optionally, you can publish the views using
11+
Optionally, publish the views:
1412

1513
```bash
1614
php artisan vendor:publish --tag="query-builder-views"
1715
```
1816

19-
## Usage
20-
Models should use the AppliesCriteria trait.
17+
## Model Setup
18+
19+
Models should use the `AppliesCriteria` trait:
2120

2221
```php
23-
class User extends Authenticatable
22+
use ACTTraining\QueryBuilder\Support\Criteria\AppliesCriteria;
23+
24+
class Employee extends Model
2425
{
2526
use AppliesCriteria;
26-
27-
...
28-
2927
}
3028
```
3129

32-
Create a Livewire component and make sure it extends QueryBuilder.
30+
## Components
31+
32+
The package provides three main abstract Livewire components to extend:
33+
34+
| Component | Purpose |
35+
|---|---|
36+
| `QueryBuilder` | Full query builder with criteria-based AND/OR filtering |
37+
| `TableBuilder` | Simpler table with URL-persisted filters and search |
38+
| `ReportBuilder` | Dynamic column selection, save/load/export, optional groupBy |
39+
40+
### QueryBuilder
41+
42+
Create a Livewire component that extends `QueryBuilder`. Define `query()`, `columns()`, and `conditions()`:
3343

3444
```php
3545
<?php
3646

37-
namespace App\Http\Livewire;
47+
namespace App\Livewire;
3848

39-
use ACTTraining\QueryBuilder\QueryBuilder;use ACTTraining\QueryBuilder\Support\Columns\BooleanColumn;use ACTTraining\QueryBuilder\Support\Columns\Column;use ACTTraining\QueryBuilder\Support\Columns\DateColumn;use ACTTraining\QueryBuilder\Support\Conditions\BooleanCondition;use ACTTraining\QueryBuilder\Support\Conditions\DateCondition;use ACTTraining\QueryBuilder\Support\Conditions\TextCondition;use App\Models\Employee;use Illuminate\Database\Eloquent\Builder;
49+
use ACTTraining\QueryBuilder\QueryBuilder;
50+
use ACTTraining\QueryBuilder\Support\Columns\BooleanColumn;
51+
use ACTTraining\QueryBuilder\Support\Columns\Column;
52+
use ACTTraining\QueryBuilder\Support\Columns\DateColumn;
53+
use ACTTraining\QueryBuilder\Support\Conditions\BooleanCondition;
54+
use ACTTraining\QueryBuilder\Support\Conditions\DateCondition;
55+
use ACTTraining\QueryBuilder\Support\Conditions\TextCondition;
56+
use App\Models\Employee;
57+
use Illuminate\Database\Eloquent\Builder;
4058

41-
class EmployeesReport extends QueryBuilder
59+
class EmployeesTable extends QueryBuilder
4260
{
4361
public function config(): void
4462
{
@@ -47,6 +65,11 @@ class EmployeesReport extends QueryBuilder
4765
->rowClickable(false);
4866
}
4967

68+
public function query(): Builder
69+
{
70+
return Employee::query()->with(['contract', 'contract.job', 'contract.location']);
71+
}
72+
5073
public function columns(): array
5174
{
5275
return [
@@ -74,20 +97,218 @@ class EmployeesReport extends QueryBuilder
7497
DateCondition::make('Start Date', 'contract.start_date'),
7598
];
7699
}
100+
}
101+
```
102+
103+
### TableBuilder
104+
105+
A simpler alternative using filters instead of criteria. Define `query()`, `columns()`, and `filters()`:
106+
107+
```php
108+
<?php
109+
110+
namespace App\Livewire;
111+
112+
use ACTTraining\QueryBuilder\TableBuilder;
113+
use ACTTraining\QueryBuilder\Support\Columns\Column;
114+
use ACTTraining\QueryBuilder\Support\Filters\TextFilter;
115+
use ACTTraining\QueryBuilder\Support\Filters\SelectFilter;
116+
use App\Models\Employee;
117+
use Illuminate\Database\Eloquent\Builder;
118+
119+
class EmployeesList extends TableBuilder
120+
{
121+
public function query(): Builder
122+
{
123+
return Employee::query();
124+
}
125+
126+
public function columns(): array
127+
{
128+
return [
129+
Column::make('Name', 'full_name')->sortable()->searchable(),
130+
Column::make('Department', 'department')->sortable(),
131+
];
132+
}
133+
134+
public function filters(): array
135+
{
136+
return [
137+
TextFilter::make('Name', 'full_name'),
138+
SelectFilter::make('Department', 'department')
139+
->options(['HR' => 'HR', 'IT' => 'IT', 'Finance' => 'Finance']),
140+
];
141+
}
142+
}
143+
```
144+
145+
### ReportBuilder
146+
147+
Extends `QueryBuilder` with dynamic column selection. Users pick columns at runtime from `availableColumns()`, and the component builds columns and conditions automatically:
148+
149+
```php
150+
<?php
77151

152+
namespace App\Livewire;
153+
154+
use ACTTraining\QueryBuilder\ReportBuilder;
155+
use App\Models\Employee;
156+
use Illuminate\Database\Eloquent\Builder;
157+
158+
class EmployeesReport extends ReportBuilder
159+
{
78160
public function query(): Builder
79161
{
80162
return Employee::query()->with(['contract', 'contract.job', 'contract.location']);
81163
}
82164

83-
public function rowClick($row): void
165+
public function availableColumns(): array
84166
{
85-
$this->dispatchBrowserEvent('notify', ['content' => 'The row was clicked', 'type' => 'success']);
167+
return [
168+
'Employee' => [
169+
['label' => 'Name', 'key' => 'full_name'],
170+
['label' => 'Email', 'key' => 'email'],
171+
],
172+
'Contract' => [
173+
['label' => 'Job Title', 'key' => 'contract.job.name'],
174+
['label' => 'Location', 'key' => 'contract.location.name'],
175+
['label' => 'Start Date', 'key' => 'contract.start_date', 'type' => 'date'],
176+
['label' => 'Salary', 'key' => 'contract.salary', 'type' => 'number'],
177+
['label' => 'Line Manager', 'key' => 'contract.line_manager', 'type' => 'boolean'],
178+
],
179+
];
180+
}
181+
}
182+
```
183+
184+
Column definitions in `availableColumns()` support these keys:
185+
186+
| Key | Description |
187+
|---|---|
188+
| `label` | Display label (required) |
189+
| `key` | Column key, supports dot-notation for relationships (required) |
190+
| `type` | Column type: `text` (default), `number`, `float`, `boolean`, `date`, `enum`, `null`, `view` |
191+
| `sortable` | Enable sorting on this column |
192+
| `justify` | Alignment: `left`, `center`, `right` |
193+
| `view` | Custom Blade component for rendering |
194+
| `options` | Options array for `enum` type |
195+
| `skipCondition` | Exclude from query builder conditions |
196+
197+
### ReportBuilder with GroupBy
198+
199+
Enable groupBy to allow users to group results by a column with aggregate functions (COUNT, SUM, AVG, MIN, MAX). Set `$enableGroupBy = true`:
200+
201+
```php
202+
<?php
203+
204+
namespace App\Livewire;
205+
206+
use ACTTraining\QueryBuilder\ReportBuilder;
207+
use App\Models\Employee;
208+
use Illuminate\Database\Eloquent\Builder;
209+
210+
class EmployeesGroupReport extends ReportBuilder
211+
{
212+
public bool $enableGroupBy = true;
213+
214+
public function query(): Builder
215+
{
216+
return Employee::query()->with(['contract', 'contract.job', 'contract.location']);
86217
}
87218

219+
public function availableColumns(): array
220+
{
221+
return [
222+
'Employee' => [
223+
['label' => 'Name', 'key' => 'full_name'],
224+
['label' => 'Department', 'key' => 'department'],
225+
],
226+
'Contract' => [
227+
['label' => 'Job Title', 'key' => 'contract.job.name'],
228+
['label' => 'Location', 'key' => 'contract.location.name'],
229+
['label' => 'Salary', 'key' => 'contract.salary', 'type' => 'number'],
230+
],
231+
];
232+
}
88233
}
89234
```
90235

236+
When `enableGroupBy` is true, the report editor UI shows additional controls:
237+
238+
- **Group By Column** - select which column to group by
239+
- **Function** - aggregate function (COUNT, SUM, AVG, MIN, MAX)
240+
- **Aggregate Column** - which column to aggregate (defaults to `id`, numeric columns from `availableColumns()` are included automatically)
241+
242+
An "Aggregate" column is automatically appended to the table when grouping is active.
243+
244+
You can customise the available aggregate functions and groupable/aggregatable columns by overriding:
245+
246+
```php
247+
public function aggregateFunctions(): array
248+
{
249+
return ['COUNT', 'SUM', 'AVG'];
250+
}
251+
252+
public function groupableColumns(): array
253+
{
254+
// Return a flat array of ['label' => ..., 'key' => ...] items
255+
return [
256+
['label' => 'Department', 'key' => 'department'],
257+
['label' => 'Location', 'key' => 'contract.location.name'],
258+
];
259+
}
260+
261+
public function aggregatableColumns(): array
262+
{
263+
return [
264+
['label' => 'ID', 'key' => 'id'],
265+
['label' => 'Salary', 'key' => 'contract.salary'],
266+
];
267+
}
268+
```
269+
270+
## Columns
271+
272+
All column types use a fluent `make($label, $key)` constructor. If `$key` is omitted, it defaults to `Str::snake($label)`.
273+
274+
| Column Type | Description |
275+
|---|---|
276+
| `Column` | General text column |
277+
| `BooleanColumn` | Boolean/checkbox display |
278+
| `DateColumn` | Date formatting with `->format()` and `->humanDiff()` |
279+
| `ViewColumn` | Custom Blade view rendering |
280+
281+
Columns support: `->sortable()`, `->searchable()`, `->justify('right')`, `->component('view.name')`, `->reformatUsing(callable)`, `->withSubTitle(callable)`, `->hideIf(condition)`, `->hideHeader()`.
282+
283+
## Conditions (QueryBuilder)
284+
285+
Used with `QueryBuilder` and `ReportBuilder` for criteria-based filtering:
286+
287+
| Condition Type | Operations |
288+
|---|---|
289+
| `TextCondition` | equals, not_equals, contains, starts_with, ends_with |
290+
| `NumberCondition` | equals, not_equals, greater_than, less_than, is_between |
291+
| `FloatCondition` | equals, not_equals, greater_than, less_than, is_between |
292+
| `BooleanCondition` | is_true, is_false |
293+
| `DateCondition` | equals, before, after, is_between |
294+
| `EnumCondition` | equals, not_equals (with defined options) |
295+
| `NullCondition` | is_set, is_not_set |
296+
297+
## Filters (TableBuilder)
298+
299+
Used with `TableBuilder` for simpler key/operator/value filtering:
300+
301+
`TextFilter`, `NumberFilter`, `DateFilter`, `BooleanFilter`, `SelectFilter`, `NullFilter`
302+
303+
## Relationship Support
304+
305+
Dot-notation keys work throughout columns, conditions, and filters to traverse Eloquent relationships:
306+
307+
```php
308+
Column::make('Job Title', 'contract.job.name')
309+
TextCondition::make('Location', 'contract.location.name')
310+
```
311+
91312
## Testing
92313

93314
```bash

0 commit comments

Comments
 (0)