dunglas/doctrine-json-odm
Store PHP objects as JSON documents in PostgreSQL JSONB or MySQL JSON columns alongside traditional Doctrine ORM mappings, enabling schema-less, NoSQL-like hybrid data models with fast querying and indexing.
Architecture fit
json_document, and jsonb_document on DBAL ≥ 4.3) plus a Symfony Serializer-based (de)serializer. Laravel's default persistence layer is Eloquent, which has no DBAL type system and no Unit of Work — so the package cannot be "installed and used" in a normal Laravel app.laravel-doctrine/orm, or (b) is a bounded module where standing up a second EntityManager is acceptable.JsonResource/cast pipeline. Two serialization contracts for the same data is a long-term source of drift.Integration feasibility
AppServiceProvider::boot() registers types behind a Type::hasType() guard, an EntityManager is bound, and mappings use attributes on Doctrine entities.DB::transaction. Every one of those becomes bespoke wiring or a bridge package's opinion. laravel-doctrine/orm is community-maintained and historically lags Doctrine majors — verify DBAL/ORM version support (specifically DBAL ≥ 4.3 for jsonb_document) before committing.Technical risk
UPDATE. This is a data-loss class of bug that is invisible to code review and surfaces in support tickets. Requires a project-wide convention (clone-before-mutate) enforced by review, not by the library.#type field stores the FQCN; renaming or moving a class requires a data migration (the README provides raw JSON_REPLACE recipes). Any refactor touching POPO namespaces becomes a database migration. type_map aliases mitigate this but must be adopted before data volume grows and are a hard-to-retrofit discipline.scienta/doctrine-json-functions) — no Eloquent query builder, no whereJsonContains ergonomics. This shifts query work from typical Laravel developers to whoever knows DQL and Postgres JSON operators.Key questions
type_map alias policy, serialization context, and the migration runbook for class renames?Stack fit
laravel-doctrine/orm, where this is additive; or (2) an isolated module where a dedicated EntityManager is an explicit architectural decision, scoped to documents that are read-mostly or write-once.GIN), containment operators, and the dedicated jsonb_document type on DBAL ≥ 4.3. MySQL 5.7+ is supported but restricted to JSON with generated-column indexing — a degraded experience, not parity.Migration path
type_map aliases from day one — never persist FQCNs. Retrofitting aliases after data exists is the single most expensive correction available here.Compatibility
jsonb_document), Symfony Serializer version compatible with both your Laravel release and the bridge package. Recent releases add Symfony 8 support and a fix for typed object collections on Serializer 8.1 — check your exact matrix.jsonb_document path, so CI needs a Postgres service container.if (!Type::hasType(...))) and assert boot-time validity with a smoke test that persists and reloads a nested graph.Sequencing
type_map alias policy, the document versioning field, and the clone-before-mutate convention documented in the repo's contributing guide.Maintenance
Support
Scaling
Failure modes
type_map adoption; reads throw at denormalization. Mitigation: aliases from day one, plus a CI check that no persisted #type value is an FQCN.Ramp-up
save(), implicit dirty tracking) actively mislead here.TPM recommendation: the capability is legitimate and the Postgres JSONB story is strong, but this is a Doctrine-ecosystem package being evaluated in a Laravel context — the integration cost, not the library quality, is the decision driver. Fund a two-week spike only if the codebase already carries Doctrine or the use case is narrowly scoped and write-light; otherwise the cheaper, lower-risk equivalent is a custom Eloquent cast backed by the same Symfony Serializer, which delivers most of the value with none of the EntityManager, DBAL-type, or class-rename-migration surface.
How can I help you explore Laravel packages today?