PHPackages                             whitecube/laravel-search-builder - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Search &amp; Filtering](/categories/search)
4. /
5. whitecube/laravel-search-builder

ActiveLibrary[Search &amp; Filtering](/categories/search)

whitecube/laravel-search-builder
================================

A package to build fast, index-friendly search queries for Laravel

v0.2.0(9mo ago)267.3k↓50%1PHP

Since Apr 24Pushed 9mo ago1 watchersCompare

[ Source](https://github.com/whitecube/laravel-search-builder)[ Packagist](https://packagist.org/packages/whitecube/laravel-search-builder)[ RSS](/packages/whitecube-laravel-search-builder/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (5)Dependencies (5)Versions (6)Used By (0)

Search Builder for Laravel
==========================

[](#search-builder-for-laravel)

A package to build fast, index-friendly search queries for Laravel.

What does it do?
----------------

[](#what-does-it-do)

The purpose of this package is to allow you to build multi-condition search queries with scores, and make use of covering indexes to be super fast. This means simply using this package as shown is not everything – you need to have a well designed database, with properly designed indexes for your searches, to get good results. To learn more about this topic, we recommend watching the free [PlanetScale MySQL for Developers course](https://planetscale.com/courses/mysql-for-developers/introduction/course-introduction).

Installation
------------

[](#installation)

```
composer require whitecube/laravel-search-builder
```

How to structure your query
---------------------------

[](#how-to-structure-your-query)

To make your search queries extremely fast, the search builder will pack all of your conditions in a subquery that will aim to hit as many covering indexes as possible, in order to build an aggregated table that only contains ids of the pertinent models (along with a score, more on this later). This aggregated table will then be used to filter down the actual table with an inner join. This means that the processing of your search logic is done entirely on your indexes, and the full table is only accessed at the end, which dramatically speeds everything up.

However, the package can not detect your database structure, so it is your responsibility to create your indexes correctly, and in such a way that your search condition queries will not have to access your main tables' data.

Here's an example of what we're looking to achieve, in raw SQL. Given that we have a products table, and we want to search it by reference and by name, and prioritise the reference over the name:

```
with id_and_total_score as (
    select id, sum(score) as score from (
        -- This query makes use of a covering index on the ref column
        select id, 100 as score
        from products
        where ref = 'SEARCH_STRING'

        union all

        -- This query makes use of a covering index on the name column
        select id, 50 as score
        from products
        where name = 'SEARCH_STRING'
    )
    as ids_and_scores
    group by id
)

select * from products
inner join id_and_total_score on id_and_total_score.id = products.id
order by score desc;
```

The search builder instance
---------------------------

[](#the-search-builder-instance)

You can get a search builder instance just by passing it the model you want to search.

```
use \App\Models\Product;
use \Whitecube\SearchBuilder\SearchBuilder;

$builder = new SearchBuilder(Product::class); // You can also pass it an instance of your model
```

Or, if your model uses the `HasSearchBuilder` trait, you can easily get a search builder instance this way, which allows you to cleanly chain your condition methods later.

```
use Whitecube\SearchBuilder\HasSearchBuilder;

class Product extends Model
{
    use HasSearchBuilder;
}
```

```
$builder = Product::searchBuilder();
```

Defining search conditions
--------------------------

[](#defining-search-conditions)

Once you have a search builder instance, you can use it to define your search conditions, by passing eloquent builder instances to the `search` method.

```
Product::searchBuilder()
    ->search(Product::select('id')->where('ref', 'SEARCH_STRING'), score: 100)
    ->search(Product::select('id')->where('name', 'SEARCH_STRING'), score: 50);
```

The score is optional and will be automatically computed if missing, using the order in which the conditions are defined, with the highest score on top.

```
Product::searchBuilder()
    ->search(Product::select('id')->where('ref', 'SEARCH_STRING'), score: 100) // score = 100
    ->search(Product::select('id')->where('name', 'SEARCH_STRING')) // score = 3
    ->search(Product::select('id')->where('description', 'SEARCH_STRING')) // score = 2
    ->search(Product::select('id')->where('content', 'SEARCH_STRING')); // score = 1
```

You can easily search on related tables. Remember to only select the column that references the id of the table you're searching.

```
Product::searchBuilder()
    // Search on a related table
    ->search(Lot::select('product_id')->where('barcode', 'SEARCH_STRING'))
    // Search on a relation of a related table
    ->search(Lot::select('product_id')->whereHas('delivery', function ($query) {
        $query->where('address', 'SEARCH_STRING');
    }))
```

If you wish to split the search terms on spaces, dashes, dots and underscores, and perform individual queries on each term, you can call the `splitTerms` method.

```
$terms = 'foo bar baz';

Product::searchBuilder()
    ->splitTerms($terms, function (SearchBuilder $searchBuilder, string $term) {
        // Called once with $term = foo, once with $term = bar, and once with $term = baz
        return $searchBuilder->search(Product::select('id')->where('ref', $term));
    });
```

Getting the results
-------------------

[](#getting-the-results)

After defining your conditions, you can get the collection of results by calling the `get` method.

```
$results = Product::searchBuilder()
    ->search(Product::select('id')->where('ref', 'SEARCH_STRING'), score: 100)
    ->search(Product::select('id')->where('name', 'SEARCH_STRING'), score: 50)
    ->get();
```

Or, if you need to do more work on the query yourself, you can get the query builder instance.

```
$query = Product::searchBuilder()
    ->search(Product::select('id')->where('ref', 'SEARCH_STRING'), score: 100)
    ->search(Product::select('id')->where('name', 'SEARCH_STRING'), score: 50)
    ->getQuery();
```

💖 Sponsorships
--------------

[](#-sponsorships)

If you are reliant on this package in your production applications, consider [sponsoring us](https://github.com/sponsors/whitecube)! It is the best way to help us keep doing what we love to do: making great open source software.

Contributing
------------

[](#contributing)

Feel free to suggest changes, ask for new features or fix bugs yourself. We're sure there are still a lot of improvements that could be made, and we would be very happy to merge useful pull requests.

Thanks!

### Unit tests

[](#unit-tests)

When adding a new feature or fixing a bug, please add corresponding unit tests. The current set of tests is limited, but every unit test added will improve the quality of the package.

Run the test suite by calling `./vendor/bin/pest`.

Made with ❤️ for open source
----------------------------

[](#made-with-️-for-open-source)

At [Whitecube](https://www.whitecube.be) we use a lot of open source software as part of our daily work. So when we have an opportunity to give something back, we're super excited!

We hope you will enjoy this small contribution from us and would love to [hear from you](mailto:hello@whitecube.be) if you find it useful in your projects. Follow us on [Twitter](https://twitter.com/whitecube_be) for more updates!

###  Health Score

37

—

LowBetter than 83% of packages

Maintenance58

Moderate activity, may be stable

Popularity33

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity38

Early-stage or recently created project

 Bus Factor1

Top contributor holds 87.5% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~210 days

Total

5

Last Release

279d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/8435657?v=4)[Whitecube](/maintainers/Whitecube)[@whitecube](https://github.com/whitecube)

---

Top Contributors

[![voidgraphics](https://avatars.githubusercontent.com/u/9298484?v=4)](https://github.com/voidgraphics "voidgraphics (14 commits)")[![theokbokki](https://avatars.githubusercontent.com/u/90846584?v=4)](https://github.com/theokbokki "theokbokki (2 commits)")

###  Code Quality

TestsPest

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/whitecube-laravel-search-builder/health.svg)

```
[![Health](https://phpackages.com/badges/whitecube-laravel-search-builder/health.svg)](https://phpackages.com/packages/whitecube-laravel-search-builder)
```

###  Alternatives

[mehradsadeghi/laravel-filter-querystring

Filter your queries based on url query string parameters like a breeze.

169118.2k](/packages/mehradsadeghi-laravel-filter-querystring)[pos-lifestyle/laravel-nova-date-range-filter

A Laravel Nova date range filter.

16179.1k](/packages/pos-lifestyle-laravel-nova-date-range-filter)[omure/scout-advanced-meilisearch

Laravel Scout extension that allows to use meilisearch advanced features as well as has an extended collection driver for testing purposes.

123.9k](/packages/omure-scout-advanced-meilisearch)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
