From 3bfe67d324907c798510382568be2b6f8c1ddc99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=BB=D1=8C=D1=8F=20=D0=A1=D0=B0=D0=BB=D0=B8=D0=B3?= =?UTF-8?q?=D0=B6=D0=B0=D0=BD=D0=BE=D0=B2?= Date: Wed, 16 Jul 2025 19:47:50 +0500 Subject: [PATCH 1/2] New PSR for standardizing Validator (ValidatorInterface) --- proposed/validator-meta.md | 85 ++++++++++++++++++++++ proposed/validator.md | 144 +++++++++++++++++++++++++++++++++++++ 2 files changed, 229 insertions(+) create mode 100644 proposed/validator-meta.md create mode 100644 proposed/validator.md diff --git a/proposed/validator-meta.md b/proposed/validator-meta.md new file mode 100644 index 000000000..002f39ea8 --- /dev/null +++ b/proposed/validator-meta.md @@ -0,0 +1,85 @@ +Validator Meta Document +======================= + +## 1. Summary + +The SimpleValidatorInterface and ExtendedValidatorInterface define universal, minimalistic contracts for value validation in PHP. They provide a unified way to perform type-agnostic validations with either a simple pass/fail response (suitable for most form or field inputs) or a detailed, structured validation report, supporting error codes for i18n and advanced cases. Inspired by Symfony's Validator and `Respect\Validation`, these interfaces allow maximum interoperability and rapid provider/implementation swap, while enabling framework- and library-level integration without tight coupling. + +Applications MAY depend only on these interfaces and swap implementations (or chains/compositions of validators) via DI, reducing coupling and simplifying maintenance, testing, and future migrations. + +## 2. Why Bother? + +Form and value validation is a ubiquitous problem across all PHP applications. Today, each framework (Symfony, Laravel, Yii, etc.) exposes its own interfaces, making it difficult to share validators, migrate between frameworks or libraries, or compose validation pipelines with userland tools. + +A universal validator contract allows: + +Rapid replacement of validation engines or libraries (vendor-agnostic interface). +Interchangeable custom and vendor-specific validators (e.g., open-source and proprietary). +Testability and integration with dependency injection containers. +Consistent error format for user feedback, translation, or error mapping. +Clean separation of simple (bool) and extended (structured, multi-error) validation. +This pattern avoids having to deeply couple code to a specific validator ecosystem (as in Symfony) and dramatically reduces refactoring when switching stacks or updating validation strategies. + +#### Pros: + +- Plug-and-play with any validator implementations (no hard dependency on a specific package) +- Extensible (vendors can add extra methods, but must comply with the common interface) +- Clean and decoupled design +- Advanced: error codes, rich violation objects + +#### Cons: + +- Slight abstraction overhead (vs. using one concrete implementation) +- Vendor- or application-specific error codes are not enforced by spec (but spec supports them) +- Contextual or cross-field validation must be built upon (not in base interfaces) + +## 3. Design Decisions + +### 3.1. Simple vs. Extended + +To satisfy both lightweight and complex needs, two interfaces are provided: + +- `SimpleValidatorInterface` — exposes only `isValid(mixed $value): bool`. Suitable for basic needs (is it a valid phone? email? int in range?...) and maximizing performance. +- `ExtendedValidatorInterface` — exposes `validate(mixed $value): ValidatorResponseInterface`, for structured results (validation status, errors, error codes/messages/etc.). +This separation enables applications to pick the level of detail they need. Many use cases will use only the simple interface. + +### 3.2. ValidatorResponseInterface + +A response from ExtendedValidatorInterface must expose: + +- `isValid(): bool` — Was validation successful? +- `getViolations(): array` — Why did it fail, with detailed error objects. + +### 3.3. ViolationInterface + +Every violation contains: + +- Machine-readable code (for programmatic matching, i18n, etc.). +- Human-readable message (for fallback user feedback). +- Optionally: parameters for message templates, offending value, etc. + Spec only mandates code and message; implementations may extend. + +### 3.4. Exception Handling + +Validation failures (value rejected) are NOT exceptional: response returned with errors. + +Exceptions are for implementation/configuration/usage errors — not for negative validation. + +### 3.5. Swappability & DI + +Core purpose — to allow hot-swapping validator engines and compositions via DI or configuration, zero code refactor. + +### 3.6. Scope + +Only single-value validation in scope; not object/collection/nested. +Contextual validation may be layered by implementors using extensions. + +## 4. People + +### 4.1 Editor(s) + +- TBA + +### 4.2 Working Group members + +- TBA diff --git a/proposed/validator.md b/proposed/validator.md new file mode 100644 index 000000000..02a279169 --- /dev/null +++ b/proposed/validator.md @@ -0,0 +1,144 @@ +Validator PSR: Specification Draft +================================== + +This document describes common interfaces to validate values in PHP, in both simple and structured modes. + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", +"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be +interpreted as described in [RFC 2119][]. + +The final implementations MAY decorate the objects with more +functionality than the one proposed but they MUST implement the indicated +interfaces/functionality first. + +[RFC 2119]: http://tools.ietf.org/html/rfc2119 + +## 1. Specification + +### 1.1. Definitions + +- Validation: Process of checking if input value satisfies certain constraints (type, format, range, etc.). +- Violation: Individual reason why a value fails validation (error). +- Error Code: Machine-readable string/code for a validation failure, suitable for mapping, i18n or programmatic branching. + +## 2. Interfaces + +### 2.1. SimpleValidatorInterface + +```php +namespace Psr\Validator; + +/** + * Minimalistic validator interface. + */ +interface SimpleValidatorInterface +{ + /** + * Validates supplied value. + * MUST return true if $value passes. + * MUST return false if $value fails. + * MUST NOT throw exceptions if $value fails. + * SHOULD throw ValidatorException if the Validator itself could not tell if the value passes or not (e.g. Validator misconfigured) + * + * @param mixed $value + * + * @throws ValidatorException + * + * @return bool + */ + public function isValid(mixed $value): bool; +} +``` + +## 2.2. ExtendedValidatorInterface + +```php +namespace Psr\Validator; + +/** + * Extended validator interface returning structured response. + */ +interface ExtendedValidatorInterface +{ + /** + * Validates supplied value and returns a ValidatorResponseInterface instance. + * MUST return ValidatorResponseInterface if $value was validated at all (with any result). + * MUST NOT throw exceptions if $value fails. + * SHOULD throw ValidatorException if the Validator itself could not tell if the value passes or not (e.g. Validator misconfigured) + * + * @param mixed $value + * + * @throws ValidatorException + * + * @return ValidatorResponseInterface + */ + public function validate(mixed $value): ValidatorResponseInterface; +} +``` + +## 2.3. ValidatorResponseInterface + +```php +namespace Psr\Validator; + +/** + * Wraps the result of validation including status and violations list. + */ +interface ValidatorResponseInterface +{ + /** + * MUST return true if $value passed, and false otherwise. + * MUST be immutable. + * + * @return bool + */ + public function isValid(): bool; + + /** + * Returns all violations (validation errors) as ViolationInterface objects. + * + * @return ViolationInterface[] + */ + public function getViolations(): array; +} +``` + +## 2.4. ViolationInterface + +```php +namespace Psr\Validator; + +/** + * A single validation violation. + */ +interface ViolationInterface +{ + /** + * Machine-readable error code (for mapping, i18n, client logic). + * + * @return string + */ + public function getCode(): string; + + /** + * Error message (human-readable, MAY be locale-dependent). + * + * @return string + */ + public function getMessage(): string; +} +``` + +## 2.5. ValidatorException + +```php +namespace Psr\Validator; + +/** + * Thrown ONLY if validator is misconfigured or cannot process request. + * MUST NOT be thrown if $value was actually tested, no matter the result. + */ +class ValidatorException extends \InvalidArgumentException +{ +} +``` From 6284964bf1281968eaedc9bfb88c6199e9451e40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=BB=D1=8C=D1=8F=20=D0=A1=D0=B0=D0=BB=D0=B8=D0=B3?= =?UTF-8?q?=D0=B6=D0=B0=D0=BD=D0=BE=D0=B2?= Date: Tue, 22 Jul 2025 19:53:24 +0500 Subject: [PATCH 2/2] docs: Swappability & DI clarified, Exception now interface --- proposed/validator-meta.md | 4 +++- proposed/validator.md | 6 +----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/proposed/validator-meta.md b/proposed/validator-meta.md index 002f39ea8..e1cbe9e04 100644 --- a/proposed/validator-meta.md +++ b/proposed/validator-meta.md @@ -67,7 +67,9 @@ Exceptions are for implementation/configuration/usage errors — not for negativ ### 3.5. Swappability & DI -Core purpose — to allow hot-swapping validator engines and compositions via DI or configuration, zero code refactor. +Core purpose — to make validation logic universally pluggable and reusable, in both applications and stand-alone +libraries, with no forced dependency on any particular framework or DI mechanism, and with zero need for code changes +when switching validator implementations. ### 3.6. Scope diff --git a/proposed/validator.md b/proposed/validator.md index 02a279169..f14b51d35 100644 --- a/proposed/validator.md +++ b/proposed/validator.md @@ -7,10 +7,6 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC 2119][]. -The final implementations MAY decorate the objects with more -functionality than the one proposed but they MUST implement the indicated -interfaces/functionality first. - [RFC 2119]: http://tools.ietf.org/html/rfc2119 ## 1. Specification @@ -138,7 +134,7 @@ namespace Psr\Validator; * Thrown ONLY if validator is misconfigured or cannot process request. * MUST NOT be thrown if $value was actually tested, no matter the result. */ -class ValidatorException extends \InvalidArgumentException +interface ValidatorException { } ```