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

Value Filter Laravel Package

seoegypt/value-filter

A lightweight Laravel package for filtering incoming request values and query parameters. Apply clean, reusable filter rules to validate and sanitize data before it reaches your application logic, keeping controllers and services tidy.

View on GitHub
Deep Wiki
Context7

Getting Started

First, recalibrate what you're installing. The package description pitches a chainable sanitizer/validator library for cleaning user input before it reaches your models. The actual artifact is a single Laravel Nova filter — a class you register in a Resource's filters() method so operators can narrow the admin index query. If you were about to composer require it into a form request, a job, or a DTO pipeline, stop: it will not do that, and the mismatch is the most expensive thing to discover late.

Hard gate: you must already run Nova, with credentials. Nova resolves from nova.laravel.com, so auth.json needs a valid license. Without it, composer require fails with a Nova authentication error that never mentions value-filter — a debugging detour people burn an afternoon on. Confirm composer show laravel/nova works in the target app before you start.

Read src/ before writing a single use statement. With 3 stars, 0 dependents, and a last release of 2023-05-15, there is no blog trail, no issue-thread lore, no community to ask. The tree is small — audit it in ten minutes and answer four questions:

  1. FQCN. Don't guess SeoEgypt\ValueFilter\ValueFilter. Read the namespace and class name from the file; every import depends on it.
  2. key(). This determines the query-string key stored in Nova's filter payload and must be unique across the panel. Nova's base implementation returns the class basename, which means a subclass silently changes its own key.
  3. name(). The dropdown label. Often hardcoded, so per-Resource labels need a subclass or withName().
  4. apply(Request $request, $query, $value). This method is the package. Check whether it hardcodes the column or reads one from config, whether it does where($column, $value), and what it does with null, arrays, and unexpected types.

First use case: one equality filter on one indexed column of one low-traffic Resource. Pick a column you'd otherwise hand-roll a select filter for — orders.status, users.role, tickets.priority.

// app/Nova/Order.php
use SeoEgypt\ValueFilter\ValueFilter; // confirm against src/

public function filters(Request $request): array
{
    return [
        ValueFilter::make(),
    ];
}

Then verify by hand before trusting it: open the Resource index, apply every option, and compare the returned ID set against a query you wrote yourself in php artisan tinker. If the two disagree for any value — especially null — stop treating this as a dependency and start treating it as a reference implementation to copy.

Default recommendation for most teams: vendor it. Copy the filter class into app/Nova/Filters (and the Vue component into resources/js/nova if one ships), drop the Composer dependency, and own ~50 lines forever. That decision is cheap today and expensive to defer.

Implementation Patterns

Pattern 1 — Direct registration (dependency path)

Pin to an exact tag, never a caret range, and register on one Resource only:

composer require seoegypt/value-filter:1.x.y --with-all-dependencies

Keep it off high-traffic Resources until its output has been validated against production-shaped data, not a three-row seed.

Pattern 2 — Subclass and own the query

The realistic leverage point is treating the package as a UI shell — label, input rendering, key() — while owning query semantics yourself. Extend the filter, override apply(), and add the constraints the base class can't express: tenant scoping, soft-delete handling, type coercion.

namespace App\Nova\Filters;

use Illuminate\Http\Request;
use SeoEgypt\ValueFilter\ValueFilter as BaseFilter;

class OrderStatusFilter extends BaseFilter
{
    public $name = 'Order status';

    public function apply(Request $request, $query, $value)
    {
        // Guard the shape Nova hands you — never trust it blindly.
        if (! in_array($value, ['pending', 'paid', 'refunded'], true)) {
            return $query;
        }

        return $query
            ->where('orders.status', $value)
            ->where('orders.tenant_id', $request->user()->tenant_id);
    }
}

Subclassing solves two recurring annoyances at once: per-Resource labels ($name) and unique keys when you need two instances of the same filter in one panel.

Pattern 3 — Supply options explicitly

If the base filter renders a free-text input rather than a select, override options() so operators choose from a fixed set instead of typing arbitrary strings — that eliminates the whole "silently wrong results from a typo" class of bug:

public function options(Request $request): array
{
    return [
        'Pending'  => 'pending',
        'Paid'     => 'paid',
        'Refunded' => 'refunded',
    ];
}

If the bundled Vue component ignores options(), that's your signal to vendor the component and edit it rather than fight the renderer.

Pattern 4 — Reuse across Resources via a base Resource

When several admin Resources need the same filter, register it once in a shared abstract Resource instead of repeating the entry:

