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

Filterus Laravel Package

ircmaxell/filterus

Filterus is a lightweight PHP library for filtering and validating data with composable, object-oriented filters. It handles strings, numbers, arrays, emails, URLs, regex, ranges, and defaults, with clear error reporting for safer input handling.

Deep Wiki
Context7

Getting Started

Filterus is a standalone coercion/validation library, not a Laravel package — there is no service provider, no config file, no Blade directives. You install it and call it directly.

composer require ircmaxell/filterus

Everything hangs off one static factory class: Filterus\Filter. Each call returns a filter object implementing Filterus\FilterInterface, which exposes two methods:

  • filter($value) — coerces and returns the cleaned value, or false on failure.
  • validate($value) — boolean check, no coercion.

Look first at:

  1. src/Filterus/Filter.php — the factory methods and the fluent modifiers (chain, optional, default, min, max).
  2. src/Filterus/FilterInterface.php — the two-method contract you'll implement for custom filters.
  3. src/Filterus/Filter/ — concrete filters (IntFilter, StringFilter, MapFilter, ListFilter, RegexFilter, EmailFilter, etc.). Skim MapFilter and ListFilter first; they're the ones you'll compose.

First use case — clean an incoming request payload into a typed array before it reaches a service or DTO:

use Filterus\Filter;

$schema = Filter::map([
    'name'  => Filter::string(1, 100),
    'age'   => Filter::int(0, 120),
    'email' => Filter::email(),
    'tags'  => Filter::list(Filter::string(1, 30), 0, 10)->optional(),
]);

$clean = $schema->filter($request->all());

if ($clean === false) {
    // at least one field failed; see Gotchas for how to find which
}

Note that filter() signals failure with false, not an exception — that shapes everything else about how you'll use this.

Implementation Patterns

Schema maps as a DTO/coercion layer. The highest-value pattern is building one Filter::map() per endpoint or command and treating it as your input boundary. Laravel's validator confirms shape and produces messages; Filterus produces types. A common split is: FormRequest handles authorization + user-facing messages, then the action pipes $request->validated() through a Filterus map to coerce "3" into 3 and drop noise before constructing a value object.

final class CreateUserData
{
    public static function fromArray(array $input): self
    {
        $clean = Filter::map([
            'name'  => Filter::string(1, 100),
            'age'   => Filter::int(18, 120)->optional(),
            'admin' => Filter::boolean()->default(false),
        ])->filter($input);

        if ($clean === false) {
            throw new ValidationException('Invalid user payload');
        }

        return new self($clean['name'], $clean['age'] ?? null, $clean['admin']);
    }
}

Chaining for layered rules. chain() applies filters in sequence, which lets you compose primitives instead of hunting for a bespoke filter:

$slug = Filter::string(1, 80)
    ->chain(Filter::regex('/^[a-z0-9-]+$/'));

Use this for "must be a string and match a format" without writing a custom class.

Lists vs. uniform arrays. Filter::list($filter, $min, $max) filters each element of an indexed array and returns a re-indexed list. Filter::array($min, $max, $elementFilter) is for array-shaped values where you also care about element filtering. Reach for list() for JSON arrays and array() when the count bounds matter more than keys.

Optional vs. default. They solve different problems: optional() permits the key/value to be absent, while default($v) substitutes a value when nothing is supplied. Use optional() for genuinely nullable fields and default() for flags and settings. Don't stack both expecting one behavior.

Unions with pool(). When an endpoint accepts one of several shapes (e.g. an ID that's either an int or a UUID string), Filter::pool([...]) tries candidates in order. Keep the candidate list short and ordered most-specific-first; a permissive Filter::string() at the front will swallow everything.

Custom filters as extension points. For domain formats (money, phone, SKU), implement FilterInterface (or extend the abstract base) and keep filter()/validate() pure and side-effect free:

final class SkuFilter implements \Filterus\FilterInterface
{
    public function filter($value)
    {
        if (!is_string($value) || !preg_match('/^[A-Z]{3}-\d{4}$/', $value)) {
            return false;
        }
        return $value;
    }

    public function validate($value): bool
    {
        return $this->filter($value) !== false;
    }
}

Then register them in a small factory or container binding so controllers never new a filter inline.

Hoist schemas out of loops. Filter objects are cheap but not free; build the schema once per request (a property, a singleton binding, or a static in the DTO) rather than inside foreach over rows.

Gotchas and Tips

  • false is overloaded. filter() returns false for failure, but a valid boolean filter can legitimately return false, and an int coercion can return 0 (which is falsy). Never branch on if (!$result). Compare === false, and when ambiguity is possible, call validate() first, then filter() only on success.
  • Coercion is aggressive. String and int filters cast rather than reject; "12abc" and 12.9 may both coerce into something you didn't intend. If you need strictness, chain a regex() or put Laravel's integer/string rules in front and let Filterus only normalize.
  • Failures are opaque. A map() returns a single false with no field-level detail. If you need messages, loop the schema yourself and run $filter->validate($input[$key] ?? null) per field to build an error bag. This is the biggest ergonomic gap versus Laravel's validator.
  • No messages, no localization, no $errors. Filterus is not a validation framework. Do not try to replace FormRequests with it; it has no concept of attribute names, translations, or HTTP status codes.
  • Treat filters as immutable. Fluent calls like chain(), optional(), and default() are easy to assume mutate in place. Always assign the return value ($f = Filter::int()->optional();) rather than relying on the original object changing — verify against your installed version's behavior.
  • Extra keys in map(). Confirm what your version does with keys not present in the schema before you rely on it. Don't assume unknown input is silently dropped or passed through — assert it in a test, because either behavior can be a security-relevant surprise.
  • optional() and default() interact with missing keys, not just nulls. A key present with null and a key absent can take different paths. Test both, especially for JSON request bodies where null is common.
  • Regex filters need delimiters (/^...$/) and return false on no-match — same overloaded-false trap as above.
  • Old codebase. This library predates PHP 7 typed signatures and modern tooling; check PHP 8.x compatibility and treat it as maintenance-mode. Pin a version in composer.json and keep Filterus usage isolated behind your own DTO/factory layer so replacing it later (with filter_var, Laravel rules, or a modern serializer) is a one-file change.
  • Debugging tip. When a schema returns false, bisect it: Filter::map() over a single key at a time. Because there's no error reporting, isolating the failing branch is faster than reasoning about the whole map.
  • Performance is fine for per-request work, but avoid constructing schemas inside queue-worker loops over thousands of rows — build once, reuse.
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.
ably/pubsub-server
mstfkhazaal/defender
mfonte/base62x
karnoweb/metapilot
tobya/bcsapiwrapper
swalker2/cpanel
vish4395/laravel-translation-manager
morningtrain/economic
teksite/systeminfo-laravel
atomcms/voting
run6/weather
siokas/laravelembeddirectives
adamlien/pkuuids
gilsonsouza/lara-doc-generator
manelgavalda/enrollment_mobile
unabomber/timezone
delatbabel/contacts
astritzeqiri/g-recaptcha
kevinongko/laravel-genode
developeruz/laravel-analytics