Validation
Learn how to validate Dtos using automatic rule inferring and validation attributes.
What is Validation?
Section titled “What is Validation?”Validation ensures that data meets specific requirements before being processed. SimpleDto provides:
- Automatic rule inferring from types and attributes
- 30+ validation attributes
- Framework integration (Laravel, Symfony)
- Custom validation rules
- Validation caching (198x faster)
Quick Start
Section titled “Quick Start”Basic Validation
Section titled “Basic Validation”use event4u\DataHelpers\SimpleDto;use event4u\DataHelpers\SimpleDto\Attributes\Required;use event4u\DataHelpers\SimpleDto\Attributes\Email;use event4u\DataHelpers\SimpleDto\Attributes\Between;use event4u\DataHelpers\SimpleDto\Enums\SerializationFormat;
class UserDto extends SimpleDto{ public function __construct( #[Required] public readonly string $name,
#[Required, Email] public readonly string $email,
#[Required, Between(18, 120)] public readonly int $age, ) {}}
// Validate and create from array (default)$dto = UserDto::validateAndCreate([ 'name' => 'John Doe', 'email' => 'john@example.com', 'age' => 30,]);
// Validate and create from JSON$dto = UserDto::validateAndCreate($jsonString, SerializationFormat::Json);
// Validate and create from XML$dto = UserDto::validateAndCreate($xmlString, SerializationFormat::Xml);Handling Validation Errors
Section titled “Handling Validation Errors”use event4u\DataHelpers\SimpleDto\Exceptions\ValidationException;
try { $dto = UserDto::validateAndCreate([ 'name' => '', // ❌ Required 'email' => 'invalid', // ❌ Invalid email 'age' => 15, // ❌ Too young ]);} catch (ValidationException $e) { echo $e->getMessage(); print_r($e->errors());}On-Demand Validation
Section titled “On-Demand Validation”For maximum performance, create DTOs without validation and validate later when needed:
// Create DTO without validation (ultra-fast)$dto = UserDto::fromArray([ 'name' => 'John Doe', 'email' => 'invalid-email', 'age' => 15,]);
// Validate later (throws ValidationException on error)$dto->validateInstance();
// Or validate without throwing exception$isValid = $dto->validateInstance(false);
if (!$isValid) { $errors = $dto->getValidationErrors();
// Check if field has errors if ($errors->has('email')) { echo $errors->first('email'); // Get first error message }
// Get all errors for a field $emailErrors = $errors->get('email');
// Get all fields with errors $fields = $errors->fields(); // ['email', 'age']
// Get all error messages $messages = $errors->messages();
// Count errors $errorCount = $errors->count(); // Number of fields with errors $messageCount = $errors->countMessages(); // Total number of messages}
// Check validation state$dto->isValidated(); // true/false - has validation been run?$dto->isValid(); // true/false/null - is DTO valid? (null if not validated yet)Benefits of On-Demand Validation:
- ✅ Ultra-fast DTO creation (~1.5μs with UltraFast mode)
- ✅ Validate only when needed (e.g., before saving to database)
- ✅ Flexible error handling (throw exception or return bool)
- ✅ Rich error API (ValidationErrorCollection with convenient methods)
Validation Attributes
Section titled “Validation Attributes”Required Validation
Section titled “Required Validation”use event4u\DataHelpers\SimpleDto\Attributes\Required;
class UserDto extends SimpleDto{ public function __construct( #[Required] public readonly string $name,
#[Required] public readonly string $email,
// Optional - no Required attribute public readonly ?string $phone = null, ) {}}String Validation
Section titled “String Validation”use event4u\DataHelpers\SimpleDto\Attributes\StringType;use event4u\DataHelpers\SimpleDto\Attributes\Min;use event4u\DataHelpers\SimpleDto\Attributes\Max;use event4u\DataHelpers\SimpleDto\Attributes\Between;
class PostDto extends SimpleDto{ public function __construct( #[Required, StringType, Min(3)] public readonly string $title,
#[Required, StringType, Between(10, 1000)] public readonly string $content,
#[StringType, Max(100)] public readonly ?string $excerpt = null, ) {}}Numeric Validation
Section titled “Numeric Validation”use event4u\DataHelpers\SimpleDto\Attributes\IntegerType;use event4u\DataHelpers\SimpleDto\Attributes\Numeric;use event4u\DataHelpers\SimpleDto\Attributes\Min;use event4u\DataHelpers\SimpleDto\Attributes\Max;
class ProductDto extends SimpleDto{ public function __construct( #[Required, IntegerType, Min(1)] public readonly int $quantity,
#[Required, Numeric, Min(0)] public readonly float $price,
#[IntegerType, Between(0, 100)] public readonly ?int $discount = null, ) {}}Email Validation
Section titled “Email Validation”use event4u\DataHelpers\SimpleDto\Attributes\Email;
class ContactDto extends SimpleDto{ public function __construct( #[Required, Email] public readonly string $email,
#[Email] public readonly ?string $alternativeEmail = null, ) {}}URL Validation
Section titled “URL Validation”use event4u\DataHelpers\SimpleDto\Attributes\Url;
class WebsiteDto extends SimpleDto{ public function __construct( #[Required, Url] public readonly string $website,
#[Url] public readonly ?string $blog = null, ) {}}Length Validation
Section titled “Length Validation”Validate length (maximum or range) for strings, numbers, and arrays. Perfect for database column types like varchar(10) or int(3).
Syntax:
- One parameter: Maximum length (0 to $max)
- Two parameters: Length range ($min to $max)
use event4u\DataHelpers\SimpleDto\Attributes\Length;
class ProductDto extends SimpleDto{ public function __construct( // Maximum length (0 to max) #[Required, Length(10)] public readonly string $name, // varchar(10) - 0-10 characters
#[Required, Length(3)] public readonly int $countryCode, // int(3) - 0-3 digits
// Length range (min to max) #[Required, Length(3, 10)] public readonly string $username, // 3-10 characters
#[Required, Length(1, 3)] public readonly int $code, // 1-3 digits
// Array length #[Length(5)] public readonly ?array $tags = null, // 0-5 items ) {}}
// Valid examples$dto = ProductDto::validateAndCreate([ 'name' => 'Product', // ✅ 7 characters (0-10) 'countryCode' => 123, // ✅ 3 digits (0-3) 'username' => 'john', // ✅ 4 characters (3-10) 'code' => 12, // ✅ 2 digits (1-3) 'tags' => ['a', 'b'], // ✅ 2 items (0-5)]);
// Invalid examples$dto = ProductDto::validateAndCreate([ 'name' => 'Very Long Product Name', // ❌ Too long (>10 characters) 'countryCode' => 1234, // ❌ Too many digits (>3) 'username' => 'ab', // ❌ Too short (<3 characters) 'code' => 1234, // ❌ Too many digits (>3) 'tags' => ['a', 'b', 'c', 'd', 'e', 'f'], // ❌ Too many items (>5)]);Validation Rules:
- Strings: Character length (using
mb_strlen) - Numbers: Number of digits (e.g.,
123= 3 digits,-999= 3 digits) - Arrays: Number of items
- Null values: Always pass (use
#[Required]for mandatory fields)
Custom Error Messages:
#[Length(10, message: 'Name must be at most 10 characters')]public readonly string $name;
#[Length(3, 10, message: 'Username must be between 3 and 10 characters')]public readonly string $username;All Validation Attributes
Section titled “All Validation Attributes”| Attribute | Description | Example |
|---|---|---|
Required | Field is required | #[Required] |
Email | Valid email address | #[Email] |
Url | Valid URL | #[Url] |
Length | Maximum or range length | #[Length(10)] or #[Length(3, 10)] |
Min | Minimum value/length | #[Min(3)] |
Max | Maximum value/length | #[Max(100)] |
Between | Value between min and max | #[Between(18, 120)] |
StringType | Must be string | #[StringType] |
IntegerType | Must be integer | #[IntegerType] |
Numeric | Must be numeric | #[Numeric] |
BooleanType | Must be boolean | #[BooleanType] |
ArrayType | Must be array | #[ArrayType] |
In | Value in list | #[In(['active', 'inactive'])] |
NotIn | Value not in list | #[NotIn(['banned'])] |
Regex | Matches regex | #[Regex('/^[A-Z]/')] |
Alpha | Only letters | #[Alpha] |
AlphaNum | Letters and numbers | #[AlphaNum] |
AlphaDash | Letters, numbers, dashes | #[AlphaDash] |
Uuid | Valid UUID | #[Uuid] |
Json | Valid JSON | #[Json] |
Date | Valid date | #[Date] |
DateFormat | Date in format | #[DateFormat('Y-m-d')] |
Before | Date before | #[Before('2024-12-31')] |
After | Date after | #[After('2024-01-01')] |
Ip | Valid IP address | #[Ip] |
Ipv4 | Valid IPv4 | #[Ipv4] |
Ipv6 | Valid IPv6 | #[Ipv6] |
MacAddress | Valid MAC address | #[MacAddress] |
Timezone | Valid timezone | #[Timezone] |
Unique | Unique in database | #[Unique('users', 'email')] |
Exists | Exists in database | #[Exists('users', 'id')] |
Custom Validation
Section titled “Custom Validation”Creating Custom Validator
Section titled “Creating Custom Validator”use event4u\DataHelpers\SimpleDto\Contracts\ValidationRule;
class EvenNumber implements ValidationRule{ public function passes(mixed $value): bool { return is_int($value) && $value % 2 === 0; }
public function message(): string { return 'The value must be an even number.'; }}
class NumberDto extends SimpleDto{ public function __construct( #[EvenNumber] public readonly int $number, ) {}}Framework Integration
Section titled “Framework Integration”Laravel Validation
Section titled “Laravel Validation”// Automatic Laravel validationclass UserController extends Controller{ public function store(Request $request) { $dto = UserDto::validateAndCreate($request->all()); // Automatically uses Laravel's validator }}Symfony Validation
Section titled “Symfony Validation”// Automatic Symfony validationclass UserController{ public function store(Request $request) { $dto = UserDto::validateAndCreate($request->request->all()); // Automatically uses Symfony's validator }}Validation Caching
Section titled “Validation Caching”SimpleDto caches validation rules for 198x faster performance:
// First call - builds and caches rules$dto1 = UserDto::validateAndCreate($data1); // ~10ms
// Subsequent calls - uses cached rules$dto2 = UserDto::validateAndCreate($data2); // ~0.05ms (198x faster!)Best Practices
Section titled “Best Practices”Combine Multiple Attributes
Section titled “Combine Multiple Attributes”// ✅ Good - multiple validation rules#[Required, StringType, Min(3), Max(50), Alpha]public readonly string $name;Use Type Hints with Validation
Section titled “Use Type Hints with Validation”// ✅ Good - type hint + validation#[Required, Between(18, 120)]public readonly int $age;
// ❌ Bad - no type hint#[Required, Between(18, 120)]public readonly $age;Validate Early
Section titled “Validate Early”// ✅ Good - validate at creation$dto = UserDto::validateAndCreate($data);
// ❌ Bad - create then validate$dto = UserDto::fromArray($data);$dto->validate();Code Examples
Section titled “Code Examples”The following working examples demonstrate this feature:
- Basic Validation - Simple validation rules
- Advanced Validation - Complex validation scenarios
- Request Validation Core - Core request validation
- Laravel Validation - Laravel integration
- Symfony Validation - Symfony integration
- Validation Modes - Different validation modes
- Nested Validation - Validating nested Dtos
All examples are fully tested and can be run directly.
Related Tests
Section titled “Related Tests”The functionality is thoroughly tested. Key test files:
- ValidationModesTest.php - Validation mode tests
- ValidationTest.php - Core validation tests
- NestedValidationTest.php - Nested validation tests
Run the tests:
# Run teststask test:unit -- --filter=ValidationSee Also
Section titled “See Also”- Type Casting - Automatic type conversion
- Creating Dtos - Creation methods
- Property Mapping - Map property names