abstract class AdminResource extends Resource
{
    public function filters(Request $request): array
    {
        return [OrderStatusFilter::make()];
    }
}

Override filters() in the handful of Resources that need something different. This keeps the filter surface auditable in one file when the Nova major upgrade lands.

Pattern 5 — Test the filter as a query contract, not as UI

Don't attempt to test the Vue component. Test the outcome. Nova sends filters as a base64-encoded JSON array in the filters query param; construct it explicitly:

public function test_status_filter_returns_only_paid_orders(): void
{
    $paid    = Order::factory()->create(['status' => 'paid']);
    $pending = Order::factory()->create(['status' => 'pending']);

    $filters = base64_encode(json_encode([
        ['class' => OrderStatusFilter::class, 'value' => 'paid'],
    ]));

    $this->actingAs($this->admin)
        ->getJson("/nova-api/orders?filters={$filters}")
        ->assertOk()
        ->assertJsonFragment(['id' => $paid->id])
        ->assertJsonMissing(['id' => $pending->id]);
}

Add explicit cases for null, an unknown value, and a wrong-typed value — those are exactly where a naive where($column, $value) misbehaves without throwing.

Pattern 6 — Gate visibility with canSee()

Filters are UI, and UI leaks information. If an operator shouldn't see a "tenant" or "moderation state" dimension, gate it:

OrderStatusFilter::make()->canSee(fn ($request) => $request->user()->isAdmin());

canSee() is a UX guard, not an authorization boundary — apply() still runs on the query, so your policies remain the security layer.

Pattern 7 — Check the query plan before rollout

A filter compiles to a where on the admin index query, executed on every page load for every operator. Run EXPLAIN on production-shaped data for the exact column. Low-cardinality columns (status, role) are fine at tens of thousands of rows and painful at millions; an unindexed column on a large table turns the admin panel into a support queue.

Gotchas and Tips

The description lies about scope. "Filter, normalize, and transform values" reads like a sanitization library. It isn't. If a colleague proposes it for form-request cleanup or API input validation, correct that in the PR — don't let it drift into a sanitization role it can't fill.

Version drift is the primary risk. A 2023-05-15 release predates Nova 5, Laravel 12, and PHP 8.3+. Three independent break lines: the Nova major (Nova 3 = Vue 2 tooling; Nova 4/5 = Vue 3), the Laravel constraint in composer.json, and the PHP floor. Check all three against your lockfile before estimating the ticket. Pin to an exact version and disable automated update PRs — an unreviewed patch bump can break the admin panel silently.

apply() is where bugs hide, and they don't throw. The failure mode is a silently wrong list an operator acts on — everything, nothing, or the wrong subset, returned with a 200. There's no error to alert on. That's precisely why Pattern 5 is not optional; it's the mitigation.

Null and type coercion. A bare where('status', null) compiles to is null, which may be what you want or may silently drop rows you expected. A bare where('status', ['a','b']) behaves differently than intuition suggests. Read apply() line by line and assert null and array behavior explicitly in tests rather than inferring it from the UI.

key() collisions. Nova's base returns the class basename, so two instances of the same filter class in one panel share a key and clobber each other's state. Subclasses get a fresh key for free — but if you register the same class twice with different withMeta() configs, set explicit ->key('...') values.

Composer resolution failure shows up at the worst time. A stale constraint blocks a Laravel upgrade months later, during an unrelated security patch. If you install it, document the pinned version and its constraint in the upgrade runbook the same day.

CI without Nova credentials cannot install it. Every pipeline resolving composer.lock needs auth.json with Nova credentials. One more argument for the vendor path: drop the dependency and the CI friction disappears with it.

Assume no maintainer from day one. 0 dependents means nobody surfaces breakage before you do, and no issue thread will answer your question. Assign a named owner, add the filter to the Nova upgrade checklist, and write down its intended semantics in the repo so the next engineer isn't reverse-engineering apply() from scratch.

Never put it on a critical path. Internal admin tooling only — no SLA, no revenue-critical view, no security-sensitive or multi-tenant-critical surface. If the requirement needs operators, ranges, dates, or anything beyond simple equality, write the Nova filter in-house; at that point the package's tiny surface becomes something you fight rather than reuse.

Extension points, in order of usefulness: override apply() (query semantics) → options() (input shape) → key()/$name (identity and label) → canSee() (visibility) → default() (preselected value on first load — easy to forget, and it changes what operators see by default). The Vue component is the last resort; touch it only after vendoring.

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.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource