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 Belongs To Dependency Laravel Package

webparking/nova-belongs-to-dependency

A Laravel Nova package that makes BelongsTo fields depend on other form fields, enabling cascading or filtered selects. Choose a parent value and the related BelongsTo options update accordingly, keeping Nova forms dynamic and consistent.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

What is being bought. webparking/nova-belongs-to-dependency is a single-purpose Laravel Nova field that turns a native BelongsTo into a dependent select: the child field's option list is narrowed by the current value of a sibling field on the same form. It replaces the custom Vue field a team would otherwise write for Country → Region → City, Client → Project → Task, Category → Subcategory. That is the entire value proposition — there is no reporting layer, no workflow engine, no multi-tenant option plumbing.

Architecture fit. The fit is good where the requirement is narrow and the stack is standard:

  • Fits: Nova 4/5 resources, plain Eloquent belongsTo chains, back-office create/update forms, two-level cascades (roughly 90% of real usage) and simple three-level chains.
  • Does not fit: BelongsToMany, MorphTo, non-Eloquent option sources, custom search endpoints, or heavy multi-tenant scoping. Those should be scoped as custom work — the package cannot be bent into them.
  • Composition is additive: the dependency filter stacks on top of the resource's own relationship definition, so existing relatable() / relatableQueryUsing() constraints and Nova's searchable() behavior keep working. This matters for a TPM because it means adoption is a field-level change, not an architectural one. No service layer, no schema, no API contract changes.

Integration feasibility. Low effort. Public API is effectively one make() plus one dependency method (->dependsOn('country')). A competent Laravel developer integrates a two-level cascade in hours, not days. The real cost is not writing the field — it is the surrounding discipline: declaration order, validation mirroring, modal field sets, asset cache clearing, and post-deploy verification. Budget roughly 1–2 developer days for the first cascade including tests and a deployment runbook, and materially less per additional cascade once the convention is established.

Technical risk. Manageable but real, and concentrated in two places:

  1. Dependency argument semantics. The argument is the field attribute key as declared in fields(), not the foreign-key column. ->dependsOn('country') pairs with BelongsTo::make('Country', 'country', ...). A mismatch produces a silently empty dropdown — no error, no alert. This is the single most likely first-integration stumble and it is a configuration error, not a package bug.
  2. Data integrity is not provided by the UI. The package restricts what can be picked; it does not enforce the relationship server-side. Every cascade needs a paired Rule::exists('states','id')->where('country_id', $this->country?->country_id). Without it, a crafted request or stale form post persists an invalid pairing. If this is not in the acceptance criteria, the feature ships as a UX nicety rather than a control.

Secondary risks: the field reads sibling form state, so it misbehaves anywhere the parent is absent (action modals that list only the child field, parents hidden via onlyOnDetail() or placed in a different grouping). Stale compiled assets are the dominant deployment failure mode — "component not resolving" is almost always cache, not code.

Key questions to resolve before committing:

  • Is the requirement limited to plain Eloquent belongsTo cascades on internal admin screens, or does anything in scope need BelongsToMany/MorphTo/custom sources? If the latter, this is not the package for that requirement.
  • Who is the named internal owner? With a Feb 2023 last release, 11 stars, zero dependents, and a thin contributor base, there is no vendor SLA. Ownership is a precondition, not a nice-to-have.
  • Does 2.0.1 (component-loading fix) actually resolve whatever workaround, if any, we would otherwise apply? Treat ^2.0.1 as the floor, not a feature upgrade — nothing in the field API changed.
  • Is this on a customer-facing surface or an SLA-bearing workflow? If yes, either descope or document the fallback (plain BelongsTo plus manual/validated entry) and the switch procedure.
  • Which Nova major are we on, and what is our Nova upgrade cadence? Longevity risk is a Nova upgrade risk, and it needs to sit on that checklist explicitly.

Integration Approach

Stack fit and compatibility gates. Confirm Nova 4/5, current Laravel and PHP versions, and that any prior install of this package is either absent or upgraded. Pin webparking/nova-belongs-to-dependency:^2.0.1 in composer.json and verify the constraint landed. 2.0.0 carries the component-registration defect and surfaces as blank index/detail columns and Failed to resolve component console warnings — do not accept a build on 2.0.0, and remove any local workaround that manually registered the component or forced ->component(...) before trusting the fix.

Migration path. Adoption is additive and reversible, which is why it is a low-risk sequencing choice:

  • The change is confined to fields() on the affected resources. No schema, no data migration, no route or policy changes.
  • Rollback is a revert of the field declaration. Because the persisted data model is unchanged, reverting costs a deploy, not a data remediation.
  • Normal install typically needs no publishing; the service provider registers compiled assets via Nova::script() / Nova::style(). If anyone previously ran vendor:publish for this package, delete the stale published copies so the provider's registration is authoritative.

Sequencing recommendation:

  1. Spike (half day). One two-level cascade on a low-traffic internal resource. Verify create, update, index, detail, and one action modal. Confirm 2.0.1 renders in index/detail without ->onlyOnForms().
  2. Establish the convention. Parent field declared before the child; dependency argument named identically to the relationship key; a short comment above the cascade explaining the pairing. Write the deploy runbook (see Operational Impact). This is the artefact that makes cascades 2..N cheap.
  3. Harden the pattern. Add the mirrored Rule::exists(...)->where(parent_fk, ...) validation and a Nova feature test for create/update asserting both valid and invalid pairings. Decide nullable explicitly on every child, since partial saves and "clear the parent" flows will hit it.
  4. Roll out resource by resource, cascades adjacent in fields(), largest child tables first with ->searchable() + relatableQueryUsing() so the dropdown is server-side search rather than a giant option list.
  5. Three-level chains last, only where the requirement is confirmed. Test the middle level changing — the grandchild should clear or reload. If it doesn't, that is a fork-or-raise decision, not something to work around in the resource.

Where to look first, in order. README usage block (effectively the whole public API — a minute's skim eliminates rework on the method signature) → src/BelongsToDependency.php (which sibling attribute it reads, how it composes the options query; this is the file forked if customization is ever needed) → the service provider (Nova::script()/Nova::style()) → the three Vue components (one read-through explains every "why is it empty in a modal" question).

Extension stance. Customize by subclassing BelongsToDependency and overriding option-query building, then registering the subclass in fields(). Do not patch vendor code — that forecloses the upgrade path on a package whose maintenance cadence is already the primary risk.

Operational Impact

Maintenance and support. This is the dominant total-cost-of-ownership item, not the integration. Last release 2023-02-15, 11 stars, 0 dependents, small contributor base, MIT licensed, no vendor SLA. Nova major releases will likely outpace package maintenance. Mitigations that must be in place before rollout:

  • Named internal owner accountable for the dependency, with the package on the Nova-major-upgrade checklist.
  • Pinned constraint (^2.0.1) and no floating versions; re-validate index, detail, form, and modal rendering on every Nova upgrade.
  • Fork-or-replace fallback on the roadmap. The code surface is small — one field class plus one dependency method plus three Vue components. A fork is a realistic afternoon, not a quarter. For a TPM this changes the risk class from "vendor dependency" to "contained dependency," but only if the fork path is documented rather than assumed.
  • Scope discipline: non-customer-facing admin surfaces. Anything with an SLA needs a documented manual fallback and a switch procedure.

Failure modes and how they surface. Triage quality depends on knowing these up front:

Symptom Most likely cause First move
Blank index/detail columns, Failed to resolve component Stale assets, or build on 2.0.0 view:clear, config:clear, restart Octane/FrankenPHP, hard refresh; confirm ^2.0.1
Child dropdown silently empty Wrong dependency argument (column vs. field attribute), or parent declared after child Compare dependsOn(...) against the parent's make() second argument and field order
Create works, edit empty Parent attribute wrong, or parent not in the current field set Check parent presence in fields(); inspect the child's lookup request payload
Empty/full list inside an action modal Parent field not in the modal's field set Include the parent, use Action::standalone(), or precompute in PHP
Previously selected value renders empty / drops on save Global scope or soft delete on the child withTrashed() / relax scopes inside relatableQueryUsing()
Invalid pairing persisted UI restriction with no server-side rule Add Rule::exists(...)->where(parent_fk, ...)

The general debugging heuristic worth writing into the runbook: watch the network tab for the child field's option request and compare the parent value it carries. That splits the problem in one step — "parent state never sent" (form/order/scope) versus "query returned wrong rows" (resource or relatableQueryUsing).

Scaling. Package runtime overhead is negligible; the scaling variable is option list size. A child table with tens of thousands of rows is a bad dropdown regardless of package. Standard posture: ->searchable() on the child, an index on the foreign key being filtered, and relatableQueryUsing() to constrain the candidate set. Because the dependency filter composes with the resource's relationship definition, this is configuration, not a package limitation.

Ramp-up. Low. A developer already fluent in Nova resources needs the README plus one read of the field class — call it half a day to first working cascade, including the gotcha list. The knowledge that actually matters is the operational envelope: dependency argument semantics, declaration order, the validation mirror, modal field sets, and the deploy cache sequence. Put those five items in the team's Nova conventions doc rather than leaving them in the package source; the next developer will not read it.

Verification and release hygiene. Feature-test the Nova API for create and update asserting both valid and invalid pairings. The reload itself is client-side and will not be exercised by HTTP tests — cover it with Dusk or a short manual QA checklist (create, update, index, detail, one modal). Add a smoke check post-deploy: a page that renders the form with no browser console errors is the cheapest regression signal available after any asset-touching change.

Recommendation. Adopt, conditionally: pinned at ^2.0.1, scoped to internal admin cascades over standard Eloquent belongsTo, with a named owner, mirrored server-side validation, a documented deploy cache sequence, and a documented fork/fallback path. Do not adopt for business-critical admin workflows or any requirement involving BelongsToMany, MorphTo, or non-Eloquent option sources without separately scoped custom work.

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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
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