atomicptr / symfony-indexed-search
Indexed Search is a Symfony bundle that provides a straightforward database-powered search functionality for Doctrine entities. It makes implementing search across your application's data simple, flexible and easy to integrate.
Package info
github.com/atomicptr/symfony-indexed-search
Type:symfony-bundle
pkg:composer/atomicptr/symfony-indexed-search
Requires
- php: ^8.5
- ext-intl: *
- doctrine/dbal: ^4.5
- doctrine/doctrine-bundle: ^3.0
- doctrine/orm: ^3.6.8
- psr/clock: ^1.0
- symfony/clock: ^8.0
- symfony/config: ^8.0
- symfony/console: ^8.0
- symfony/dependency-injection: ^8.0
- symfony/http-kernel: ^8.0
Requires (Dev)
- carthage-software/mago: ^1.59
- doctrine/doctrine-migrations-bundle: ^4.0
- ekino/phpstan-banned-code: ^3.2
- pestphp/pest: ^5.3.5
- phpstan/extension-installer: ^1.4.3
- phpstan/phpstan: ^2.3.5
- phpstan/phpstan-deprecation-rules: ^2.0.5
- phpstan/phpstan-doctrine: ^2.1.2
- phpstan/phpstan-strict-rules: ^2.1.1
- phpstan/phpstan-symfony: ^2.1.1
- shipmonk/dead-code-detector: ^1.4.2
- symfony/framework-bundle: ^8.0
Suggests
- doctrine/doctrine-migrations-bundle: Manage the document table through your migrations
- shipmonk/dead-code-detector: Include extension.neon so members only the bundle reads aren't reported as unused
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-11-10 19:01:00 UTC
README
Indexed Search is a Symfony bundle that provides a straightforward database-powered search functionality for Doctrine entities. It makes implementing search across your application's data simple, flexible and easy to integrate.
Requirements
- PHP 8.5+ (ext-intl required) and Symfony 8
- Doctrine
- SQLite, MySQL, MariaDB or PostgreSQL
Installation
composer require atomicptr/symfony-indexed-search
Make sure it's installed in your config/bundles.php:
Atomicptr\Symfony\IndexedSearch\IndexedSearchBundle::class => ['all' => true],
You might also need to create migrations for our index tables:
bin/console doctrine:migrations:diff bin/console doctrine:migrations:migrate
Usage
Mark what you want to search and what you want to filter by:
#[ORM\Entity] #[Searchable(filters: ['type' => 'product'])] // fixed filters for every product class Product { #[ORM\Column] #[SearchableText(weight: Weight::Highest)] // Highest, High, Normal (default) or Low private string $name; #[ORM\Column(type: 'text')] #[SearchableText(format: TextFormat::Html)] // optional, strips the HTML private string $description; #[ORM\Column] #[SearchableFilter('tenant')] private int $tenantId; #[ORM\Column] #[SearchableDate] // optional, for sorting by date private DateTimeImmutable $createdAt; #[ORM\Column] #[SearchableWhen] // optional, only indexed while true private bool $published; }
Build the index:
bin/console indexed-search:index
And search:
$result = $searchService->search( 'red sho', filters: ['tenant' => 42, 'type' => ['product', 'article']], sort: SearchSort::Relevance, // or RelevanceWithRecency, Newest, Oldest page: 1, hydrate: true, ); foreach ($result->hits as $hit) { $hit->entity; // your Product } $result->entities(); // or just the Products $result->total; $result->hasNextPage;
Every word has to match the start of a word somewhere in the text, so red sho finds "Red running shoes". Values of the
same filter are OR, different filters are AND
The index doesn't update itself, call SearchIndexer::index(), indexByIds() or remove() or rerun the command when
your entities change
Translations
If an entity should be found in multiple languages, return one document per language instead of using the attributes:
#[SearchableDocuments] public function searchDocuments(): iterable { yield Document::create('en') ->withText($this->name, Weight::Highest) ->withFilter('lang', 'en'); yield Document::create('de') ->withText($this->nameGerman, Weight::Highest) ->withFilter('lang', 'de'); }
Search with filters: ['lang' => 'de'] and $hit->variant tells you which one matched
License
MIT