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 Column Filter Laravel Package

philperusse/nova-column-filter

philperusse/nova-column-filter adds configurable column filters to Laravel Nova resource index tables, letting users narrow records by specific fields directly from the Nova UI for faster, more focused browsing.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit

  • The package is a thin extension of Laravel Nova's filter contract: a ColumnFilter subclass that exposes a developer-defined columns() allowlist and an apply() that maps a user-chosen column/operator/value onto a WHERE clause on the Nova index query. No service provider of consequence, no migrations, no model coupling. It is a presentation-layer convenience at the far edge of the system.
  • From a TPM frame, that is the entire value proposition: the blast radius of adoption or removal is one dropdown on an internal admin screen. It touches no customer-facing traffic, queues, auth, or persistence beyond the generated predicate. That makes it cheap to trial — and also too small to justify a dependency-governance program of its own.
  • The architectural decision it genuinely informs is scope discipline: whether Nova stays an admin surface or starts absorbing ad-hoc reporting. A generic column queryer is the thin end of that wedge. Saved views, compound filters, and exports belong in a purpose-built surface (Retool, Metabase, an internal dashboard), not in Nova filters.
  • The functional core is plausibly ~150 lines of PHP plus a compiled JS asset. That size is the decisive fact: a thing this small should be owned outright rather than depended upon. Treat the repo as a reference implementation and a spec, not a package to install.

