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

Nova Attach Many Laravel Package

dillingham/nova-attach-many

A Laravel Nova field for attaching many related models to a BelongsToMany relationship in one modal. Search, paginate, and create records inline, then attach or detach them without leaving the form. Includes customizable display, authorization, and pivot support.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. The package is a Nova field extension, not a platform component. It plugs into Nova's field pipeline, ships its own Vue assets, and requires no service-provider registration or infrastructure change. Architecturally it is thin: attach/detach semantics are delegated to Eloquent's BelongsToMany and to Nova's relationship authorization, so the package adds presentation (a searchable modal, live attach count, one-click detach) rather than new domain behavior. That is a good fit for an admin panel that already has many-to-many relations modeled correctly, and a poor fit for anything that needs pivot payloads, ordering, validation, or approval state — those belong to the native BelongsToMany field or a dedicated pivot resource.

The hard architectural constraint is scope: the string passed to AttachMany::make() must resolve to a BelongsToMany. HasMany/MorphMany will render nothing useful. This makes adoption a per-relationship decision, which is fine, but it means the field cannot become a blanket replacement for relationship UI.

Integration feasibility. High, with conditions. The documented path is ~ten minutes from composer require dillingham/nova-attach-many:^2.0 to a working detail screen: publish Nova assets, clear caches, add the field, ensure the related resource has a non-empty $title and a $searchable list, and confirm the parent policy exposes attachAny<Relationship>/attach<Relationship> plus viewAny on the related resource. Every one of those is a prerequisite, and every one fails silently — an empty modal is far more often a policy or $searchable gap than a package bug. Feasibility therefore depends less on the library and more on whether the team's Nova resources and policies are already in good shape.

Technical risk. Three risks, ranked by blast radius:

  1. Maintenance and compatibility risk (highest). Single maintainer, MIT, no SLA, one release (2022-07-25) after a multi-year gap, zero dependents. The 1.x → 2.x jump was a Nova 4 / Vue 3 asset-pipeline rewrite, not an additive change. Future Nova majors can break this field with no upstream commitment to fix it. The expected symptom is a blank or non-functional field on a production admin screen.
  2. Correctness risk on the write path. Two specific hazards: an AttachMany field left in a create/update form participates in relationship syncing on save, and an untouched field may clear existing pivots — this must be verified against the 2.0.0 source before it ships anywhere but the detail view. Separately, there is no uniqueness enforcement in the UI, so repeated attach/detach cycles and concurrent editors can accrete duplicate pivot rows that corrupt counts and later sync() assumptions.
  3. Governance risk. Detach is immediate and has no undo, and the package emits no audit trail. For meaningful relationships (roles, entitlements, segments) that is a policy decision the team must own explicitly, via help text and external activity logging.

Key questions to resolve before committing:

  • Which Nova major is in production, and is the Nova 3 → 4 upgrade complete or in flight? (2.0.0 applies only to Nova 4.)
  • Will the field live on detail views only, or in create/update forms? If forms, has pivot clobbering been tested?
  • Does any target workflow need pivot columns, ordering, validation, approvals, granular permissions, or tenant isolation? If yes, this is the wrong tool.
  • Do all target pivots have a unique index on the two foreign keys today?
  • What is the realistic bulk-attach ceiling, and is selection size validated?
  • Who is the named fork owner, and at what adoption breadth does that become mandatory?
  • What is the documented fallback (swap back to BelongsToMany::make()) and how cheap is it to execute?

Integration Approach

Stack fit. Laravel + Nova 4 + Composer, with assets flowing through Nova's publish step. No new services, no queues, no external dependencies, no schema changes required by the package itself. The only deploy-pipeline addition is php artisan nova:publish (plus optimize:clear), which should already exist for any Nova deployment and is the first thing to check when the field renders blank.

Migration path. Progressive, per-resource, and reversible in one line. Do not rip out BelongsToMany::make() everywhere at once. Keep the native field wherever pivot columns or per-row pivot UI are needed; swap in AttachMany only for the "attach/detach existing records, nothing else" case. This gives a side-by-side comparison on real data and a rollback that is a pin revert plus asset republish — no data operation, which is what keeps the whole bet low-risk.

Compatibility. Pin the major, never float: ^2.0 for Nova 4, frozen ^1.0 for Nova 3. Exclude the package from unattended composer update and treat any Nova major bump as its own ticket with a regression pass on every resource using the field. Record the validated Nova minor in the dependency inventory so the pairing is auditable rather than tribal knowledge.

Sequencing.

  1. Confirm Nova 4 in production and confirm the Nova 3 → 4 migration is done or explicitly bundled — do not stack two migrations.
  2. Pin ^2.0, install on staging, publish assets, clear caches.
  3. Build a shared builder/trait (attachMany($relationship, $resource, $query)) that standardizes ->resource(), ->title(), and tenant scoping in one place. This is the cheapest way to realize the package's actual benefit — panel-wide consistency — and it makes scoping auditable.
  4. Pilot on one representative resource, ->onlyOnDetail(), with production-scale data.
  5. Add the pivot unique index before editors touch it.
  6. Write tests against the write path: assertDatabaseHas/assertDatabaseMissing on the pivot table, plus a negative test proving a user without policy rights attaches nothing. Do not test the Vue component.
  7. Post-deploy smoke check: modal lists options, typing filters, attach writes a row, detach removes it, unauthorized user sees nothing.
  8. Roll out resource by resource; name a fork owner before adoption spreads beyond one or two resources.

Operational Impact

Maintenance. Budget roughly one day per quarter plus a defined block on every Nova upgrade. This is a tactical admin accelerator, not a platform dependency, and should be tiered accordingly in the dependency inventory. The absence of a release cadence since 2022-07-25 means the team, not upstream, absorbs compatibility work.

Support. The dominant support cost is misdiagnosis, not breakage. Silent failures — empty modal, non-filtering search, no-op save — present as package bugs and are almost always relationship-shape, $title/$searchable, or policy gaps. Publish a short triage runbook in that exact order (relationship returns BelongsToMany → related resource resolvable → non-empty title → $searchable defined → attachAny<Relationship> allowed → check the search request in the network tab). Standardizing through the shared builder reduces both training load and support surface; per-resource drift reintroduces it.

Scaling. ->query() runs server-side and is the primary lever: keep the candidate set small and scoped rather than relying on client-side filtering. Pair it with a real $searchable list and a database index on the title column. Bulk attach is N inserts with no built-in cap, so validate selection size via Nova relationship validation, keep bulk operations to a sane ceiling, and wrap scripted attaches in DB::transaction() to bound lock contention. The pivot unique index is a scaling prerequisite, not a nicety — duplicates break counts and downstream sync().

Failure modes, ranked by damage:

  • Form-submit clobbering of existing pivots — highest damage, silent, only mitigated by defaulting to ->onlyOnDetail() until the fill/resolve behavior is verified.
  • Asset breakage after a Nova upgrade — blank field on a production admin screen; mitigated by a post-deploy smoke check on one representative resource and a documented one-line fallback.
  • Duplicate pivot rows — accretes quietly, corrupts counts; mitigated by a schema-level unique index.
  • Authorization no-ops — missing policy methods yield an empty modal or a save that does nothing; caught by the negative test.
  • Unaudited detach — irreversible operator action with no trail; mitigated by help() text and external activity logging.
  • Index-view noise — a non-sortable stub in the resource index; mitigated with ->onlyOnDetail() or ->hideFromIndex().

Ramp-up. Ten minutes to a first working detail screen; roughly a day for a mid-level developer to be genuinely productive, because the real learning is Nova policy and relationship literacy, not the field's fluent API. The shared builder is what converts that one-day ramp into a repeatable pattern across the panel — and what makes the eventual fork-or-replace decision a contained piece of work rather than an archaeology project.

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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource