Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Searchable Laravel Package

eslam-dev/laravel-searchable

A Laravel package that adds searchable behavior to Eloquent models, letting you index records and run quick, flexible searches across your data with minimal setup. It plugs into your existing models so you can find matching results without writing custom query logic or wiring up a separate search se...

View on GitHub
Deep Wiki
Context7

Getting Started

Version context: 1.0.2 is a patch release (1.0.1 → 1.0.2) and the release notes are a bare compare link with no described features, breaking changes, or deprecations. Treat it as bugfix-only: nothing here changes how you integrate the package, but read the diff before bumping in a pinned/locked environment. Because there is no prior assessment, the notes below describe the day-to-day shape of a "searchable model" package of this kind — verify exact class names, config keys, and method signatures against the repo README and the trait source, since the changelog does not document the API surface.

Minimal first steps:

  1. Install and confirm discovery

    composer require eslam-dev/laravel-searchable
    

    Laravel's package auto-discovery should register the service provider. If the package ships a config file, publish it (php artisan vendor:publish --tag=searchable-config or the tag listed in the README) and commit it — do not rely on package defaults in production.

  2. Read the trait before the README. The single most important file is the Searchable trait itself (typically under src/). It tells you exactly what it adds to the model: a query scope, a static search entry point, and any protected properties it expects you to define (searchable columns, weights, minimum term length). This is faster than guessing from examples.

  3. Wire up one model end-to-end. Add the trait to a model with a small, stable schema (e.g. Article), declare the searchable columns, and replace an existing naive query on an index page. Do this before touching your biggest table — search packages hide their cost until you point them at real data volume.

  4. First real use case: swapping where('title', 'like', "%{$q}%") chains in a listing controller for the package's scope, so multi-column matching, weighting, and (if supported) relevance ordering live in one place rather than being copy-pasted per controller.

Implementation Patterns

Trait-on-model, scope-in-controller. The idiomatic usage is a thin trait declaration on the model and a fluent scope call in the controller, so existing query constraints still compose:

// Model — illustrative; confirm property names against the trait source
use Searchable;

protected array $searchable = ['title', 'body'];
// Controller
$results = Article::query()
    ->where('published', true)      // your constraints still apply
    ->search($request->string('q')) // package scope
    ->with('author')                // eager load as usual
    ->paginate(20);

The key pattern: treat the search scope as one clause among many, not as a replacement for the query builder. Everything you rely on today — where, whereHas, policy scoping, with, paginate, cursorPaginate — should remain available on both sides of it. If it doesn't, that's a signal the package is returning a collection rather than a builder, which changes pagination and eager-loading strategy significantly.

Scope search to the caller, not just the term. Multi-tenant and authorization filters belong outside the search scope:

$results = Article::query()
    ->where('tenant_id', $tenant->id)
    ->whereIn('status', $allowedStatuses)
    ->search($term)
    ->paginate();

This keeps the package ignorant of your permission model and makes it trivial to add a global scope or policy later.

Centralize term normalization. Put trimming, minimum-length checks, and multi-word splitting in a FormRequest or a small SearchQuery value object rather than in each controller. Packages differ on whether they AND or OR multiple words and whether they strip wildcards — pinning that behaviour in one place means an upgrade can't silently change your UX page by page.

Keep a fallback path. For low-traffic or admin screens, a LIKE fallback when the package returns nothing is often not worth the complexity — but for user-facing search on large tables, decide early whether the package's matching (usually LIKE-based) is genuinely sufficient or whether you need MATCH ... AGAINST / Postgres tsvector / an external index. This package is a convenience layer, not a search engine; the integration tip is to isolate search behind a SearchService so swapping the driver later is a one-file change.

Test the scope, not the page. Assert on the query builder (toSql() / bound terms) for one integration test per searchable model, plus one feature test that the term reaches the scope from the request. That catches the realistic failure mode — a column added to the model but not to the searchable list — without brittle HTML assertions.

Gotchas and Tips

  • Trait name collisions. Searchable is a very common trait name (Spatie and others use it). If you depend on more than one search package, alias on import: use Searchable as PackageSearchable;. A fatal "trait method conflict" on boot is the usual symptom.
  • Wildcard injection in terms. If the package interpolates % and _ from user input into LIKE, a search for 100% or a_b behaves as a pattern rather than literal text. Escape or strip these at the request layer — cheap, and avoids the "search returns everything" bug report.
  • Collation and case sensitivity. MySQL LIKE is case-insensitive under utf8mb4_unicode_ci; Postgres LIKE is case-sensitive and needs ILIKE. Packages that build raw SQL often get this wrong on one driver. Test on the driver you actually deploy on, not SQLite — SQLite's LIKE is case-insensitive for ASCII, which will happily hide the bug in your test suite.
  • select * and relevance ordering. If the package supports weighting/ordering, ordering by a computed relevance score can conflict with paginate's stability and with distinct/groupBy. Order by relevance then by id as a tiebreaker.
  • Config caching. Any published config is baked into bootstrap/cache/config.php. In Docker/CI, run php artisan config:clear when changing searchable settings, or you will debug a setting that is loaded and ignored.
  • Extension point: override, don't fork. When the default matching is wrong for one model, override the scope or the relevant protected method on that model rather than editing vendor code — patches like 1.0.2 land often, and a fork makes them expensive.
  • Upgrade hygiene for patch releases. With changelog-only releases, review the compare diff (git diff 1.0.1 1.0.2 against the tag or the GitHub compare view) for changes to the trait's protected properties and the query-building internals; those are the surfaces your code actually depends on. Pin to ~1.0 and let Composer take patch bumps, but run your search integration tests before merging the lockfile change.
  • Debugging slow or empty results. Log the generated SQL (->toSql() with bindings via ->getBindings()) rather than dumping the builder — the failure is nearly always the term-building step, not the database. If results are empty, check minimum-term-length config and whether the searchable columns are actually listed on the model before suspecting indexing.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core