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

Symfony Doctrine Search Bundle Laravel Package

intellect-web-development/symfony-doctrine-search-bundle

A Symfony bundle for integrating Doctrine search functionality into your application, helping you add entity search, indexing, and query support with streamlined service configuration for Doctrine-backed Symfony projects.

View on GitHub
Deep Wiki
Context7

Getting Started

Treat this bundle as a thin, read-only HTTP facade over Doctrine: you give it an entity and query parameters, it gives you filtered/paginated JSON. Before writing any code, verify that assumption against the source, because the package has zero stars, zero dependents, and a very low score — the README may be the only contract you get.

Minimal steps

  1. Install and inspect what actually landed:

    composer require intellect-web-development/symfony-doctrine-search-bundle
    ls vendor/intellect-web-development/symfony-doctrine-search-bundle/src
    
  2. Register the bundle if Flex did not. The class name will match the package namespace, typically:

    // config/bundles.php
    IntellectWebDevelopment\SymfonyDoctrineSearchBundle\SymfonyDoctrineSearchBundle::class => ['all' => true],
    
  3. Discover the routes it exposes:

    bin/console debug:router | grep -i search
    
  4. Check for a configuration file. If the bundle ships a Configuration tree, Symfony Flex may have created config/packages/*search*.yaml; otherwise inspect DependencyInjection/Configuration.php in the vendor directory.

  5. Confirm the entry point with a real request against a mapped entity:

    curl 'https://localhost/api/search/product?q=widget&page=1&limit=20'
    

Where to look first

  • src/Controller/ — the HTTP surface, request parameter names, response shape, and status codes.
  • src/DependencyInjection/Configuration.php — what is configurable versus hard-coded.
  • src/Service/ or src/Search/ — how the Doctrine query is built, which fields are searched, and whether filters/sorting are supported.
  • Resources/config/routes.yaml (or attributes on the controller) — the actual route prefix and path variables.
  • README.md and tests — the only reliable usage examples in a package this young.

First use case

Use it for a low-risk read endpoint: an admin table search, a typeahead/autocomplete endpoint, or a public catalog filter. Start with one entity, one or two string fields, and a hard limit. Do not make it the only way your application queries that entity; wrap it behind your own service interface so you can replace it later.

Implementation Patterns

Keep it behind your own boundary

The most important day-to-day pattern is isolation. Inject the bundle's search service/controller logic into your own application service and expose your own interface:

interface EntitySearchInterface
{
    public function search(string $entity, array $criteria, int $page, int $limit): SearchResult;
}

Then adapt the bundle inside DoctrineSearchAdapter. If the bundle stalls, has a security issue, or is abandoned, you swap one adapter for a hand-written QueryBuilder, a PostgreSQL full-text query, or Meilisearch without touching controllers.

Custom controller for access control and tenancy

Do not expose the bundle's route directly if it accepts an entity name or arbitrary filters. Subclass or decorate its controller/service and add:

  • An allow-list of searchable entities.
  • Tenant/account scoping appended to every query (AND e.tenant = :tenant).
  • Field-level authorization, so users cannot filter on salary, internal notes, etc.
  • Consistent error responses (404 for unknown entity, 400 for bad parameters).

Stable response envelope

Normalize the bundle's output into your own API shape rather than letting clients depend on vendor internals:

{
  "data": [ ... ],
  "meta": { "page": 1, "limit": 20, "total": 143 },
  "links": { "next": "...", "prev": null }
}

Use Symfony Serializer groups or explicit DTO mapping. This avoids leaking every Doctrine-mapped field — including relations that trigger lazy loads — and gives you room to change the underlying engine.

Frontend integration

For typeahead, debounce (~250–300 ms), send a short query, cap results at 5–10, and abort stale requests with AbortController. For admin tables, keep search, sort, filter, and pagination in the URL query string so views are shareable and back-button friendly. Always display the total count only if the bundle provides an efficient count; otherwise use “has more” pagination.

Filters and sorting

If the bundle supports field filters, validate every field name against Doctrine metadata before passing it through. Whitelist sortable columns. For date/number ranges, confirm whether the bundle expects field[gte], field_from, or comma-separated values — these conventions are rarely portable and are a common source of frontend/backend mismatch.

Testing

Write functional tests with KernelBrowser and fixtures:

  • Search returns only matching entities.
  • Unknown entity returns 404, not 500.
  • A user from tenant A cannot see tenant B results.
  • limit above the maximum is clamped.
  • Invalid sort/filter fields are rejected.

Use the Symfony profiler or doctrine logging in dev to inspect the generated SQL. If the bundle does not expose its query builder, this is your main debugging tool.

Caching

For public, read-heavy endpoints, add HTTP caching (Cache-Control, ETag) at the controller/reverse-proxy level. Invalidate by tagging responses per entity type and purging on Doctrine postPersist/postUpdate/postRemove events, or simply keep TTLs short. Do not cache tenant-scoped results without including tenant identity in the cache key.

Gotchas and Tips

Package risk is the first gotcha. Zero stars, zero dependents, and a score around 19.7 mean no community validation. Pin an exact version in composer.json, review the source before production use, and check the release history — the listed last release of 2026-10-11 is unusual and should be verified against Packagist tags. Prefer ^x.y with a committed lock file, and avoid relying on it for critical authorization logic.

Route exposure. Bundles often register routes under a generic prefix such as /api/search or /_search. Check debug:router and your security.yaml access_control. It is easy to accidentally ship an unauthenticated endpoint that exposes entity data.

Arbitrary entity names are dangerous. If the API takes an entity/FQCN parameter, a client could probe non-searchable entities or trigger metadata errors. Always map public names to a server-side allow-list:

private const SEARCHABLE = [
    'product' => Product::class,
    'article' => Article::class,
];

Leading-wildcard LIKE does not use indexes. Most “search any field” implementations generate LIKE '%term%'. That is fine for small tables and painful at scale. For serious use, add a database full-text index (MySQL FULLTEXT, PostgreSQL tsvector/pg_trgm) or push search to a dedicated engine. Watch query plans with EXPLAIN.

Sort and filter injection. Never interpolate request parameters into DQL. If the bundle accepts sort=createdAt or order=asc, confirm it validates against entity metadata. If not, wrap the endpoint and validate yourself.

Pagination count cost. A COUNT(*) over a large filtered set can dominate response time. If the bundle always counts, consider a custom endpoint using fetchJoin/Paginator with a “next page exists” check instead.

Lazy loading during serialization. Returning entities directly often triggers N+1 queries for relations. Prefer DTOs or configure serializer groups. If you must return entities, fetch-join the relations you expose.

Database portability. Case-insensitive LIKE behaves differently on MySQL (collation-dependent), PostgreSQL (ILIKE or citext), and SQLite. Accent handling also differs. Test on the database you deploy, not just SQLite in CI.

Doctrine metadata edge cases. Inherited entities, embeddables, non-mapped properties, and association fields may not be searchable or sortable. Verify behavior with your actual inheritance model.

Config and container caching. After changing bundle configuration, run bin/console cache:clear and bin/console lint:container. A misconfigured service often surfaces as a generic 500 rather than a helpful error.

Error semantics. Confirm whether an unknown entity, malformed page, or invalid filter produces 400/404 or a 500 with a stack trace. Normalize this in your adapter; clients should never see Doctrine exceptions.

Extension points to look for. The bundle may expose custom filter classes, event subscribers, or a configurable searchable-field list. If it does, prefer extending those over forking. If it does not, decoration and your own adapter are the safest extension points. Avoid editing vendor code; use a Composer patch only as a temporary measure.

Have an exit plan. Because the package is unproven, define the replacement path up front: a small QueryBuilder-based search service for simple cases, and a dedicated search engine once relevance, typo tolerance, or scale matters. The bundle is most valuable as a quick way to stand up a first endpoint — not as long-term infrastructure.

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.
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table
siberfx/flysystem-wasabi
hollyit/token-replace
ippanelcom/laravel-sdk
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel