padam87/search-bundle
Lightweight Symfony bundle for adding search to Doctrine-backed applications. Define searchable fields and filters, build queries from request parameters, and return paginated results with minimal configuration.
composer require padam87/search-bundle. On anything newer the constraint graph usually fails — you either need --ignore-platform-reqs, a manual "padam87/search-bundle": "dev-master" entry, or you accept that this is a legacy-only tool and plan a replacement.app/AppKernel.php:
new Padam87\SearchBundle\Padam87SearchBundle(),
There is typically little to no configuration required; check DependencyInjection/Configuration.php and Resources/config/ for the service IDs and any tunables before assuming defaults.Resources/doc may be thin or stale. The authoritative references are the Annotation/ directory (what you can put on entity properties), the expression/parser classes (what query syntax is accepted), and Resources/config/services.xml (service IDs to inject).$request->query->get('q'), and render the resulting query/result.Start with one entity and one text field. Get a working /search?q=foo endpoint before touching operators, sorting, or joins — the value of the package is the string-to-QueryBuilder translation, and you want to see exactly what it produces early.
Annotation-driven field mapping. The core pattern is declaring which entity properties are searchable, then letting the bundle map user-supplied terms onto those properties. Keep the annotation surface small and intentional — every annotated field is effectively a public query parameter.
Controller as a thin adapter. Keep the controller dumb: read q, read page/sort, call the search service, hand the result to a paginator, render. Business rules (which fields are exposed, who can search what) belong in a dedicated search service or a per-entity configuration, not inline in the action.
Paginate explicitly. This bundle builds a query; it does not paginate. Wire the returned QueryBuilder into KnpPaginatorBundle or Pagerfanta immediately — otherwise you'll be tempted to getResult() on an unbounded query and hit memory limits the first time someone searches for a common word.
One generic search action, many entities. A common day-to-day pattern is a single SearchController::searchAction($entityAlias) that resolves an alias to an entity class, runs the search, and renders a shared template. This keeps search UX consistent across the app and means adding a searchable entity is a config/annotation change, not a new controller.
Search form type. Build a small SearchType with a single q text field plus optional filters. Bind it, use handleRequest, and pass the validated string onward. This gives you CSRF, trimming, and a natural place to normalize input before it reaches the parser.
Repository hooks for anything non-trivial. When a search needs a join (searching a related entity's name), sorting by a computed value, or a WHERE ... IN restriction for permissions, do it in a custom repository method that accepts the search criteria and applies them to a QueryBuilder the bundle started. Don't try to express relational logic in the query string.
Reusable filter/expression handlers. If the bundle exposes operator or expression extension points (check for tagged services or an expression-handler interface), register app-specific operators there — e.g. is:active, owner:me, date ranges. This keeps the query-string grammar expressive without forking the package.
Result decoration. The bundle returns entities, not view models. Map to arrays/DTOs in the controller or a transformer if your templates need highlighting, snippets, or computed display fields — and if you want match highlighting, do it yourself; there's no relevance scoring or snippet extraction here.
composer.json and vendor-fork it if you need a fix, because upstream PRs are not going to land.cache:clear (and in dev, warmup) before debugging. "My field isn't searchable" is almost always a stale metadata cache, not a bug.:, >, <, quotes, and spaces in the query string need proper encoding in links and forms. Half of "search is broken" reports are the browser or a hand-built link mangling the expression.LIKE 'term%' over LIKE '%term%', or accept that you need Elasticsearch/Algolia.$qb->getDQL() and getParameters()) before executing. The Doctrine profiler in the Symfony web toolbar shows the SQL, but the DQL is what tells you whether the parser interpreted your query the way you intended.services.yml is usually cleaner than subclassing, and lets you inject app-specific defaults (page size, default sort, field whitelist).AppKernel registration for a bundle-less config, and verify the annotation reader still works with modern Doctrine annotations. Budget for a replacement (Doctrine filters, a custom QueryBuilder service, or a real search engine) rather than a port.How can I help you explore Laravel packages today?