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

Custom Relationship Field Laravel Package

digital-creative/custom-relationship-field

A Laravel Nova field for customizable relationship selection. Define how related records are searched and displayed, giving Nova resources flexible relationship inputs that fit naturally into forms while reducing the need for custom field code.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. The critical framing for any planning conversation: this is a Laravel Nova field, not an Eloquent relationship. It emulates HasMany/BelongsToMany in the admin UI only — search, select, attach, reorder — while the actual persistence is an ordinary column (realistically a JSON-cast attribute). That makes it a pure presentation-layer component with no footprint on models, APIs, or the database schema. For an internal, human-curated grouping (featured products, editorial collections, pinned resources) it fits cleanly and removes a migration + pivot + custom-field work package from the critical path. For anything that needs referential integrity, whereHas, eager loading, cascades, or visibility to a consumer outside the admin panel, it is the wrong tool and no amount of configuration fixes that. The fit test is one sentence: does anything other than a Nova screen need to know this relationship exists? If yes, stop.

Integration feasibility. High, with a caveat. The package is essentially one field class plus compiled Nova frontend assets; install is a single composer require, and usage is inline configuration on an existing resource (CustomRelationshipField::make(...)->options(...)). A competent Laravel dev can prove a round-trip on a throwaway resource in roughly half a day. The caveat is that the package reaches into Nova's index-query pipeline — the v1.1.3 release is a buildIndexQuery crash fix for bulk "select all" in a BelongsToMany context — which means it is coupled to Nova internals rather than only Nova's public field API. That single fact drives most of the risk below.

Technical risk. Ranked, because they are not equal:

  1. Single-maintainer dependency with near-zero adoption signal (33 stars, 0 dependents, one visible maintainer, MIT, last release 2024-07-18, low opportunity score). This is not disqualifying for an internal admin widget, but it must be booked as a vendored utility, not a platform dependency. Assume you will patch or fork it yourself on the next Nova major.
  2. Nova upgrade fragility. Because it hooks the index-query path, every Nova minor bump is a potential break in a screen editors use daily. This is a recurring, schedulable cost — not a one-time install risk.
  3. Authorization scoping is your responsibility. Nova policies on the owning resource do not constrain the options query. In a multi-tenant deployment, an unscoped ->options() closure is a live data-leak vector, and it is the kind of thing that reviews miss because the code looks like UI configuration.
  4. No referential integrity. Deleting a referenced record leaves a dangling ID in every JSON column that pointed at it. Soft failure, but it accumulates and it is invisible until someone opens an old record.
  5. Read-path semantics differ from a real relationship. whereIn does not preserve ordering, there is no eager loading, and index views can N+1 if the field resolves per row. Anything that assumes relational behavior — reports, exports, search indexing — breaks quietly.

Key questions to close before committing:

  • Which Nova major/minor are we on, and what is the upgrade cadence? (Confirm against the package's composer.json constraints, not the release date.)
  • Who is the named internal owner of this field, and who forks it when upstream goes quiet?
  • Does curation order matter? If yes, the backing column must encode position, not just IDs, and that decision is much cheaper now than retrofitted.
  • What is the deletion policy for referenced records — cleanup job, soft deletes, or accept dangling IDs?
  • Is multi-tenancy or role-based visibility in play? If so, every options closure needs explicit scoping and review.
  • What is the maximum realistic set size per record, and does anyone need to aggregate or filter by these IDs at scale?
  • What is the explicit trigger condition for promoting this to a real pivot table? If nobody owns that trigger, the workaround becomes permanent by default.

Integration Approach

Stack fit. Laravel + Nova is the only supported shape. No additional infrastructure, no queue, no external service. The only new persistent artifact is a column on the owning table. This is about as low-blast-radius as a feature integration gets — which is precisely why the risk is easy to under-manage: nothing about the deploy looks consequential, so the wrapper, the scoping, and the upgrade test step get skipped.

Migration path. Three scenarios, and the plan differs:

  • Greenfield (recommended). Add the JSON column, cast it to array, configure the field. No data movement, no dual-write window.
  • From an existing pivot table. Backfill IDs into the JSON column, run a dual-write window with the field editable, verify parity against the pivot, then remove the old field — and remove it in the same PR the pivot is dropped. Two sources of truth diverge on the first edit through the other path.
  • To a real pivot table later. This is the exit path and it should be designed now: keep option queries as named model methods and wrap the package field in a project-local class, so the swap touches one file rather than every resource. The UI semantics change (native relation fields behave differently), so budget a short re-pilot, not a configuration flip.

Compatibility. Pin to ^1.1.3 at minimum — earlier versions carry a latent crash on bulk select-all that an editor will eventually hit. Pin the exact Nova version alongside it and treat them as a coupled pair in the lockfile. Verify compiled frontend assets are published during deploy; "renders as a blank box" is nearly always an asset/mix problem rather than PHP. Test select-all on the index view against realistic record counts, because the crash fix moved the question from does it work to what does it cost.

Sequencing (each step is a gate for the next):

  1. Confirm Nova version and that assets publish cleanly in the deploy pipeline.
  2. Pilot on a deliberately low-value resource — internal dashboard or CMS collection, not a customer-facing surface.
  3. Prove the definition of done: search → select → save → reopen → identical set, round-tripping through the model cast.
  4. Introduce the project-local wrapper field class and adopt it in the pilot resource.
  5. Move the options query out of fields() onto the model as a named method, with tenant/role scoping explicit inside it.
  6. Add the orphan-cleanup job (scheduled, idempotent) if deletes of referenced records matter.
  7. Add "bump Nova → open every resource using the wrapper → test select-all" to the release checklist.
  8. Replicate to additional resources one at a time, verifying index browsing, search, sorting, filtering, and select-all on each.

Operational Impact

Maintenance. This is the dominant ongoing cost and it should be stated plainly in any adoption decision. There is no upstream SLA, one visible maintainer, and a release line that went quiet after mid-2024. Upstream issues and PRs may go unread. The realistic operating model is: pin the version, keep the single-file seam, name an internal owner, and assume you patch Nova-major compatibility yourself. Budget it as a fork, not as a subscription you can escalate to.

Support. Self-support with good debuggability — the surface is small enough to read in ten minutes. Two diagnostic patterns cover most incidents: call the options closure from tinker to split "our query is wrong" from "Nova/asset is wrong," and check the browser console before debugging backend code. Worth writing into a short runbook alongside the resource, because the next person to touch it will not be the person who integrated it.

Scaling. The constraint is not traffic, it is set size. There is no pivot table, so every read is an application-side whereIn and every write materializes the full ID set into a JSON column. Select-all over thousands of records will produce a JSON blob the UI struggles to render and your controllers struggle to use — bound the option list (domain filter or a hard limit) so the UI cannot offer a set the storage cannot comfortably hold. Index views are the other scaling edge: a field that resolves per row turns a page render into N queries, so memoize options per request. Set an explicit ceiling (for example, low hundreds of links per record) and a re-evaluation trigger at which you build the pivot, or the ceiling will be discovered by an editor rather than decided by the team.

Failure modes — worth pre-agreeing the response to each:

  • Data leak via unscoped options closure. Severity high, likelihood moderate in multi-tenant setups. Mitigation: explicit tenant/role scoping in every closure, review every ->options() as an authorization boundary, not a UI convenience.
  • Nova minor bump breaks the admin screen. Severity medium, likelihood high over a 12–18 month horizon. Mitigation: the release-checklist test step and a fast-fork capability.
  • Dangling IDs after deletions. Severity low, likelihood certain. Mitigation: scheduled cleanup, or soft deletes on referenced models.
  • Order loss on read. Severity low-to-medium and easy to miss; if curation order is the product feature, whereIn returning arbitrary order is a silent defect. Mitigation: store position and re-sort in PHP, decided at design time.
  • Blank field after deploy. Severity low, likelihood moderate. Mitigation: asset publish verification in the pipeline.
  • Two sources of truth. Severity medium, likelihood low but rising over time. Mitigation: any move to a real pivot removes the custom field in the same PR.

Ramp-up. Small — a developer unfamiliar with the package can read the entire source in one sitting, and the integration recipe is roughly one to two days of work covering the wrapper, the shared options method, tenant scoping, the cleanup job, and a contract comment in the resource stating what backs the field and that no API reads it. That comment is cheap and it is what turns a future migration into planned work rather than an incident. The cost to plan against is not onboarding; it is the recurring per-Nova-upgrade verification and the standing ownership of cleanup, scoping, and the eventual promotion decision.

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.
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle