blendbyte/nova-attach-many
blendbyte/nova-attach-many provides a Laravel Nova field for managing many-to-many relationships: search and select multiple related records from a modal, attach or detach them, and keep resource forms clean and efficient. Ideal for BelongsToMany fields in Nova.
Architecture fit. blendbyte/nova-attach-many is a single Nova field that resolves a belongsToMany relationship and renders a searchable attach/detach surface inside a standard Nova resource form. It fits cleanly into the architecture most Nova admin panels already have: relationship declared on the Eloquent model, policy on the related resource, validation on the related resource's searchable()/searchableColumns() query. It does not introduce a service layer, a queue, or a new persistence model — it writes pivot rows. That is a small architectural footprint, which is the main reason a TPM can justify it: the integration surface is one field class plus the policy and search configuration you already own.
The important architectural boundary for product planning: this is relationship management, not pivot editing. It creates the pivot row; it does not expose pivot columns. Anything where an operator must set a role, quantity, date, or approval state on the pivot is out of scope and should route to a dedicated pivot resource or a Nova action. Deciding that boundary up front determines whether this is a half-day wiring job or a mismatched tool.
Integration feasibility. High, with caveats. Composer install, Nova auto-discovers the field, and the resource change is one line (AttachMany::make('Users')). The realistic effort is not the install — it is (a) confirming the fork namespace (Blendbyte\NovaAttachMany\AttachMany, not the upstream Dillingham\...) and the fluent API against src/AttachMany.php on the exact installed version, and (b) defining and testing the policy and search-scoping rules. Method names like showCounts() and showPreview() are inherited upstream conventions, not fork guarantees — verify before committing them to a design doc.
Technical risk. The risk profile is dominated by adoption concentration, not complexity:
BelongsToMany only. HasMany, BelongsTo, and MorphToMany will no-op or fail at runtime, and forks have historically assumed a single pivot table for morph handling. Verify explicitly if polymorphic relations are on the roadmap.showPreview() loads related models and can N+1 on large relationships; showCounts() alone is the safer default at scale.Key questions for the team before adoption.
dillingham package; mixing both causes namespace and asset-publishing collisions.)ActionExecuted layer?Stack fit. Native fit for a Laravel Nova 5 admin panel on Eloquent belongsToMany. Zero infrastructure change, no new datastore, no migration. The package composes with the components you already have rather than adding a parallel one: Nova policies on the related resource gate attach/detach (attachUser/detachUser, or generic attach/detach), validation rules on the related resource constrain eligibility, and the relationship itself — wherePivot, a scoped relation, a global scope — propagates into the field's query. On 2.0.1 a scoped relation composes correctly with the related resource's filter methods; that combination was unreliable on 2.0.0. For product planning, this is the lever that keeps customisation inside code you own.
Migration path. Pin composer require blendbyte/nova-attach-many:^2.0.1 — explicitly not 2.0.0, which carries the filter-resolution bug. If migrating from dillingham/nova-attach-many, this is a continuity move and a namespace change; the fluent API largely carries over but fork drift means reading src/AttachMany.php on the installed version is cheaper than debugging a BadMethodCallException. If coming from hand-rolled attach screens, replace them relationship by relationship rather than in one cut — the failure mode is two competing UIs for the same pivot.
Compatibility decisions to lock in.
^2.0.1, exact. Add a smoke test (Dusk or a feature test hitting the attach endpoint) so a Nova minor bump fails loudly instead of silently.BelongsToMany on the index for quick inline toggling, each scoped with ->onlyOnDetail() / ->onlyOnIndex(). Both can live on one relationship; competing unscoped UIs should not.NovaServiceProvider helper rather than repeating the decision per field. This is a UX consistency call as much as a technical one.showCounts() alone unless showPreview() is justified, plus eager-loading on indexQuery/detailQuery.Sequencing.
AttachMany::make('Members', 'users', User::class)) where labels and relations diverge. Search, apply configured filters, confirm the attach list and counts agree — this is the code path 2.0.1 changed.Where the search UI cannot express the filter, constrain the relationship (wherePivot, scoped relation, global scope) rather than patching the field — keeps the customisation in owned code.
Maintenance. The code is small and MIT, so the practical maintenance question is not "can we fix it" but "who is watching it." At 12 stars and zero dependents, you are effectively the QA department: no upstream test suite you can lean on for your specific relationship shapes, no release-note discipline beyond a changelog. Budget for a periodic version-review ritual (is the fork still tracking Nova?) and a standing assumption that you may inherit the code. Realistically this is a day or two a year of attention, plus the cost of the smoke test — low in absolute terms, but it belongs on someone's name.
Support. No SLA, no security response commitment, no commercial channel. That is acceptable for an internal admin panel and disqualifying for anything customer-facing, audit-critical, or high-volume. The ROI case that does hold: search, validation, and sync notifications measurably reduce "I attached the wrong thing" and "I can't find the record" tickets from internal operators. That support-burden reduction is the most defensible part of the business case, and it should be stated in those terms when this goes to a review.
Scaling. Two axes. Data volume: candidate lists are driven by the related resource's searchable query; showPreview() can N+1 and should give way to showCounts() on large relationships, with eager-loading on the resource queries. Relationship count: each new attach surface is cheap to add but needs its own policy and scoping decision, so cost scales with governance work, not with code. The field does not scale into pivot-attribute editing — the moment a relationship needs operator-set pivot data, offload to a dedicated resource or action rather than stretching this field.
Failure modes to plan for.
searchable() (joins, whereHas, global scopes). Mitigation: diff candidate sets before and after on every scoped relationship; treat Nova and package bumps as behaviour changes until proven otherwise.onlyOnDetail() / onlyOnIndex() scoping.Ramp-up. Deliberately shallow for engineers — the install and first field are near-trivial, and the real learning is in reading src/AttachMany.php on the pinned version (namespace, fluent methods, fork drift from upstream) and in understanding Nova's relatable/query-filter resolution. For a TPM the ramp-up is different: it is the per-relationship governance worksheet — who may attach, what bounds the candidate set, where that rule lives. That worksheet, not the install, is what determines whether operators trust the surface. Budget half a day for the spike, a day for the first governed relationship including tests, and treat everything after that as configuration.
How can I help you explore Laravel packages today?