Installation
composer require act-training/query-builder
Publish the config file (if available) with:
php artisan vendor:publish --provider="ActTraining\QueryBuilder\QueryBuilderServiceProvider"
Basic Usage Import the package in your controller/service:
use ActTraining\QueryBuilder\QueryBuilder;
use App\Models\User;
use ActTraining\QueryBuilder\ReportBuilder; // New for reporting features
First Query
$users = QueryBuilder::for(User::class)
->where('active', true)
->orderBy('name')
->get();
ReportBuilder Usage (New)
$report = new ReportBuilder(User::class);
$report->columns(['id', 'name', 'email']); // Now with searchable column labels
return view('reports.users', compact('report'));
Key Files to Review
config/query-builder.php (if published)src/QueryBuilder.php (core class)src/Traits/ (extension traits)resources/js/column-search.js (new Alpine.js component)src/ReportBuilder.php (new reporting class)$query = QueryBuilder::for(User::class)
->whereLike('name', request('search'))
->whereIn('role_id', request('roles', []))
->orderBy(request('sort', 'name'))
->paginate(request('per_page', 15));
// In your controller
$report = new ReportBuilder(User::class);
$report->columns([
'id' => 'ID',
'name' => 'Full Name',
'email' => 'Email Address',
'created_at' => 'Registration Date'
]);
// Column labels are now searchable via Alpine.js
return view('reports.users', compact('report'));
// Disable column search (default is enabled)
$report = new ReportBuilder(User::class);
$report->enableColumnSearch = false; // New property
// app/Models/User.php
public function scopeActive($query)
{
return $query->where('active', true);
}
// Usage
$query = QueryBuilder::for(User::class)->active()->get();
$filters = request()->input('filters', []);
$query = QueryBuilder::for(User::class);
foreach ($filters as $field => $value) {
if (str_ends_with($field, '_like')) {
$query->whereLike(str_replace('_like', '', $field), $value);
}
}
public function boot()
{
QueryBuilder::extend(function ($builder) {
$builder->macro('customScope', function ($builder) {
return $builder->where('custom_field', 'value');
});
});
}
<x-query-builder::report-builder :report="$report" />
<!-- New component with built-in column search -->
// resources/js/column-search.js
document.addEventListener('alpine:init', () => {
Alpine.data('columnSearch', () => ({
init() {
this.$watch('query', debounce(() => {
// Custom search logic if needed
}, 300));
}
}));
});
public function test_report_builder_column_search()
{
$report = new ReportBuilder(User::class);
$report->columns(['name' => 'Full Name']);
$view = blade()->render("reports.users", ['report' => $report]);
$this->assertStringContainsString('x-data="columnSearch()"', $view);
}
$report->columns([
'id' => 'User ID', // Searchable label
'name' => 'Full Name'
]);
<x-query-builder::report-builder :report="$report" id="user-report-search" />
$report->enableColumnSearch = false;
Alpine.store() for shared state.$report = new ReportBuilder(User::class);
$report->columns(['name' => 'Full Name']);
dump($report->getSearchableColumns()); // Check labels
| Issue | Cause | Solution |
|---|---|---|
| Columns not searchable | Missing labels | Set explicit labels in columns() |
| Search input not appearing | Alpine.js not loaded | Check resources/js/column-search.js |
| Case sensitivity problems | Default search is case-insensitive | Customize search logic in JS |
Override the default search behavior:
// resources/js/column-search.js
Alpine.data('columnSearch', () => ({
searchColumns(columns, query) {
// Custom search implementation
return columns.filter(col =>
col.label.toLowerCase().includes(query.toLowerCase()) ||
col.key.toLowerCase().includes(query.toLowerCase())
);
}
}));
Listen for column search events (if supported):
// config/query-builder.php
'report_builder' => [
'events' => [
'search' => \App\Listeners\LogColumnSearch::class,
],
],
ReportBuilder::driver('custom', function () {
return new CustomReportBuilder();
});
Extend the default ReportBuilder component:
<x-query-builder::report-builder :report="$report">
@slot('extra')
<button wire:click="refresh">Refresh</button>
@endslot
</x-query-builder::report-builder>
For large datasets, combine client-side search with server-side filtering:
$report = new ReportBuilder(User::class);
$report->columns(['name' => 'Full Name']);
$query = $report->query()
->where('name', 'like', '%'.request('search').'%');
// Sync server-side search with client-side
document.getElementById('column-search').addEventListener('input', (e) => {
window.location.search = `?search=${e.target.value}`;
});
How can I help you explore Laravel packages today?