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

Default Value Filterable Laravel Package

javii-script/default-value-filterable

A Laravel package that adds default-value support to filterable fields, letting you preselect filters and apply sensible defaults so list views start with the right results out of the box.

View on GitHub
Deep Wiki
Context7

Getting Started

Before anything else: verify the surface area. This package has 2 stars, 0 dependents, and a single release (2025-01-16). There is no meaningful ecosystem around it, so treat the README as a starting hypothesis, not documentation. The whole package is almost certainly a handful of classes — read src/ end to end (10–15 minutes) before writing any application code. Specifically confirm:

  • The exact trait/class name (packages like this typically ship a Filterable trait or a DefaultValueFilterable concern for Eloquent models).
  • Whether defaults are declared as a class property, a method, a PHP attribute (#[Filterable(default: ...)]), or a config array.
  • Whether it hooks into spatie/laravel-query-builder, a hand-rolled ?filter[...] parser, or Filament/Nova table filters. The name suggests the former, but confirm.
  • The Laravel/PHP constraints in composer.json and whether tests exist.

Install and pin.

composer require javii-script/default-value-filterable
# It has one release; pin it explicitly rather than floating.
composer require "javii-script/default-value-filterable:^1.0"

Check for a service provider and any publishable config:

php artisan vendor:publish --provider="JaviiScript\DefaultValueFilterable\DefaultValueFilterableServiceProvider"

If no provider is auto-discovered, inspect composer.json → extra.laravel.providers. A missing provider on a package that expects one is the single most common "it does nothing" failure.

First use case — the one that pays for the package immediately. A paginated index endpoint where the UI always shows some filter state, but the first page load has an empty query string. Without defaults you either return unfiltered rows or the front end has to know the server's defaults.

// app/Models/Post.php
use JaviiScript\DefaultValueFilterable\Concerns\Filterable; // verify namespace

class Post extends Model
{
    use Filterable;

    // Shape depends on the package — verify against src/.
    protected array $defaultFilters = [
        'status' => 'published',
        'sort'   => '-published_at',
    ];
}
// app/Http/Controllers/Api/PostController.php
public function index(Request $request)
{
    return Post::query()
        ->filterable($request->query()) // verify method name
        ->paginate();
}

The success criterion: GET /api/posts and GET /api/posts?filter[status]=draft return different result sets, and GET /api/posts?filter[status]= (explicit blank) is distinguishable from absent. That third case is where these packages usually have opinions — pin it down now.

Implementation Patterns

1. Defaults as the contract, not the fallback. The valuable pattern isn't "apply a default when missing" — it's "the endpoint's default view is declared in one place and is identical for web, API, and tests." Put the defaults on the model/filter class, and let the client opt out explicitly rather than opt in.

// Default = what the dashboard shows on first load.
// Override = what the user clicked.
$filters = $request->validated('filter', []); // [] means "use defaults"

2. Separate read models from write models. Don't bolt filter defaults onto models that are also mass-assigned from request payloads. Prefer a dedicated query/filter class per index endpoint, and apply the trait there if the package supports a non-model host. If it's model-only, keep the default set small and stable — those properties become part of your public API surface.

3. Layer with spatie/laravel-query-builder if that's the integration. The common shape is that the package resolves defaults before AllowedFilter runs, so your allow-list still governs what's legal:

Post::query()
    ->filterable($request->query())      // supplies defaults + user input
    ->allowedFilters(['status', 'author_id'])
    ->allowedSorts(['published_at', 'title'])
    ->paginate();

Confirm the ordering by testing an illegal default — a default for a filter that is not in allowedFilters() should either be silently dropped or throw. Either behavior is fine; not knowing which is not.

4. Make defaults environment- and tenancy-aware. Hardcoded property arrays break the moment you have multi-tenancy or per-user preferences. Resolve them lazily:

protected function defaultFilters(): array
{
    return [
        'status'     => 'published',
        'department' => auth()->user()?->department_id,
    ];
}

Lazy resolution (method, not property) also avoids serializing stale values into queued jobs or cache payloads.

5. Test the three states explicitly. Any test suite for this package should have one test per column of this matrix:

Query string Expected
? (nothing) defaults applied
?filter[status]=draft override wins, other defaults preserved
?filter[status]= (blank) decide and document: blank, ignored, or default

The third row is the one that regresses silently and the one your front end will hit when a user clears a dropdown.

6. Reuse the resolved filter set for UI state. Return it in the response so the front end can render active filter chips without duplicating defaults:

return PostResource::collection($posts)->additional([
    'meta' => ['filters' => $posts->appliedFilters()], // if exposed
]);

If the package doesn't expose the resolved set, wrap the call and record what you passed in — you will want it in logs when a user reports "the wrong rows."

7. Use it for report/export endpoints too. Anywhere a CSV export or scheduled report needs the same slice of data as the on-screen table, routing both through the same filterable query guarantees they can't drift.

Gotchas and Tips

Absent vs. empty vs. zero is the whole game. ?filter[page]=0, ?filter[status]=, and a missing key are three different things, and PHP's empty()/?? will happily collapse them. Whatever the package does, write a test that locks it in and document it in the controller.

Type coercion will bite you. Defaults declared as strings ('0', 'false', 'null') versus booleans/integers matter once they reach whereIn or a JSON column. Cast at the definition site and don't rely on the package to infer types from a property array.

Singleton / static state and Octane. Small packages often cache the resolved defaults on a static or a container singleton — fine under PHP-FPM, a cross-request leak under Laravel Octane or in long-running queue workers. Grep src/ for static, $this->app->singleton, and once(. If you find them, test with php artisan octane:start and two concurrent users with different tenants.

Don't let defaults leak into writes. A trait named Filterable should never touch fillable, but verify it doesn't add global scopes. A bootFilterable() that registers a global scope will silently filter Post::find($id) and every relationship query — a spectacular debugging session waiting to happen. Quick check: Post::withoutGlobalScopes()->count() vs Post::count().

Index alignment. A default filter turns every "first page load" into a filtered query. If the default is status = 'published' on a 10M-row table with no index on status, you've made the cheapest request in your app the expensive one. Run EXPLAIN on the default query specifically, not just the filtered variants.

Validation belongs above the package. Don't assume it validates filter keys or values. Run request input through a FormRequest with an allow-list of keys before it reaches the filterable call, otherwise unknown keys end up in where clauses depending on implementation. If the package does where($key, $value) with user-supplied keys, that is an injection/column-enumeration risk — check this first.

Nested and array defaults. 'tags' => ['a','b'] versus 'tags' => 'a,b' — confirm how arrays are merged with incoming input. Most implementations replace rather than merge, which is usually what you want, but verify before shipping a multi-select.

Debugging recipe. When the wrong rows come back, log in this order: (1) raw query string, (2) validated filter array, (3) resolved filter array immediately before execution, (4) toSql() + bindings. Nearly every bug is a mismatch between (2) and (3).

Pin the version and vendor the source if it becomes load-bearing. One release, zero dependents, no maintainer bus factor. If this ends up in a production path, either fork it into app/Support/ behind your own interface or add a thin wrapper class so swapping it out is a one-file change:

final class PostIndexQuery
{
    public function __construct(private array $input) {}

    public function build(): Builder
    {
        return Post::query()->filterable($this->input);
    }
}

Extension points to look for. Before forking, check for a published config file, a Filterable contract you can implement, or events/macros. A package this small frequently exposes one macro hook that covers 80% of customization needs — cheaper than a fork.

Alternative worth pricing out. The entire behavior is roughly 40 lines around array_merge($defaults, $input) plus a when() per key. If you find yourself working around the package more than once a week, replace it — the maintenance cost of a 2-star dependency in a core read path exceeds the cost of the code it saves.

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.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource