PHPackages                             philiprehberger/php-schema-validator - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Validation &amp; Sanitization](/categories/validation)
4. /
5. philiprehberger/php-schema-validator

ActiveLibrary[Validation &amp; Sanitization](/categories/validation)

philiprehberger/php-schema-validator
====================================

Fluent data schema validator with nested objects, arrays, and dot-notation errors

v1.2.0(2mo ago)138MITPHPPHP ^8.2CI passing

Since Mar 15Pushed 1mo agoCompare

[ Source](https://github.com/philiprehberger/php-schema-validator)[ Packagist](https://packagist.org/packages/philiprehberger/php-schema-validator)[ Docs](https://github.com/philiprehberger/php-schema-validator)[ GitHub Sponsors](https://github.com/philiprehberger)[ RSS](/packages/philiprehberger-php-schema-validator/feed)WikiDiscussions main Synced 3w ago

READMEChangelogDependencies (6)Versions (10)Used By (0)

PHP Schema Validator
====================

[](#php-schema-validator)

[![Tests](https://github.com/philiprehberger/php-schema-validator/actions/workflows/tests.yml/badge.svg)](https://github.com/philiprehberger/php-schema-validator/actions/workflows/tests.yml)[![Latest Version on Packagist](https://camo.githubusercontent.com/e69bf1d3d2c4979aa97ebc74e06bf912fc74407b9cd87e942e003928910b2b93/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7068696c69707265686265726765722f7068702d736368656d612d76616c696461746f722e737667)](https://packagist.org/packages/philiprehberger/php-schema-validator)[![Last updated](https://camo.githubusercontent.com/af587dd2930d79e3398e9471d751da24505745e0003a81bb8593ff872a8e31fd/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6173742d636f6d6d69742f7068696c69707265686265726765722f7068702d736368656d612d76616c696461746f72)](https://github.com/philiprehberger/php-schema-validator/commits/main)

Fluent data schema validator with nested objects, arrays, and dot-notation errors.

Requirements
------------

[](#requirements)

- PHP 8.2+

Installation
------------

[](#installation)

```
composer require philiprehberger/php-schema-validator
```

Usage
-----

[](#usage)

```
use PhilipRehberger\SchemaValidator\Schema;

$schema = Schema::object([
    'name'  => Schema::string()->min(1)->max(100),
    'email' => Schema::string()->email(),
    'age'   => Schema::int()->min(0)->max(150),
]);

$result = $schema->validateData([
    'name'  => 'Alice',
    'email' => 'alice@example.com',
    'age'   => 30,
]);

$result->passes(); // true
$result->fails();  // false
$result->errors(); // []
```

### Nested Objects

[](#nested-objects)

```
$schema = Schema::object([
    'user' => Schema::object([
        'profile' => Schema::object([
            'email' => Schema::string()->email(),
        ]),
    ]),
]);

$result = $schema->validateData([
    'user' => ['profile' => ['email' => 'invalid']],
]);

$result->errors(); // ["user.profile.email must be a valid email address"]
```

### Typed Arrays

[](#typed-arrays)

```
$schema = Schema::object([
    'tags'  => Schema::arrayOf(Schema::string()),
    'items' => Schema::arrayOf(Schema::object([
        'id'   => Schema::int(),
        'name' => Schema::string(),
    ])),
]);
```

### Optional and Nullable Fields

[](#optional-and-nullable-fields)

```
$schema = Schema::object([
    'name'     => Schema::string(),
    'nickname' => Schema::string()->optional(),  // field may be absent
    'bio'      => Schema::string()->nullable(),  // field may be null
]);
```

### String Validators

[](#string-validators)

```
Schema::string()->min(3)->max(50);   // length constraints
Schema::string()->email();           // email format
Schema::string()->url();             // URL format
Schema::string()->uuid();            // UUID format
Schema::string()->regex('/^\d+$/');  // custom pattern
```

### Enum Values

[](#enum-values)

```
Schema::enum(['draft', 'published', 'archived']);
```

### Any Value

[](#any-value)

```
Schema::any();           // accepts any non-null value
Schema::any()->nullable(); // accepts anything including null
```

### Custom Validation Rules

[](#custom-validation-rules)

Add custom validation logic to any schema type using `custom()`. The callable receives the value and returns `null` if valid, or an error message string if invalid.

```
$schema = Schema::object([
    'username' => Schema::string()->min(3)->custom(function (string $value): ?string {
        if (str_starts_with($value, 'admin')) {
            return 'must not start with "admin"';
        }

        return null;
    }),
    'age' => Schema::int()->min(0)->custom(function (int $value): ?string {
        if ($value % 2 !== 0) {
            return 'must be an even number';
        }

        return null;
    }),
]);

$result = $schema->validateData(['username' => 'admin_user', 'age' => 25]);
$result->errors();
// ["username must not start with "admin"", "age must be an even number"]
```

Custom validators only run when all built-in checks pass.

### Value Transformers

[](#value-transformers)

Use `transform()` to normalize a value before validation. The callable receives the raw value and returns the transformed value.

```
$schema = Schema::object([
    'email' => Schema::string()->email()->transform(fn (mixed $v) => strtolower(trim($v))),
    'tags'  => Schema::arrayOf(Schema::string())->transform(fn (mixed $v) => array_unique($v)),
]);

$result = $schema->validateData([
    'email' => '  Alice@Example.COM  ',
    'tags'  => ['php', 'laravel', 'php'],
]);

$result->passes(); // true — email was trimmed and lowered before validation
```

Transformers run before any type or constraint checks (but after the null check).

### Cross-Field Validation

[](#cross-field-validation)

Use `crossField()` on an `ObjectSchema` to validate relationships between fields. Each callable receives the full data array and returns `null` if valid, or an error message string.

```
$schema = Schema::object([
    'password'         => Schema::string()->min(8),
    'password_confirm' => Schema::string(),
    'start_date'       => Schema::string(),
    'end_date'         => Schema::string(),
])->crossField(function (array $data): ?string {
    if ($data['password'] !== $data['password_confirm']) {
        return 'password_confirm must match password';
    }

    return null;
})->crossField(function (array $data): ?string {
    if ($data['start_date'] >= $data['end_date']) {
        return 'end_date must be after start_date';
    }

    return null;
});

$result = $schema->validateData([
    'password'         => 'secret123',
    'password_confirm' => 'different',
    'start_date'       => '2026-03-20',
    'end_date'         => '2026-03-10',
]);

$result->errors();
// ["password_confirm must match password", "end_date must be after start_date"]
```

Cross-field validators only run when all individual field validations pass.

### Conditional Fields

[](#conditional-fields)

Use `when()` on an `ObjectSchema` to conditionally require additional fields based on the value of another field.

```
$schema = Schema::object([
    'type' => Schema::string(),
    'email' => Schema::string()->email(),
])->when('type', 'business', [
    'company_name' => Schema::string()->min(1),
    'tax_id' => Schema::string(),
]);

// When type is 'business', company_name and tax_id are also validated
// When type is anything else, those fields are ignored
```

### Schema Composition

[](#schema-composition)

Use `extend()` to create a new schema that combines the fields of the current schema with additional fields.

```
$base = Schema::object(['name' => Schema::string(), 'email' => Schema::string()->email()]);
$admin = $base->extend(['role' => Schema::string(), 'permissions' => Schema::arrayOf(Schema::string())]);
// $admin validates name, email, role, and permissions
// $base is unchanged
```

### Custom Error Messages

[](#custom-error-messages)

Use `withMessages()` on a `ValidationResult` to replace default error messages for specific fields.

```
$result = $schema->validateData($data);

$result = $result->withMessages([
    'name' => 'Please enter your full name',
    'email' => 'A valid email address is required',
]);
```

API
---

[](#api)

### `Schema` (static factory)

[](#schema-static-factory)

MethodReturnsDescription`Schema::object(array $fields)``ObjectSchema`Create an object schema with field definitions`Schema::string()``StringSchema`Create a string schema`Schema::int()``IntSchema`Create an integer schema`Schema::float()``FloatSchema`Create a float schema`Schema::bool()``BoolSchema`Create a boolean schema`Schema::arrayOf(SchemaType $item)``ArraySchema`Create a typed array schema`Schema::enum(array $values)``EnumSchema`Create an enum schema`Schema::any()``AnySchema`Create a schema that accepts any value### `ValidationResult`

[](#validationresult)

MethodReturnsDescription`passes()``bool`True if validation passed`fails()``bool`True if validation failed`errors()``array`All error messages`firstError()``?string`First error message or null`withMessages(array $messages)``ValidationResult`Replace errors for matching field paths with custom messages### `ObjectSchema` extras

[](#objectschema-extras)

MethodDescription`crossField(callable $validator)`Add a cross-field validator (receives full data array, returns `?string`)`when(string $field, mixed $value, array $thenSchema)`Conditionally validate additional fields when a field matches a value`extend(array $additionalFields)`Create a new schema combining current fields with additional fields### Common Modifiers

[](#common-modifiers)

All schema types support:

MethodDescription`optional()`Field may be absent from the parent object`nullable()`Field may be null`custom(callable $validator)`Add a custom validation callback (receives value, returns `?string`)`transform(callable $transformer)`Transform the value before validationDevelopment
-----------

[](#development)

```
composer install
vendor/bin/phpunit
vendor/bin/pint --test
```

Support
-------

[](#support)

If you find this project useful:

⭐ [Star the repo](https://github.com/philiprehberger/php-schema-validator)

🐛 [Report issues](https://github.com/philiprehberger/php-schema-validator/issues?q=is%3Aissue+is%3Aopen+label%3Abug)

💡 [Suggest features](https://github.com/philiprehberger/php-schema-validator/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement)

❤️ [Sponsor development](https://github.com/sponsors/philiprehberger)

🌐 [All Open Source Projects](https://philiprehberger.com/open-source-packages)

💻 [GitHub Profile](https://github.com/philiprehberger)

🔗 [LinkedIn Profile](https://www.linkedin.com/in/philiprehberger)

License
-------

[](#license)

[MIT](LICENSE)

###  Health Score

41

—

FairBetter than 87% of packages

Maintenance88

Actively maintained with recent releases

Popularity9

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity52

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~1 days

Total

9

Last Release

88d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/cfd7d24cbbf32400fa13ce0bbe7a31edd2d66a6d4488eafdb3d64c5337bf0435?d=identicon)[philiprehberger](/maintainers/philiprehberger)

---

Top Contributors

[![philiprehberger](https://avatars.githubusercontent.com/u/8218077?v=4)](https://github.com/philiprehberger "philiprehberger (15 commits)")

---

Tags

phpschemavalidatorvalidationfluent

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/philiprehberger-php-schema-validator/health.svg)

```
[![Health](https://phpackages.com/badges/philiprehberger-php-schema-validator/health.svg)](https://phpackages.com/packages/philiprehberger-php-schema-validator)
```

###  Alternatives

[evaisse/php-json-schema-generator

A JSON Schema Generator.

18310.5k1](/packages/evaisse-php-json-schema-generator)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
