Product Decisions This Supports
- Domain modeling standards (primitive obsession vs. value objects). This package is infrastructure glue that lets a team persist typed value objects (Money, EmailAddress, UUID, DateRange) directly through Doctrine instead of scattering strings and floats across entities. The PM decision it informs: do we mandate value objects at domain boundaries, and if so, what's the persistence cost?
- Build vs. buy for persistence plumbing. The bundle's actual surface area is small — it registers
yokai/doctrine-value-object DBAL types into the Symfony container so you don't hand-wire doctrine.dbal.types config. That's a "buy" decision worth roughly a few hours of engineering, not an architecture decision. Frame it as a convenience dependency, not a platform commitment.
- Data integrity and migration risk. Custom DBAL types change how columns round-trip to the database. Adopting this is a schema-contract decision: it affects migrations, fixtures, raw SQL reporting, and any consumer reading the DB outside the ORM. That's a roadmap item, not just a composer require.
- API/contract consistency. If value objects are the canonical representation in the domain, they tend to leak into serializers, form types, and API resources. This package makes the persistence half cheap, which shifts the real cost to the serialization/validation layer — useful input when scoping a DDD-flavored refactor.
- Explicitly not a Laravel decision. This is a Symfony bundle; it targets Symfony's DI container and Doctrine bundle configuration. On Laravel/Eloquent it is not usable as-is. If your stack is Laravel, the relevant decision is whether to adopt
yokai/doctrine-value-object directly (or an Eloquent cast equivalent), not this bundle.
When to Consider This Package
Consider it when all of the following hold:
- The service is Symfony with Doctrine ORM/DBAL, and value objects are already a team convention or an agreed near-term direction.
- You want auto-registration of value-object DBAL types and are comfortable inheriting the bundle's config conventions rather than maintaining your own compiler pass or
doctrine.dbal.types block.
- You're comfortable with a very small dependency: 13 stars, 0 dependents, single-maintainer risk, Apache-2.0 (permissive, forkable, so the license is not a blocker).
- The value objects you need are simple single-column mappings; complex composite mappings still need custom DBAL types regardless.
Look elsewhere — or just vendor the ~100 lines — when:
- The stack is Laravel/Eloquent. This is the dominant disqualifier. Use Eloquent custom casts or the underlying library directly.
- You need vendor support, SLAs, or a security-response commitment. Zero dependents means zero external validation of edge cases; you are the first adopter in most failure modes.
- Your team already has a type registry or a DDD base package. Duplicating registration logic creates two sources of truth.
- The domain refactor is speculative. Don't introduce DDD persistence machinery to satisfy an architecture diagram; the migration and reporting costs land whether or not the value objects earn their keep.
- You need a bus-factor above one. Wrap it, fork it, or reimplement it — but don't let it become load-bearing without an owner.
How to Pitch It (Stakeholders)
To executives: This is a small, free, permissively licensed utility that removes boilerplate when a Symfony team stores typed domain values in the database. It is not a strategic bet and it is not a cost line — the risk is maintenance, not money. Because it has essentially no adoption (13 stars, no dependent packages), we should treat it as code we may end up owning: either vendor it, fork it, or absorb it into our own base library. Recommendation: approve as a tactical convenience inside one service, with an explicit owner and an exit plan.
To engineering: It's a thin Symfony bundle over yokai/doctrine-value-object that registers value-object DBAL types into the container. Adopt it only if you're already on Symfony + Doctrine and already sold on value objects; the savings are a config block and a compiler pass. Verify round-tripping, migration generation, and any raw-SQL/reporting paths before merging. If the stack is Laravel, stop — this doesn't apply; use casts. If the maintainer goes quiet, the fork cost is trivial, so the real gate is whether the abstraction matches our domain, not whether the package is popular.