garak/doctrine-postgres-types-bundle
Symfony bundle that registers PostgreSQL-specific Doctrine DBAL types, so you can map Postgres arrays, JSONB, and similar column types directly to PHP values in your entities without writing custom type classes.
Architecture fit. The package is a thin Symfony bundle wrapping Doctrine DBAL custom types for PostgreSQL-native column types (jsonb, arrays, hstore, inet/cidr, ranges, ltree, and similar — confirm the exact set against src/). Architecturally this is a low-coupling, narrow-surface dependency: it sits in the persistence layer, contributes a compiler pass and/or doctrine.dbal.types entries, and has no runtime footprint beyond type conversion between PHP values and Postgres wire representations. For a Laravel-first or framework-agnostic codebase it is an obvious non-fit — the bundle's service wiring assumes Symfony's DI container and bundle auto-registration. For a Symfony codebase already on Doctrine ORM, the fit is clean and the blast radius is small.
Integration feasibility. Mechanically trivial: composer require garak/doctrine-postgres-types-bundle, register in config/bundles.php, add type mappings, verify with doctrine:migrations:diff. The real feasibility question is not "can we install it" but "do we need it." Doctrine DBAL has progressively absorbed Postgres coverage (native json, array handling, and per-column mapping via columnDefinition), and the maintained alternative martin-georgiev/postgresql-for-doctrine covers the same gap with active releases and real download volume. Any of the remaining types can be implemented as ~40-line Type subclasses. The bundle's only durable value is the compiler-pass registration convenience.
Technical risk. High, concentrated in three areas:
composer.json constraints against our target PHP (8.3/8.4) and DBAL version. Doctrine DBAL 3 deprecated Type::addType() in favor of doctrine.dbal.types configuration and TypeRegistry work in DBAL 4; a compiler pass written for DBAL 2/3 is a plausible hard break on upgrade. Same question for Symfony 6/7 bundle metadata and services.yaml syntax.Key questions.
martin-georgiev/postgresql-for-doctrine?php, doctrine/dbal, and symfony/* version constraints versus our locked versions?dbal.types config, or both — and is that path forward-compatible with DBAL 4?Stack fit. Viable only for a Symfony + Doctrine ORM + PostgreSQL stack. Not applicable to Laravel/Eloquent despite the prompt framing — the package is Symfony-specific and contributes nothing to Laravel's query builder or Eloquent casting layer. If the question is genuinely "how does a TPM leverage this in a Laravel shop," the honest answer is: don't adopt the package; mine it as a reference implementation for the type-conversion logic and build Laravel-side casts or a small DBAL type set directly.
Migration path. Treat as a trial dependency, not a platform commitment:
jsonb and one with an array column, run doctrine:schema:validate and migrations:diff against a scratch Postgres instance.jsonb and not json or text, since a mapping mismatch here silently changes index and operator behavior.Compatibility. Pin exact versions in composer.json and disable Dependabot auto-merge for this package. If we proceed, fork-and-vendor is the correct posture — an unpinned, unmaintained dependency with a compiler pass that mutates Doctrine's global type registry is not something to float.
Sequencing. Legal/license review in parallel with the technical spike, both before any shared-schema entity lands. Do the spike before the first migration referencing a Postgres-specific type, because retrofitting type mappings onto an existing table means a schema diff that Doctrine will want to express as DROP COLUMN / ADD COLUMN — a data-loss-shaped migration on a live table. If the type is already in production under a generic mapping, plan a controlled ALTER TABLE ... TYPE migration with a backfill verification step, not a migrations:diff autogeneration.
Maintenance. Ownership must be explicit. Unforked, this package has no maintainer; forked, the maintenance burden is roughly "one engineer, a few hours per Doctrine major release." That is acceptable only if we also accept the fork as a real artifact — CI, tagged releases, a documented type inventory. A vendored fork that nobody owns is strictly worse than either adopting the maintained alternative or writing three type classes in-house.
Support. No upstream support channel, no issue triage, no security contact. Internal escalation path is "the engineer who forked it." Document that in the service catalog so it isn't a surprise during an incident.
Scaling. Negligible runtime cost — type conversion is per-row PHP and comparable to native Doctrine hydration. Watch two things: large jsonb payloads are fully materialized in PHP memory on hydration (same as any Doctrine JSON type, but worth knowing before someone stores a 40 MB document), and array types bypass Doctrine's unit-of-work diffing granularity, so a mutation inside a PHP array requires reassigning the whole attribute or the update is silently dropped.
Failure modes.
Unknown column type "jsonb" requested at boot or first query when the type isn't registered — caught in CI if schema validation runs.text/json mapping. This produces schema-diff churn and, worse, round-trip corruption on existing rows.Mitigations: schema validation in CI, a round-trip integration test per type against a real Postgres container, pinned versions, and a pre-approved exit plan (fork, or replace with martin-georgiev/postgresql-for-doctrine, or inline the subclasses).
Ramp-up. Learning the bundle itself is under a day for anyone who knows Doctrine. The actual cost is PostgreSQL type fluency — operators, index support (GIN on jsonb and arrays), and how each type maps to Doctrine's schema tool. Budget that separately; the bundle does not remove it, it only removes the registration boilerplate.
Recommendation. Do not adopt as a strategic dependency. Default to the maintained martin-georgiev/postgresql-for-doctrine or a small in-house type set; use this bundle as a spike/reference only, and only behind a fork we own if a specific unsupported type makes it genuinely worth the carrying cost.
How can I help you explore Laravel packages today?