Product Decisions This Supports
- Whether to ship customer-defined "custom fields" at all. The package is a compact reference implementation of the attribute/EAV pattern: a side table of key–value pairs attached to any Doctrine entity, hydrated onto the parent object via a Doctrine event listener, plus a form type for editing. That is exactly the shape of the decision "do we let admins add fields we didn't design?" — and reading ~a day of this code lets you price that feature honestly instead of guessing.
- Build vs. buy vs. borrow for metadata. Three options usually surface: (a) build a bespoke attribute subsystem, (b) buy/borrow a maintained library, (c) adopt a managed custom-fields/search service. This package represents the cheapest version of (b) — a pattern to copy rather than a dependency to inherit — which is a legitimate third path in the build/buy memo.
- Roadmap sequencing for flexible data. It supports deferring a heavyweight schema-evolution programme by showing what "good enough" generic attributes cost: a join, no typed columns, no indexes on values, and filtering/sorting that degrades quickly. That is the input to "ship attributes in v1, revisit when a customer asks to sort by a custom field."
- Extending entities you don't own. Bundles and third-party models (vendor user tables, imported catalogues) can't be migrated freely. An attribute side table is the standard escape hatch, and this code demonstrates the polymorphic link (entity class + id) needed to do it without touching vendor schemas.
- Prototype vs. production gating. Use it to prototype an admin-configurable attribute UI in a spike; the artefact of that spike is a requirements list (typed values, validation, search, audit history) that the production build must satisfy — requirements nobody writes down when the feature is purely abstract.
When to Consider This Package
Consider it when all of the following hold:
- You are on Symfony with Doctrine ORM — this is a Symfony bundle, not a Laravel package. The brief's framing is wrong; there is no service provider, no Eloquent, no Laravel integration. On Laravel the only usable asset is the idea.
- You are on a legacy Symfony 2.x/3.x-era stack (or a fork you control) where
composer require of a 2015 bundle is not a compatibility experiment.
- Your need is modest: a handful of attributes per entity, read-mostly, no hard requirement to filter, sort, or aggregate on attribute values at scale.
- You are willing to vendor or fork the code. With 24 stars, no dependents, and a last release of 2015-07-16, treat it as sample code with an MIT licence, not a maintained dependency. Budget the fork explicitly, including PHP 8 and Doctrine 3 upgrades.
Look elsewhere — usually at a JSON/jsonb column, or a maintained EAV/custom-fields library, or a managed service — when:
- The stack is Laravel or modern Symfony (5/6/7); the listener and mapping APIs it relies on have moved substantially.
- You need to query, filter, sort, or report on attribute values; EAV value tables without indexes and typed columns turn into a performance cliff and a product promise you can't keep.
- You need typed values, validation, i18n, or per-tenant isolation; the package gives you strings and a form type, and little else.
- You need audit history or compliance guarantees on attribute changes. There is no change log here.
- You need a security patch path. A single-maintainer, decade-dormant repo is a standing "no fix will arrive" risk; if accepted, it must be accepted consciously and documented.
- Your write volume is high. Multi-row attribute writes per save are a known throughput tax; this pattern is fine for admin-edited records, poor for high-churn event data.
How to Pitch It (Stakeholders)
To executives — one paragraph. This is a small, MIT-licensed piece of sample code that shows how to let customers add their own fields to records without us running a database migration for every request. It is not something we should install: it was last released in 2015 and has no downstream users, so there is no support or security-update path, and it does not work on our current framework. The value is decision support, not a dependency. It lets us price the "custom fields" feature — roughly a week of engineering to imitate the pattern well, versus the multi-quarter cost of a bespoke metadata platform — and gives us a concrete list of what a production version must add: typed values, validation, search, and an audit trail. Recommendation: treat it as a design reference during discovery; do not add it to the dependency manifest.
To engineering — the ask. Spend half a day reading the attribute entity, the Doctrine listener that hydrates attributes onto the parent, and the form type. Then tell me three things: (1) what a clean-room equivalent costs in our stack — most likely a JSON column with generated indexes rather than an EAV table; (2) which of the four production gaps (typing, validation, query/sort, audit) is the expensive one for us; and (3) whether the vendor-the-bundle option is ever preferable to the JSON column. I expect the answer to be "copy the pattern, skip the dependency," and I want that in writing so the build-vs-buy decision is documented rather than assumed. Flag the framework mismatch explicitly in any write-up so nobody downstream treats this as a Laravel-compatible evaluation.