PHPackages                             tetthys/commit-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. [Utility &amp; Helpers](/categories/utility)
4. /
5. tetthys/commit-validator

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

tetthys/commit-validator
========================

Framework-agnostic commit-time validator for session-aggregated payloads using DTO + PHP Attributes.

0.0.2(4mo ago)15MITPHPPHP ^8.4

Since Jan 13Pushed 4mo agoCompare

[ Source](https://github.com/tetthys/commit-validator)[ Packagist](https://packagist.org/packages/tetthys/commit-validator)[ RSS](/packages/tetthys-commit-validator/feed)WikiDiscussions dev Synced 1mo ago

READMEChangelog (2)DependenciesVersions (3)Used By (0)

tetthys/commit-validator
========================

[](#tetthyscommit-validator)

A fast, framework-agnostic validator designed for **commit-time validation** of **session-aggregated payloads** (multi-step forms), using **DTOs + PHP Attributes** and an optional lightweight **DSL** for commit-only rules.

This library is intentionally minimal: it validates the *final, assembled* data right before you “commit” it to your database (or any durable store).

- **PHP**: 8.4+
- **Framework**: none (pure PHP)
- **Primary style**: DTO + Attributes
- **Secondary style**: DSL (for commit-only overlays)
- **No global helper is shipped**: avoid name collisions; you can define your own optional helper (`cv()` recommended).

---

Table of Contents
-----------------

[](#table-of-contents)

- [Why this library exists](#why-this-library-exists)
- [Install](#install)
- [Concepts](#concepts)
    - [Commit-time validation](#commit-time-validation)
    - [DTOs and Attributes](#dtos-and-attributes)
    - [Paths and error format](#paths-and-error-format)
- [Quick Start](#quick-start)
    - [Recommended: define a local `cv()` helper (optional)](#recommended-define-a-local-cv-helper-optional)
- [Defining DTOs](#defining-dtos)
    - [Basic fields](#basic-fields)
    - [Nested DTOs](#nested-dtos)
    - [Arrays of DTOs (Each)](#arrays-of-dtos-each)
    - [Collection constraints (Count)](#collection-constraints-count)
- [Validating](#validating)
    - [Validating a DTO instance](#validating-a-dto-instance)
    - [Adding commit-only rules (DSL overlays)](#adding-commit-only-rules-dsl-overlays)
- [Multi-step form workflow (session aggregation pattern)](#multi-step-form-workflow-session-aggregation-pattern)
    - [Step storage](#step-storage)
    - [Final aggregation](#final-aggregation)
    - [Commit validation](#commit-validation)
- [Error handling](#error-handling)
    - [Displaying errors](#displaying-errors)
    - [Mapping paths to form field names (recommended pattern)](#mapping-paths-to-form-field-names-recommended-pattern)
- [Examples](#examples)
    - [Example: product.images is required and must have 1..6 items](#example-productimages-is-required-and-must-have-16-items)
    - [Example: nested address + items list](#example-nested-address--items-list)
    - [Example: draft vs commit strictness](#example-draft-vs-commit-strictness)
- [Performance notes](#performance-notes)
- [API reference](#api-reference)
- [License](#license)

---

Why this library exists
-----------------------

[](#why-this-library-exists)

Many validators are request-scoped: they validate a single request.
But multi-step forms often work like this:

1. Step 1 validates and stores partial data (session, cache, temp DB row, etc.)
2. Step 2 validates and stores more data
3. Step N stores the last piece
4. **Commit**: assemble the final payload and validate it holistically

At commit-time you need constraints like:

- "`product.images` must exist, and have 1..6 items"
- "`shipping.address` must be present if `shipping.method` is `delivery`"
- "`items` must have at least one item, and each item must be valid"
- "Nested DTOs must satisfy their own rules"

`tetthys/commit-validator` focuses specifically on this commit-time validation problem.

---

Install
-------

[](#install)

```
composer require tetthys/commit-validator
```

Requirements:

- PHP `^8.4`

---

Concepts
--------

[](#concepts)

### Commit-time validation

[](#commit-time-validation)

“Commit-time validation” means you validate **the final assembled payload**, not each partial step in isolation.

This library assumes you already have a mechanism to store intermediate step data and to assemble it into a final array or DTO at commit time.

### DTOs and Attributes

[](#dtos-and-attributes)

You define a DTO (data transfer object) and attach validation rules to its public properties using PHP Attributes:

```
use CommitValidator\Attributes\Required;
use CommitValidator\Attributes\Length;

final readonly class PostDTO
{
    public function __construct(
        #[Required('Title is required.')]
        #[Length(min: 3, max: 80, message: 'Title must be 3..80 chars.')]
        public string $title,

        #[Required('Body is required.')]
        #[Length(min: 10, message: 'Body must be at least 10 chars.')]
        public string $body,
    ) {}
}
```

### Paths and error format

[](#paths-and-error-format)

Validation errors are keyed by a **dot path**:

- `title`
- `product.images`
- `product.images.0.url`
- `address.city`

Errors are returned as a map:

```
[
  "product.images" => [
    ["code" => "min", "message" => "Images must be between 1 and 6."],
  ],
  "product.images.2.url" => [
    ["code" => "regex", "message" => "Image URL must be a valid http(s) URL."],
  ],
]
```

This makes it easy to match errors back to nested form inputs and UI components.

---

Quick Start
-----------

[](#quick-start)

### 1) Define DTO + Attributes

[](#1-define-dto--attributes)

```
