ocherenkov / laravel-searchable-trait
A reusable Eloquent trait for case-insensitive searches across columns, concatenated fields, and relationships.
Package info
github.com/ocherenkov/laravel-searchable-trait
pkg:composer/ocherenkov/laravel-searchable-trait
Requires
- php: ^8.2
- illuminate/cache: ^12.0 || ^13.0
- illuminate/database: ^12.0 || ^13.0
Requires (Dev)
- laravel/pint: ~1.30.0
- orchestra/testbench: ^10.0 || ^11.0
- phpunit/phpunit: ^11.5 || ^12.5 || ^13.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
A small Laravel package that adds a reusable search() scope to Eloquent models. It supports case-insensitive searches across model columns, concatenated fields, and relationships.
Requirements
- PHP 8.2 or newer
- Laravel 12 or 13
Installation
Install the package through Composer:
composer require ocherenkov/laravel-searchable-trait
No service provider or configuration file is required.
Usage
Import and use the trait in any Eloquent model:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Ocherenkov\LaravelSearchableTrait\SearchTrait; class Widget extends Model { use SearchTrait; protected array $searchable = ['location', 'content']; protected array $searchableConcat = [ ['first_name', 'last_name'], ]; protected array $searchableRelations = [ 'tags' => ['name'], 'category' => ['title'], ]; }
Then call the search() local scope:
$widgets = Widget::search('office')->get(); $activeWidgets = Widget::search('office') ->where('status', 'active') ->get();
By default, a record may match any configured column. Pass true as the second argument to require every configured local column to match:
$widgets = Widget::search('office', true)->get();
Passing null, an empty string, or whitespace leaves the query unchanged.
Automatic column detection
If $searchable is not defined, the package reads the model's table schema and searches all columns except:
- the model's primary key;
- the created and updated timestamp columns;
- attributes listed in the model's
$hiddenproperty.
The detected list is cached per model, connection, and table. Clear it after a runtime schema change with:
(new Widget())->forgetSearchableColumnsCache();
For predictable queries and better performance, explicitly defining $searchable is recommended in production applications.
Database support
Regular column and relationship searches use Laravel's query grammar. Concatenated searches use CONCAT_WS on MySQL, MariaDB, PostgreSQL, and SQL Server, with a compatible expression for SQLite.
The search is implemented with UPPER(column) LIKE ?. On large datasets, consider database-specific functional indexes or a dedicated full-text search solution.
Testing
composer install
composer test
The GitHub Actions matrix tests the package against Laravel 12 and 13.
License
The MIT License. See LICENSE.