stinger-soft/doctrine-entity-search-bundle
A Symfony bundle that adds full-text search to Doctrine entities: index chosen fields, then query records through a simple search service and get ranked results without writing custom DQL. Drop it into existing Symfony and Doctrine projects to make entity data searchable with minimal configuration.
This bundle is the Doctrine ORM bridge for EntitySearchBundle — it supplies the query-building layer, while the parent bundle defines the search contract your entities implement. Treat it as a thin integration, not a full search engine.
composer require stinger-soft/entity-search-bundle stinger-soft/doctrine-entity-search-bundle
config/bundles.php (Flex may not auto-register a zero-install package):
StingerSoft\EntitySearchBundle\EntitySearchBundle::class => ['all' => true],
StingerSoft\DoctrineEntitySearchBundle\DoctrineEntitySearchBundle::class => ['all' => true],
SearchableEntityInterface/SearchServiceInterface the parent defines. That interface is your actual API surface; the Doctrine package just wires it to an EntityManager.class Product implements SearchableEntityInterface
{
public function getSearchableFields(): array
{
return ['name', 'sku', 'description'];
}
}
public function search(SearchServiceInterface $search, string $term): array
{
return $search->search($term, Product::class);
}
Per-entity field declaration. The idiomatic pattern is to let each entity describe its own search surface via the interface method rather than centralising a field map. This keeps search logic colocated with the schema and survives entity refactors.
Weighted / prioritised fields. Most implementations of this style accept an associative array where the key is the field and the value is a weight or ordering hint (['name' => 10, 'description' => 1]). Check the interface signature — if it returns a flat array, fall back to ordering by relevance manually or via a secondary ORDER BY.
Controller-level wiring. Inject the service via autowiring into a controller action, bind ?q= from the request, and hand the term straight in. Keep pagination outside the search call:
search() to get a QueryBuilder or result set, then attach KnpPaginator/Pagerfanta adapters.Query, wrap it in a Doctrine adapter rather than ->getResult() directly, so you preserve paging.Query customisation hook. If the returned object is a QueryBuilder, the common extension pattern is to grab it post-build and add your own andWhere() — e.g. filtering to active = true or scoping to a tenant. Do this in a small domain service rather than the controller so the scoping is testable.
Multi-entity search. For a site-wide search box, loop over your searchable entity classes, call the service per class, and merge/sort results in PHP. There is generally no cross-entity relevance ranking built in — normalise scores yourself if you need a unified feed.
Testing. Because the implementation is Doctrine-bound, integration-test against a real (SQLite) connection rather than mocking the EntityManager. Assert on returned identifiers, not on generated DQL strings.
LIKE %term% semantics: leading wildcards kill index usage and performance degrades linearly on large tables. For anything beyond small datasets, reach for a real search backend (Elastic/Meilisearch) rather than pushing this bundle harder.LIKE is case-sensitive. If the bundle doesn't normalise this (likely a plain LIKE), searches behave differently between dev SQLite, staging MySQL, and prod Postgres. Test on your production engine.setParameter(). A zero-audience package may not have had security review.->select()/->leftJoin() fetches on the returned QueryBuilder if it exposes one.composer.json, and consider vendoring or forking the ~few hundred lines of query-building if the dependency becomes load-bearing.doctrine_entity_search: in config/packages/. Check the bundle's DependencyInjection/Configuration.php in the repo — that file is the authoritative reference when docs are absent.How can I help you explore Laravel packages today?