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

Assert Laravel Package

nilportugues/assert

A lightweight PHP assertion library for validating values and enforcing invariants. It provides expressive, chainable assertions that fail with clear exceptions, helping you catch invalid input early and make code contracts explicit and easy to read.

Deep Wiki
Context7

Getting Started

Install and inspect

composer require nilportugues/assert

The package has no Laravel service provider, facade, or config file — it is a plain PHP assertion helper. Before writing code, open the following in the repository (or vendor/nilportugues/assert after install):

  1. src/ — the main Assert class (or similarly named class) is the entire public API surface.
  2. README.md — usually lists every assertion method and the exception each throws.
  3. tests/ — the fastest way to see real call signatures and edge-case behavior, especially around nulls, empty strings, and numeric strings.

Confirm the minimum PHP version in composer.json. Release date is 2016-08-04, so expect a PHP 5.6/7.0-era codebase; verify it installs cleanly on your PHP 8.x before committing to it.

First use case

The natural day-to-day fit is guard clauses at the boundary of your domain code — value objects, DTOs, and service methods — not replacing Laravel's Validator for user-facing form input.

use NilPortugues\Assert\Assert; // verify exact namespace/class name in src/

final class Money
{
    private int $amount;

    public function __construct(int $amount)
    {
        Assert::integer($amount);
        Assert::greaterThan($amount, 0);

        $this->amount = $amount;
    }
}

Start by wrapping one value object or one service method. Do not retrofit an entire application on day one; this package is unmaintained and you want a small, reversible blast radius if you abandon it later.

Implementation Patterns

1. Assert at construction, not at use

The strongest pattern is to validate once in a constructor/factory and let the rest of the codebase trust the type. This pairs well with Laravel's container and readonly properties:

final class Email
{
    public function __construct(public readonly string $value)
    {
        Assert::string($value);
        Assert::email($value); // check method name in README
    }
}

2. Bridge assertion exceptions into Laravel's error handling

The package throws its own exception class (commonly InvalidArgumentException or a package-specific AssertionException). Laravel will render that as a 500 unless you catch it. Convert at the boundary:

use Illuminate\Validation\ValidationException;

try {
    $dto = new CreateOrderRequest($request->all());
} catch (\InvalidArgumentException $e) {
    throw ValidationException::withMessages([
        'order' => $e->getMessage(),
    ]);
}

A small AssertionsToValidation middleware or a base FormRequest::passedValidation() hook keeps this conversion in one place instead of sprinkled across controllers.

3. Use it inside FormRequest::after() for conditional rules

Laravel's rule strings get awkward for cross-field or domain-specific invariants. Use the assertion library as a post-validation guard:

public function after(): array
{
    return [
        function (Validator $validator) {
            try {
                new DateRange($this->input('start'), $this->input('end'));
            } catch (\InvalidArgumentException $e) {
                $validator->errors()->add('start', $e->getMessage());
            }
        },
    ];
}

4. Wrap it in a project-owned facade or helper

Because the upstream package is unmaintained, wrap it behind one class of your own (App\Support\Assert). That gives you a single file to change if you later swap to webmozart/assert, beberlei/assert, or hand-rolled checks — and lets you add Laravel-aware helpers (localized messages, ValidationException throwing) without forking.

5. Validate Artisan/queue payloads the same way

Jobs and console commands get the same guard-clause treatment. Fail fast in the job constructor so bad payloads never reach handle():

public function __construct(public array $payload)
{
    Assert::array($payload);
    Assert::keyExists($payload, 'user_id');
}

6. Pair with Laravel validation, don't replace it

Use Laravel's Validator for request shape, authorization, and user-facing messages; use the assertion package for invariants that must hold regardless of entry point (HTTP, queue, console, tests). This separation keeps validation messages translatable and keeps domain objects honest.

Gotchas and Tips

Unmaintained since 2016 — treat it as a vendored utility

The last release is from August 2016 and the repository is effectively abandoned. Expect:

  • No PHP 8.1+ enum/readonly support in signatures.
  • Possible deprecation warnings on PHP 8.x from older syntax (implicit nullable parameters, create_function, dynamic properties).
  • No security patching, no new assertion types, no Composer constraint updates.

Run your test suite on the target PHP version before adopting. If anything breaks, wrap and replace rather than patch.

Exception types and HTTP status

The library's exceptions are generic PHP exceptions, not Illuminate\Validation\ValidationException or HttpException. Uncaught, they render as 500s. Always convert at the controller/request boundary. Check which exception class each assertion throws — some libraries throw InvalidArgumentException, others a custom AssertionFailedException; broad catch (\InvalidArgumentException) may or may not catch everything.

Method naming is inconsistent across assertion libraries

In this ecosystem you will find isString() vs string(), notEmpty() vs notBlank(), greaterThan() vs min(). Read the actual src/ file — do not assume based on webmozart/assert or beberlei/assert muscle memory. Method names are the number one source of "does nothing" bugs: a typo in a static call throws BadMethodCallException, a typo inside a fluent chain may silently pass.

Null and empty-string semantics

The most common production surprise. Verify in tests/ whether:

  • notEmpty('0') passes or fails.
  • integer('42') (numeric string) passes.
  • notNull and notEmpty are distinct.

Domain objects should reject numeric strings deliberately — assert is_int() not is_numeric() when the type matters.

No localization, no field names

Messages are generic English strings and usually lack field context. Do not surface them directly to end users. Either map them in the ValidationException conversion (as above) or use them only for logs and 500-level "this is a programmer error" diagnostics.

Performance is fine; misuse is not

Static assertion calls are microseconds. The cost is architectural: assertions in hot loops or in boot() methods across hundreds of models will slow tests. Assert in constructors and at job/request boundaries only.

Testing expectations

Because assertions throw, your unit tests for value objects double as behavior documentation. Use expectException(\InvalidArgumentException::class) (or the actual class) and assert on the message. Add one test per assertion path — this is cheap and it pins the upstream behavior so a future replacement is safe.

Extension points are limited

There is no documented macro/extension mechanism in a package this small. If you need custom assertions (e.g., Assert::cpf() for Brazilian documents, which is plausible given the author), the intended approach is a subclass or a wrapper class in your own namespace that delegates to the library and adds methods. Do not edit vendor/.

Migration path if you outgrow it

The API is small enough to replace in an afternoon. webmozart/assert (now webmozart/assert maintained under Symfony) and beberlei/assert are the canonical maintained alternatives. Because you wrapped it in App\Support\Assert, swapping means rewriting one file and re-running the suite. Decide on this exit strategy before you sprinkle direct NilPortugues\Assert\Assert:: calls across 40 files.

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