Integration feasibility

  • Feasibility is decided almost entirely by version alignment. Last release 2019-02-25 places it in the Nova 1.x/2.x, Laravel 5.7–6, PHP 7.2–7.4 window. Nova 3 (2020), 4 (2022), and 5 (2024) changed filter metadata, asset registration, and frontend tooling. Assume breakage until a spike proves otherwise.
  • The cheapest possible disqualifier is a composer.json constraint check against our pinned laravel/nova, illuminate/*, and php. A conflict is an instant, near-zero-cost "no" and should be run before anyone reads the source.
  • Even with constraints relaxed, the apply(Request $request, $query, $value) signature is broadly stable across Nova 2–4, but filter metadata and asset registration are not. The filter can install cleanly server-side and silently never render — the highest-time-waste failure mode in a spike, because it presents as a misconfiguration rather than an incompatibility.
  • Positive signal in the negative: MIT license, tiny surface, zero transitive dependencies to audit, zero dependents to inherit. Fork or port cost is low and there is no supply chain to take on.

Technical risk

  • Abandonment (high, dominant). Six years without a release, single maintainer, no issue triage, no security feed. Every future Nova or PHP major becomes unplanned work we own. This is a bookable cost, not a surprise — it must be a named line item with an owner, not an assumption.
  • Compatibility (high). Nova is closed-source and paid; breakage cannot be reasoned about by inspection, only tested empirically against our exact build. "It should work" is unverifiable here.
  • Correctness and data exposure (medium likelihood, highest severity). If the column and operator sets are developer-defined constants, the surface is small. If any fragment derives from user input, this is SQL injection and cross-tenant disclosure inside the admin panel — a hard stop, not a fork-and-fix. Hand-built predicates can also bypass global scopes and soft deletes; that requires an explicit test, not a code read.
  • Silent failure (medium). Filters that fail to publish or register typically just do not appear. Users assume the capability is missing, work around it, and the investment regresses with no error to alert on.
  • Low reward relative to risk. The delivered value is a generic "column + operator + value" control. Most users need three or four curated, index-aware named filters — cheaper to build and more consistent in the answers they produce.

Key questions

  1. Which Nova major and Laravel/PHP versions are in production, and does the package's composer.json permit them? (Cheapest disqualifier — check first.)
  2. What is the concrete filter question, and is it recurring enough to warrant engineering effort at all, versus a saved named filter shipped once?
  3. Is the column/operator set developer-defined and static, or can a user influence the expression? (Hard stop if the latter.)
  4. Does it ship a compiled JS asset requiring nova:publish, and does that survive our deploy pipeline and current Nova tooling?
  5. Does the generated predicate respect global scopes, soft deletes, multi-tenancy, and Nova lenses? Who signs off on the test?
  6. What does the generated SQL cost on our largest resource table — does it scan?
  7. Are we prepared to fork into our own namespace with a named owner and a review trigger at the next Nova major? MIT permits it; the question is budget and accountability.

Integration Approach

Stack fit

  • Appropriate only for a Laravel + Nova monolith where Nova is already the internal admin surface and the team accepts ownership of the filter code. Not appropriate for customer-facing APIs, multi-tenant query layers, or as a substitute for reporting infrastructure.
  • Integration surface is one use in a resource's filters() method plus a columns() map. No model, migration, or policy changes. That minimal surface is the appeal — and precisely why adoption is the wrong frame: anything that small is cheaper to own than to depend on.

Migration path

  • Recommended — port the pattern. Reimplement the filter class (column select, operator, value, apply()) in app/Nova/Filters, retain MIT attribution in a header comment, and add no Composer entry. This keeps us on current Nova contracts and lets us restrict the allowlist to indexed, safe columns. Estimate under one engineering day for a developer fluent in Nova and Eloquent.
  • Fallback — fork and vendor. Copy the repo into an internal namespace, relax constraints to our stack, ship via path/private VCS, and treat it as first-party code with a runbook owner. Preserve the MIT notice.
  • Do not add the upstream package to composer.json as a routine dependency. With no maintainer, no dependents, and no release cadence, we would inherit a fork we neither wrote nor chose.
  • State the alternative explicitly: stock Nova filters plus a curated set of named, index-aware filters. Lower capability, zero third-party risk, better UX for the majority. Prefer this unless arbitrary column querying is a hard requirement.
  • Fallback to the fallback — the one-day spike. Install against the exact production stack, publish assets, and render one filter. Exit criteria: it installs, it renders, the generated SQL respects scopes and soft deletes, the column list is static, and query time on the largest resource table is acceptable. Any failure on the last three is a "no," not a "fix it later."

Compatibility

  • Pin the target matrix before any work: Nova major, Laravel minor, PHP version. The 2019 asset pipeline is the likeliest break — Nova 4 moved to Vite-era builds, and 2019-era compiled assets may not load under current tooling.
  • Budget for the frontend half of the spike separately from the PHP half; they fail independently, and the asset failure is the quieter of the two.
  • Any fork inherits this problem permanently. A port does not: writing the filter against the current Nova filter contract means the next major upgrade is our normal work, not archaeology on someone else's build config.

Sequencing

  1. Composer constraint check against the production matrix. Minutes. Kill early if it conflicts.
  2. Confirm the requirement: is the ask "arbitrary column querying" or "answer these four recurring questions quickly"? If the latter, ship curated named filters and close this out.
  3. If the former, run the one-day spike in a non-production branch against the exact stack, including asset publish.
  4. Decide port vs. fork vs. drop based on spike exit criteria — not on the README's claims.
  5. If proceeding, ship under app/Nova/Filters with an allowlist restricted to indexed, low-cardinality, developer-defined columns; add tests covering scopes, soft deletes, and tenant boundaries.
  6. Record the decision in the risk register with a revisit trigger at the next Nova major.

Operational Impact

Maintenance

  • The package itself has no maintenance cadence to rely on: no release since 2019-02-25, single maintainer, no dependents, no security feed. Adopting it is a decision to own unmaintained code, and that ownership must be assigned to a named engineer or team before install — not after the first breakage.
  • A port is roughly 150 lines we wrote and understand; a fork is roughly 150 lines we inherited and must reverse-engineer at the next Nova upgrade. The maintenance delta between the two is the strongest argument for porting.
  • Revisit trigger should be explicit: the next Nova major, or the next PHP/Laravel LTS bump, whichever comes first.

Support

  • Users will not file tickets saying "the filter silently failed to render." They will report that they "can't filter by column anymore," which is indistinguishable from a permissions or caching issue at first triage. Document the expected behavior on the resource so support has a baseline.
  • Internal-only blast radius is the saving grace: no customer-facing SLA is implicated, and removal is a one-line revert in a filters() method.
  • Escalation path is the owning team, not upstream. Assume the upstream issue tracker is inert.

Scaling

  • Generic column querying invites unindexed WHERE clauses, LIKE '%…%' scans, and correlated subqueries on the largest resource tables. The filter's cost is bounded by whichever column a user picks, not by the filter's own footprint — so the worst case is chosen by the least-informed user.
  • Mitigate by restricting the allowlist to indexed, low-cardinality columns (status, owner, type, boolean flags) and by measuring query time on the largest resource table during the spike. Do not expose free-text columns on large tables.
  • If filtering demand grows into slicing, saved views, compounding, or exports, that is a signal to move the workload to a read replica or a BI surface — not to extend the Nova filter.

Failure modes

  • Silent non-rendering after a Nova or asset-pipeline upgrade: filter installs, never appears, users quietly work around it. Test rendering explicitly; do not assume.
  • Scope leakage: a hand-built predicate that ignores global scopes, soft deletes, or tenant constraints exposes records the user should not see. Test, don't read.
  • Injection / expression exposure: if the column or operator can be influenced by user input, treat as a security incident class, not a bug. Static allowlist is the control.
  • Query degradation: an unindexed column on a large table turns an admin convenience into a page-timeout source. Bound it with an allowlist and a query-time check.
  • Fork drift: a vendored copy quietly diverges from upstream (which is inert anyway) and from our Nova version, with no upgrade path. Named owner and review trigger are the mitigation.

Ramp-up

  • A Nova-fluent developer can read, understand, and port the functional core in under a day. There is no meaningful learning curve and no specialist knowledge required — which is itself the argument against taking on a dependency.
  • Stakeholder ramp-up is faster than engineering ramp-up: show one working filter against a real resource and the product conversation ("do we want self-serve querying or curated answers?") becomes concrete in a single demo.
  • Frame the recommendation to leadership as: "Buy the concept, build the filter." The package earns its place as a prototype and a spec; it does not earn a line in composer.json.
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.
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
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