Download the PHP package fab2s/searchable without Composer
On this page you can find all versions of the php package fab2s/searchable. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download fab2s/searchable
More information about fab2s/searchable
Files in fab2s/searchable
Package searchable
Short Description Laravel searchable models based on FullText indexes with phonetic matching
License MIT
Informations about the package searchable
Searchable
Add fulltext search to your Eloquent models in minutes — no external services, no Scout driver, just your existing database.
This package keeps things simple: it concatenates model fields into a single indexed column and uses native fulltext capabilities (MATCH...AGAINST on MySQL, tsvector/tsquery on PostgreSQL) for fast prefix-based search, ideal for autocomplete.
Why Searchable?
If you need fast autocomplete or simple search and already run MySQL/MariaDB or PostgreSQL, you don't need a separate search engine.
| Searchable | Laravel Scout + Driver | |
|---|---|---|
| Infrastructure | Your existing database | External service (Algolia, Meilisearch, Typesense, ...) |
| Setup | Add a trait, run one command | Install driver, configure credentials, manage process/service |
| Sync | Automatic on Eloquent save |
Queue workers, manual imports |
| Query integration | Standard Eloquent scopes & builder — composes with where, join, orderBy, etc. |
Separate ::search() API with limited query builder support |
| Phonetic matching | Built-in, pluggable algorithms (also provides typo tolerance) | Depends on the external service |
| Scalability | Performs well even with millions of rows thanks to single-column native fulltext indexes | Designed for very large-scale, multi-field search |
| Best for | Autocomplete, name/title/email search, up to millions of rows | Multi-field search, weighted ranking, facets, advanced typo tolerance |
Searchable is not a replacement for a dedicated search engine — it's a lightweight alternative for the many cases where one isn't needed. The single-column approach is what makes it fast: native fulltext indexes on one column scale well, whereas indexing many columns separately (especially on MySQL) is where dedicated engines pull ahead.
Requirements
- PHP 8.1+
- Laravel 10.x / 11.x / 12.x
- MySQL / MariaDB or PostgreSQL
ext-intlPHP extension
Installation
The service provider is auto-discovered.
Quick start
Implement SearchableInterface on your model, use the Searchable trait, and list the fields to index:
Then run the artisan command to add the column and fulltext index:
That's it. The searchable column is automatically populated on every save.
Choosing fields wisely: The quality of matching depends directly on which fields you index. This package is designed for fast, simple autocomplete — not complex full-text search. Keep
$searchablesfocused on the few fields users actually type into a search box (names, titles, emails). Adding large or numerous fields dilutes relevance and increases storage. If you need weighted fields, facets, or advanced ranking, consider a dedicated search engine instead.
Searching
The trait provides a search scope that handles everything automatically:
It composes with other query builder methods:
Results are ordered by relevance (DESC) by default. Pass null to disable:
The driver is detected automatically from the query's connection. The scope picks up the model's tsConfig and phonetic settings.
For IDE autocompletion, add a
@methodannotation to your model:
Empty search terms
When the search input is empty or contains only operators/whitespace, the search scope is a no-op — no WHERE or ORDER BY clause is added. This means you can safely pass user input without checking for empty strings:
Advanced usage with SearchQuery
For more control (table aliases in joins, custom field name), use SearchQuery directly:
This is particularly useful when searching across joined tables. The third argument to addMatch is a table alias that prefixes the searchable column, preventing ambiguity:
Configuration
Every option can be set by declaring a property on your model. The trait picks them up automatically and falls back to sensible defaults when omitted:
| Property | Type | Default | Description |
|---|---|---|---|
$searchableField |
string |
'searchable' |
Column name for the searchable content |
$searchableFieldDbType |
string |
'string' |
Migration column type (string, text) |
$searchableFieldDbSize |
int |
500 |
Column size (applies to string type) |
$searchables |
array<string> |
[] |
Model fields to index |
$searchableTsConfig |
string |
'english' |
PostgreSQL text search configuration |
$searchablePhonetic |
bool |
false |
Enable phonetic matching |
$searchablePhoneticAlgorithm |
class-string<PhoneticInterface> |
— (metaphone) | Custom phonetic encoder class |
Each property has a corresponding getter method (getSearchableField(), getSearchableFieldDbType(), etc.) defined in SearchableInterface. You can override those methods instead if you need computed values.
Custom content
Override getSearchableContent() to control what gets indexed. The $additional parameter lets you inject extra data (decrypted fields, computed values, etc.):
PostgreSQL text search configuration
By default, PostgreSQL uses the english text search configuration. Set $searchableTsConfig to change it:
The search scope picks this up automatically. When using SearchQuery directly, pass the same value:
Phonetic matching
Enable phonetic matching to find results despite spelling variations (eg. "jon" matches "john", "smyth" matches "smith"). This uses PHP's metaphone() to append phonetic codes to the same searchable field — no extra column or extension needed.
That's all — both storage and the search scope handle it automatically. Stored content becomes john smith jn sm0, and a search for jon produces the term jn which matches.
When using SearchQuery directly, pass the phonetic flag:
Custom phonetic algorithm
The default metaphone() works well for English. For other languages, set $searchablePhoneticAlgorithm to any class implementing PhoneticInterface:
Then reference it on your model:
The trait resolves the class to a closure internally — no method override needed.
When using SearchQuery directly, pass the encoder as a closure:
Built-in French encoders
Two French phonetic algorithms are included, optimized PHP ports from Talisman (MIT):
| Class | Algorithm | Description |
|---|---|---|
Phonetic |
Phonetic Français | Comprehensive French phonetic algorithm by Edouard Berge. Handles ligatures, silent letters, nasal vowels, and many French-specific spelling rules. |
Soundex2 |
Soundex2 | French adaptation of Soundex. Simpler and faster than Phonetic, produces 4-character codes. |
Both implement PhoneticInterface and handle Unicode normalization (accents, ligatures like œ and æ) internally.
Phonetic encoder benchmarks
Measured on a set of 520 French words, 1000 iterations each (PHP 8.4):
| Encoder | Per word | Throughput |
|---|---|---|
| metaphone | ~2 µs | ~500k/s |
| Soundex2 | ~35 µs | ~28k/s |
| Phonetic | ~51 µs | ~20k/s |
PHP's native metaphone() is a C extension and unsurprisingly the fastest. Both French encoders are pure PHP with extensive regex-based rule sets, yet fast enough for typical use — encoding 1000 words takes under 50ms.
Automatic setup after migrations
The package listens to Laravel's MigrationsEnded event and automatically runs searchable:enable after every successful up migration. This means:
- After
php artisan migrate, the searchable column and fulltext index are added to any new Searchable model. - After
php artisan migrate:fresh, they are recreated along with the rest of your schema. - Rollbacks (
down) and pretended migrations (--pretend) are ignored.
This is fully automatic — no configuration needed. If you need to re-index existing records, run the command manually with --index.
The Enable command
The command detects the database driver and creates the appropriate index:
- MySQL:
ALTER TABLE ... ADD FULLTEXT - PostgreSQL:
CREATE INDEX ... USING GIN(to_tsvector(...))
Adding Searchable to an existing model
You can add the Searchable feature to a model with pre-existing data at any time. After implementing SearchableInterface and using the Searchable trait, run the enable command with --index to set up the column, create the fulltext index, and populate it for all existing records:
You can also run it without --model to process all Searchable models at once. Indexing is optimized with batch processing to handle large tables efficiently.
When to re-index
The searchable column is automatically kept in sync on every Eloquent save. Manual re-indexing is only needed when:
- Adding Searchable to a model with existing data — existing rows have no searchable content yet.
- Changing
$searchables— after adding or removing fields from the index, existing rows still contain the old content. - Mass imports that bypass Eloquent — raw SQL inserts,
DB::insert(), or bulk imports that skip model events won't populate the searchable column.
In all these cases, run:
Contributing
Contributions are welcome. Feel free to open issues and submit pull requests.
License
Searchable is open-sourced software licensed under the MIT license.