Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Constrained Morph To For Laravel Laravel Package

pindab0ter/constrained-morph-to-for-laravel

Type-constrained polymorphic relationships for Laravel Eloquent. Extend morphTo to accept only specified model types, ensuring type safety and data integrity while keeping the flexibility of a polymorphic database structure.

View on GitHub
Deep Wiki
Context7

Product Decisions This Supports

Feature decisions: whether a polymorphic relation is intentionally open or deliberately closed. Most teams inherit morphTo() relations that were never scoped — a commentable that "any model can attach to" is rarely a product decision, it's an accident of the schema. This package forces the question into the code review: what may attach here, and who owns that list? That is a product question with a one-line answer in the codebase, which is the cheapest possible form of the decision.

Roadmap: retiring a model type without a flag day. The strongest PM-facing use case is narrowing. If you plan to stop allowing Image attachments in favour of Media, you can shrink the allowlist in one release (disallowed types now resolve to null), observe the fallout, backfill and clean data, then delete the class last. That converts a risky migration into a reversible, staged rollout — provided the null result is acceptable during the window (see caveats).

Build vs buy: buy, but budget to own. Reimplementing this is roughly a MorphTo subclass plus a trait and a test matrix against every Eloquent surface you touch — a week or two of senior engineering time plus perpetual maintenance. At 3 stars and zero dependents the package is not a strategic dependency, so the honest framing is "adopt as vendorable code, not as a vendor." Decision: take it, pin the version, accept that a mid-level engineer may own the diff permanently.

Use cases worth scoping in this quarter:

  • Low-blast-radius read paths — comment targets, attachment owners, reaction subjects, taggables. Wrong-type rows are a data-hygiene annoyance, not an incident.
  • Deprecation narrowing per the above.
  • IDE/static-analysis leverage — generic return annotations (ConstrainedMorphTo<Post|Video, $this>) reduce the "what is this actually?" tax on every engineer who touches the relation. Small, real, compounding.

Decisions this package does not support — do not let it be oversold:

  • It is not a write-side integrity control. The README implies a disallowed type can still be persisted; it just reads back as null. Any stakeholder claim of "this association can never happen" is false unless you ship a validation rule, observer, or check constraint in the same release.
  • It is not appropriate for money, entitlements, permissions, audit subjects, or moderation state. There, null-on-mismatch is indistinguishable from a deleted parent — a silent failure where you need a loud one.

When to Consider This Package

Adopt when most of these hold:

  • Eloquent polymorphic relations exist and are, in practice, narrower than the schema allows.
  • The relation sits on a read path with limited blast radius — losing a relation silently degrades a page, not a payment.
  • You need to narrow or retire a model type and want a staged path off a flag day.
  • The team already uses morph maps. If not, fix that first — constraining to raw class strings just relocates the brittleness to a shorter list.
  • You can pin an exact version and treat upgrades as reviewed changes.
  • A domain team will own the allowlist as reviewed code, not the platform team as infrastructure.

Look elsewhere — or don't adopt — when:

  • The write path is the actual problem. This package doesn't stop bad rows being inserted. If the pain is data integrity at write time, you want validation rules, model observers, or a database check constraint — and the package is at best a complement.
  • The null contract is unacceptable. Entitlements, billing, permissions, audit, moderation: any relation where a missing parent must raise rather than degrade.
  • You need a guarantee, not a filter. This is application-layer code, bypassable by query builder calls or raw SQL. If the requirement is a hard invariant, this doesn't deliver it.
  • The app leans heavily on whereMorphedTo() / orWhereMorphedTo(). The v1.3.1 fix shows that surface was broken in a released version; assume the edges are still being found.
  • Heavy third-party polymorphic interception — activity logging, auditing, media libraries, soft-delete wrappers, search indexers — and you can't verify each one composes cleanly.
  • Laravel 13 is load-bearing in your upgrade plan. The README lists 13.x; resolve whether that's genuinely tested before it anchors a roadmap commitment.

Before a go decision, close these questions: does the constraint filter at query level or post-hydration (this decides the performance profile of with() / whereHas() on mixed-type sets, and whether disallowed rows leak into eager-loaded collections)? What are the semantics of exists(), associate(), dissociate(), touch(), has(), and cascading deletes when the type is disallowed? What is actual test coverage, including morph maps plus mixed-type eager loading?

How to Pitch It (Stakeholders)

To executives — one paragraph: Our database allows any model type to attach to certain shared relations, which was never a deliberate product decision and is now a source of data-hygiene cleanup and, in places, an unquantified risk. This is a small, MIT-licensed, drop-in package that lets us state explicitly which types each relation accepts, with no schema change and no data migration — adoption is one line per relation and reversible by reverting that line. It costs us no licence and roughly a sprint of one engineer's time to adopt safely across a handful of low-risk relations. I recommend adopting it narrowly this quarter to (a) make these allowlists explicit and owned, and (b) give us a staged, reversible path to retiring a model type later. I am explicitly not recommending it for billing, permissions, or audit relations — it filters on read but does not block writes, and a disallowed type resolves to null rather than raising an error, which is the wrong failure mode where correctness is non-negotiable. Because it's a 3-star, single-maintainer package, the plan pins the version and assumes we may own the code ourselves; the diff is small enough that this is a realistic contingency, not a euphemism.

To engineering — the ask:

  • Pin an exact version (1.3.1), not a caret range. This is pre-2.0 and still correcting query-builder edge cases; the whereMorphedTo() column-qualification fix is the kind of patch we take deliberately.
  • Spike in staging on two relations — one single-type, one multi-type — exercising eager loading, whereHas, exists(), soft deletes, and morph-map aliases.
  • Ship the write-side guard in the same release as the first read constraint. Otherwise the claim to the business is "filtered on read," not "rejected on write."
  • Inventory every package that intercepts polymorphic behaviour before rollout, and audit existing whereMorphedTo() usage.
  • Expand relation by relation on low-blast-radius paths (comment, attachment, reaction, tag targets). Never money, entitlements, permissions, or audit subjects.
  • The allowlist is domain-owned code with a named reviewer — not a platform-team config detail.

The one-sentence pitch: A one-line, reversible way to say which models a polymorphic relation may resolve to — worth adopting on low-risk read paths to make implicit rules explicit and unlock staged narrowing, and specifically not a write-side integrity guarantee.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
adachsoft/php-code-style