lendable/tag-bundle
Lendable TagBundle provides Doctrine-backed tagging for Symfony apps. Add a Taggable interface to any entity, then use the included Tag and Tagging entities and manager services to attach, detach, and query tags without building custom tag storage or relationships.
One tagging primitive instead of N bespoke ones. The decision this package actually serves is portfolio-level: when the roadmap contains two or more features that each need lightweight classification — customer segments, document categories, ticket triage, content curation, internal admin labels, saved-view filters — fund a single generic tagging layer rather than letting each squad ship its own join table. Tags are the cheapest substrate for segments, facets, and automation trigger conditions, and retrofitting a shared abstraction after the second and third entity type is far more expensive than starting with one.
Build vs. adopt, framed honestly. There is no product and no vendor here — the choice is between a small conventions-only library and roughly a day of in-house work. Adopt when the stack is Symfony + Doctrine and the team wants standard interfaces (a Taggable interface, a trait, a Tag entity) and a polymorphic mapping without a design debate. Build when the data model needs to diverge: tag hierarchies, tag-level metadata (color, description, owner), permissions, or tenancy isolation. In that case the library's abstraction is the thing worth copying, not the dependency.
Roadmap sequencing — an enabler, not a line item. Integration cost is low enough that this belongs inside a follow-on feature (saved views, facet filters, segmentation) rather than occupying its own roadmap slot. Its value is avoided duplication, not a capability users will notice.
Diligence flag before scoping anything. The brief lists this as a Laravel/PHP package; the repository is a Symfony bundle (Lendable publishes Symfony bundles), and the assessment notes explicitly confirm a Laravel mismatch. If the target stack is Laravel, the correct decision is to adopt the schema concept — a tags table plus a polymorphic pivot (taggable_type, taggable_id, tag_id) exposed through an Eloquent trait — and not the package. Confirm stack fit before this appears in any plan; otherwise you have scoped an integration that cannot happen.
Ownership decision, made deliberately. With zero stars, zero dependents, and no visible release cadence, adoption is really a decision to vendor first-party code. That is defensible for a schema this trivial, but it should be recorded as a staffing commitment, not waved through as "just a Composer require."
Consider it when:
Look elsewhere when:
spatie/laravel-tags or a native Eloquent implementation.One-liner: A small Symfony/Doctrine library that adds a generic "tag anything" layer, so one capability serves many upcoming features instead of each team rebuilding labels for its own domain.
For executives: Low cost and low standalone value — this is an enabler, not a differentiator. The case for it is avoided duplicate engineering across the next two or three features, plus a faster path to segmentation and filtering that customers will eventually ask for. Be clear about what we are not buying: there is no vendor, no support contract, and no adoption base. We would be taking on a small piece of internal code to own. That is manageable at this size, but it should be a conscious decision rather than a side effect of a composer require. Recommendation: conditional approval, scoped to a Symfony service and generic tagging only; otherwise build the thin abstraction in-house and move on.
For engineering: It is a thin abstraction — an interface, a trait, a tag entity, and the Doctrine subscribers that wire them up. Before committing: confirm the repository is a Symfony bundle (it is), verify PHP/Doctrine/Symfony version constraints in composer.json, determine whether the bundle owns schema and migrations or only entity classes, and confirm whether tagging is truly polymorphic. Pin the version and assume you may fork if upstream goes quiet. Index the pivot for both access directions — (taggable_type, taggable_id, tag_id) unique, plus a reverse index on (tag_id, taggable_type) — enforce tag normalization at write time, and handle orphaned pivot rows on entity deletion, since polymorphic joins cannot use foreign keys. A two-day spike behind a feature flag, ending in a build-vs-adopt call, is the right shape. Require the adopt path to clear a concrete bar: current version constraints, documented schema ownership, and a named internal owner.
How can I help you explore Laravel packages today?