diff --git a/proposed/validator-meta.md b/proposed/validator-meta.md new file mode 100644 index 000000000..e1cbe9e04 --- /dev/null +++ b/proposed/validator-meta.md @@ -0,0 +1,87 @@ +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 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 + +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..f14b51d35 --- /dev/null +++ b/proposed/validator.md @@ -0,0 +1,140 @@ +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][]. + +[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. + */ +interface ValidatorException +{ +} +```