intaro/postgres-search-bundle
A Symfony bundle for integrating PostgreSQL native full-text search with Doctrine entities. It offers indexed tsvector support, search query helpers, and relevance ranking, helping applications avoid external search engines while using Postgres search features.
Architecture fit — a framework mismatch that a TPM must surface immediately. The package is a Symfony2 bundle built around Doctrine 2 entities, the Symfony DI container, and bundle kernel conventions. A Laravel codebase has none of that: it runs Eloquent (or optionally Doctrine via a third-party bridge) on a service-provider model. There is no clean "install and configure" path. For a TPM, this reframes the decision: you are not evaluating a dependency, you are evaluating a reference implementation of a technique — PostgreSQL native full-text search (tsvector columns, GIN indexes, tsquery matching, ts_rank weighting). The technique is sound; the packaging is not usable in our stack. The opportunity score (18.54) reflects that the underlying pattern has value even though the artifact does not.
What the package actually contributes (and what a TPM should bank). Stripped of Symfony scaffolding, its value is a documented recipe: map searchable fields to a weighted tsvector, index with GIN, build tsquery with configurable dictionaries and language-aware stemming, rank with ts_rank/ts_rank_cd, and expose prefix/phrase query helpers. That recipe is reproducible in Laravel in roughly one to two engineering days of spike work plus a migration. The TPM takeaway: the package shortens discovery time, not delivery time.
Integration feasibility — low for adoption, moderate for pattern extraction. Even in its native Symfony2 context the package is stranded: Symfony 2 is end-of-life (2018/2019), so the bundle sits on an unmaintained framework generation. In Laravel, adopting it would require pulling in Doctrine, an ORM bridge, and a bundle emulation layer — all to obtain SQL that we can write directly. That is inverted cost/benefit. The realistic integration path is a read-only port: use the repository as source material for the SQL and schema design, then reimplement natively.
Technical risk — high, and it's supply-chain risk as much as code risk.
websearch_to_tsquery in PG11, generated columns in PG12).Key questions the TPM should put to the decision owner:
LIKE queries, raw SQL, Laravel Scout, or an external engine? This determines whether we're replacing nothing, upgrading cheaply, or duplicating capability.tsvector columns, or is this net-new schema work with backfill and migration risk?Verdict for the TPM: do not adopt the package; adopt the pattern. Rejecting it costs us nothing we can't rebuild in days, and accepting it imports an unmaintained, unsupported dependency into a modern Laravel application.
Stack fit — none at the framework boundary. Laravel's idioms are migrations, Eloquent/query builder, service providers, and (optionally) Scout. The bundle's idioms are annotations, entity listeners, DQL, and bundle configuration. The only viable integration is a translation: extract the SQL semantics from the bundle, then express them in Laravel-native constructs.
Migration path — port the pattern, discard the dependency.
tsvector), index type (GIN), query construction (to_tsquery vs plainto_tsquery vs websearch_to_tsquery), weighting (setweight with A/B/C/D classes), ranking (ts_rank vs ts_rank_cd), and dictionary/regconfig handling. Write this down as the specification.tsvector columns (PostgreSQL 12+) or trigger-maintained columns on older versions, with GIN indexes. Verify against your managed-Postgres offering — some providers restrict extensions or lag versions.whereRaw with bound parameters for tsquery construction, exposed as a local Eloquent scope or a dedicated SearchRepository. Never string-concatenate user input into tsquery; prefer plainto_tsquery/websearch_to_tsquery and bind parameters.ts_rank_cd(...) as an alias, order by it, paginate with Laravel's paginator — matching what the bundle did, minus the lifecycle hooks.SearchService contract so the backend can later be swapped for Scout + Meilisearch/Typesense/OpenSearch without touching callers. This is the single highest-leverage architectural decision and it's cheap now, expensive later.Compatibility notes.
websearch_to_tsquery).regconfig selection — the bundle didn't solve that for you either, so scope it deliberately.tsvector alone; pg_trgm is a partial answer, a dedicated engine is the full one.Sequencing (TPM-owned plan).
SearchService, parameterized and injectable.Maintenance — low surface area, but 100% owned by us. By porting rather than depending, we eliminate upstream risk and upstream fixes. The code is small (a migration, an index, a query scope, a ranking clause), and it lives in our repo under our review process. Budget ongoing ownership of the FTS SQL, index hygiene, and relevance tuning. Net cost is lower than adopting the bundle, because there is no upstream to track, no version to chase, and no CVE feed to monitor for a package that will never be patched.
Support — none upstream. No maintainer, no issue triage, no security advisories, no CVE response. For a TPM, this is a governance blocker: the package cannot be entered into a dependency register with a named, responsive owner. If the organization requires supported dependencies with a security-response path, this fails by definition and the conversation ends there.
Scaling — adequate for the "already own the database" tier. Postgres FTS with GIN indexes handles read-heavy search over tens of millions of rows given appropriate hardware and work_mem tuning. The ceilings to communicate upward:
tsvector maintenance — generated columns are cheaper than triggers.VACUUM/REINDEX hygiene; this is an operational task, not a code task.Failure modes to plan for.
tsquery / query injection causing errors or unexpected matches — mitigate with plainto_tsquery/websearch_to_tsquery, parameter binding, and sanitization tests.pg_stat_user_indexes, set work_mem per-query where warranted, document REINDEX cadence.regconfig per column and test each language.Ramp-up.
Portfolio-level bottom line: Score 0.24 with 0 stars and 0 dependents is a do-not-adopt signal, compounded by the Symfony2/Doctrine2 target and an EOL framework. The TPM's leverage here is to reject the artifact, retain the architectural option, and convert the package's documentation into a 1–2 day spike. That preserves the strategic upside — search on the database we already operate, with no new vendor and no new on-call surface — while avoiding an unmaintained dependency. Set a measurable migration trigger (p95 search latency, zero-result rate, or a paid search-experience requirement) so that any future move to Meilisearch/Typesense/OpenSearch is justified by evidence rather than by preference.
How can I help you explore Laravel packages today?