phpdot/validator

Strict, type-safe validation with structured error codes for the PHPdot ecosystem.

Maintainers

Package info

github.com/phpdot/validator

Issues

pkg:composer/phpdot/validator

Transparency log

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

v0.1.0 2026-07-17 23:14 UTC

This package is auto-updated.

Last update: 2026-07-18 03:25:32 UTC


README

Strict, type-safe validation that speaks phpdot/error: every rule failure is a structured error code, so validation errors flow through the same ErrorBag as the rest of your application — one output shape everywhere. Rules are objects, bound to your domain error codes, and the factory threads any registered message translator into the bag automatically.

Table of Contents

Requirements

Requirement Constraint
PHP >= 8.5
phpdot/error ^0.1

phpdot/container is a dev-only suggestion for auto-wiring ValidatorFactory.

Installation

composer require phpdot/validator

Usage

Each rule is bound to one of your domain error codes with withError(). Create a fresh Validator per validation session from the injected factory:

use PHPdot\Validator\Rule\Email;
use PHPdot\Validator\Rule\Min;
use PHPdot\Validator\Rule\Required;
use PHPdot\Validator\ValidatorFactory;

$validator = (new ValidatorFactory())->create();

$errors = $validator->validate($request->all(), [
    'username' => [
        (new Required())->withError(UserErrorCode::UsernameRequired),
        (new Min(3))->withError(UserErrorCode::UsernameTooShort),
    ],
    'email' => [
        (new Required())->withError(UserErrorCode::EmailRequired),
        (new Email())->withError(UserErrorCode::EmailInvalid),
    ],
]);

if ($errors->hasErrors()) {
    return $response->json($errors->toArray(), $errors->getHttpStatus());
}

$errors is a phpdot/error ErrorBag — the same value your controllers, services, and responders already handle.

Auto-wired with DI

Inject ValidatorFactory and call create() per validation. The factory threads any registered MessageTranslatorInterface into the bag, so your services never import the translator:

public function __construct(private readonly ValidatorFactory $validators) {}

$bag = $this->validators->create()->validate($input, $rules);

Accumulating across payloads

Reuse one validator across several validate() calls; errors accumulate into one bag:

$v = $this->validators->create();
$v->validate($userInput, $userRules);
$v->validate($paymentInput, $paymentRules);
$bag = $v->errors();   // both payloads' errors combined

The rule set covers presence, type, size, format, choice, cross-field comparison, date, and closure rules; implement the Rule contract for your own.

Architecture

ValidatorFactory builds a Validator (wiring in the translator). validate() runs each field's rules against the input inside a ValidationContext (which exposes sibling fields for cross-field rules); a failing rule contributes its bound error code to the ErrorBag from phpdot/error.

graph TD
    FACTORY["ValidatorFactory<br/><br/>create() per session, threads the translator"]
    VALIDATOR["Validator<br/><br/>runs rules field-by-field"]
    CONTEXT["ValidationContext<br/><br/>value + sibling fields for cross-field rules"]
    RULES["Rule implementations<br/><br/>presence / type / size / format /<br/>choice / comparison / date / closure"]
    BAG["phpdot/error ErrorBag<br/><br/>structured error codes, one output shape"]

    FACTORY --> VALIDATOR
    VALIDATOR --> CONTEXT
    VALIDATOR --> RULES
    RULES --> BAG
Loading

Testing

composer install
composer test        # PHPUnit
composer analyse     # PHPStan, level max + strict rules
composer cs-check    # PHP-CS-Fixer
composer check       # All three

License

MIT.

This repository is a read-only mirror, generated by CI from phpdot/monorepo. Pull requests and issues belong in the monorepo.