mozex/laravel-searchable
Add a Searchable trait to any Eloquent model to search multiple columns and related data (relations, morphs, even cross-database) via a single ->search() call. Works with Laravel Scout and includes optional Filament table/global search integration.
Installation:
composer require mozex/laravel-searchable
No additional configuration or migrations required.
Basic Model Integration:
Add the Searchable trait to your Eloquent model and define searchableColumns():
use Mozex\Searchable\Searchable;
class Comment extends Model
{
use Searchable;
public function searchableColumns(): array
{
return ['body', 'author.name']; // Direct column + relation
}
public function author()
{
return $this->belongsTo(User::class);
}
}
First Search Query:
$results = Comment::search('laravel')->get();
// Or with query constraints:
$results = Comment::where('published', true)
->search($request->input('q'))
->paginate();
Searchable trait and searchableColumns() methodadvancedSearchable() macro if using FilamentDefine Searchable Columns:
public function searchableColumns(): array
{
return [
'title', // Direct column
'author.name', // BelongsTo relation
'tags.name', // HasMany relation
'commentable:post.title', // Morph relation
];
}
Search Execution:
// Basic search
Model::search('query')->get();
// With query builder
Model::query()
->where('status', 'active')
->search($request->q)
->get();
Column Filtering:
// Search specific columns
Model::search('query', in: ['title', 'body'])->get();
// Add/remove columns dynamically
Model::search('query', include: ['slug'], except: ['author.name'])->get();
Morph Relations:
// Requires morph map setup
Relation::morphMap(['post' => Post::class, 'video' => Video::class]);
public function searchableColumns(): array
{
return ['commentable:post.title', 'commentable:video.name'];
}
Cross-Database Relations:
// Automatically handles external connections
Model::search('query', externalLimit: 200)->get();
Filament Integration:
// Table column search
TextColumn::make('title')->advancedSearchable();
// Global search provider
$panel->globalSearch(SearchableGlobalSearchProvider::class);
Query Builder Integration:
// When $query->search() conflicts
$model->applySearch($query, 'term', in: ['title']);
use Mozex\Searchable\Searchable as DatabaseSearchable;
class Model
{
use DatabaseSearchable { scopeSearch as scopeDatabaseSearch; }
use \Laravel\Scout\Searchable;
}
pg_trgm indexes on PostgreSQL for LIKE performanceMethod Conflict Resolution:
search() method - use applySearch() insteadCase Sensitivity:
Cross-Database Limits:
externalLimit parameter if neededPerformance Caveats:
%term%) prevent index usageQuery Inspection:
$query = Model::query()->search('term')->toSql();
dd($query); // View generated SQL
Column Validation:
Filament Issues:
getGloballySearchableAttributes() is defined for each resourcesearchableColumns()Custom Search Logic:
// Override search behavior
public function scopeCustomSearch($query, $term)
{
return $this->applySearch($query, $term, in: ['custom_column']);
}
Dynamic Column Configuration:
// Conditional search columns
public function searchableColumns()
{
return $this->isAdmin()
? ['title', 'body', 'author.name']
: ['title', 'body'];
}
Advanced Filament Customization:
// Custom global search provider
class CustomSearchProvider extends SearchableGlobalSearchProvider
{
protected function getSearchableModels(): array
{
return [Post::class, Page::class];
}
}
Morph Relation Requirements:
Relation Path Validation:
author.company.name requires author → company → name chainDatabase-Specific Behavior:
Query Structure:
WHERE (col1 LIKE '%term%' OR col2 LIKE '%term%')Relation Handling:
Memory Considerations:
externalLimit based on your data volume
How can I help you explore Laravel packages today?