gravity / dataverify
A lightweight PHP validation library with fluent interface for validating data structures, supporting batch/fail-fast modes and custom strategies
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 1
Forks: 0
Open Issues: 0
pkg:composer/gravity/dataverify
Requires
- php: >=8.1
Requires (Dev)
- infection/infection: ^0.31
- phpbench/phpbench: ^1.4
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^11.4
- symfony/yaml: ^8.0
Suggests
- symfony/yaml: ^7.0 - Required for YAML translation files
This package is auto-updated.
Last update: 2025-12-28 18:16:41 UTC
README
A fluent, zero-dependency PHP validation library.
composer require gravity/dataverify
Quick Start
use Gravity\DataVerify; $data = (object)[ 'email' => 'user@example.com', 'age' => 25 ]; $dv = new DataVerify($data); $dv ->field('email')->required->email ->field('age')->required->int->between(18, 100); if (!$dv->verify()) { print_r($dv->getErrors()); }
Key Features
Fluent validation
$dv->field('email')->required->email->maxLength(100);
Nested objects
$dv->field('user')->required->object ->subfield('name')->required->string ->subfield('email')->required->email;
Conditional validation
$dv->field('vat_number') ->when('country', '=', 'FR') ->then->required->regex('/^FR\d{11}$/');
Custom strategies
class SiretStrategy extends ValidationStrategy { public function getName(): string { return 'siret'; } protected function handler(mixed $value): bool { /* validation logic */ } } DataVerify::global()->register(new SiretStrategy()); $dv->field('siret')->siret; // Available everywhere
Use Cases
REST APIs & Web Services
Perfect for validating incoming API requests with conditional logic:
// POST /api/users/register $data = json_decode(file_get_contents('php://input')); $dv = new DataVerify($data); $dv ->field('email')->required->email->disposableEmail ->field('password')->required->minLength(8) ->containsUpper->containsNumber->containsSpecialCharacter ->field('company_name') ->when('account_type', '=', 'business') ->then->required->string->minLength(2) ->field('vat_number') ->when('account_type', '=', 'business') ->and('country', 'in', ['FR', 'BE', 'DE']) ->then->required->regex('/^[A-Z]{2}\d{9,12}$/'); if (!$dv->verify(batch: false)) { // Fail-fast for better performance http_response_code(400); echo json_encode(['errors' => $dv->getErrors()]); exit; }
Form Validation (WordPress, PrestaShop, Laravel)
Validate complex forms with dependent fields:
// E-commerce checkout form $dv = new DataVerify($_POST); $dv ->field('shipping_method')->required->in(['standard', 'express', 'pickup']) ->field('shipping_address') ->when('shipping_method', '!=', 'pickup') ->then->required->string->minLength(10) ->field('shipping_city') ->when('shipping_method', '!=', 'pickup') ->then->required->string ->field('pickup_store') ->when('shipping_method', '=', 'pickup') ->then->required->string ->field('gift_message') ->when('is_gift', '=', true) ->then->required->maxLength(500); if (!$dv->verify()) { // Display errors in form foreach ($dv->getErrors() as $error) { echo "<p class='error'>{$error['message']}</p>"; } }
Data Processing Pipelines
Validate batches of data with fail-fast for early termination:
// Process CSV import with 10,000 rows foreach ($csvRows as $row) { $dv = new DataVerify($row); $dv ->field('sku')->required->alphanumeric ->field('price')->required->numeric->greaterThan(0) ->field('stock')->int->between(0, 99999); if (!$dv->verify(batch: false)) { // Stop at first error per row $failedRows[] = ['row' => $row, 'errors' => $dv->getErrors()]; continue; // Skip invalid row } // Process valid row... }
Conditional Business Rules
Complex validation logic based on multiple conditions:
// SaaS subscription validation $dv = new DataVerify($subscription); $dv ->field('plan')->required->in(['free', 'pro', 'enterprise']) ->field('payment_method') ->when('plan', '!=', 'free') ->then->required->in(['card', 'invoice']) ->field('card_number') ->when('plan', '!=', 'free') ->and('payment_method', '=', 'card') ->then->required->regex('/^\d{16}$/') ->field('billing_email') ->when('plan', '=', 'enterprise') ->or('payment_method', '=', 'invoice') ->then->required->email ->field('seats') ->when('plan', 'in', ['pro', 'enterprise']) ->then->required->int->between(1, 1000);
Multi-language Applications
Built-in i18n with automatic locale detection:
$dv = new DataVerify($data); $dv->setLocale('fr'); // Built-in: EN, FR $dv->field('email')->required->email; if (!$dv->verify()) { // Error message in French: // "Le champ email doit être une adresse email valide" echo $dv->getErrors()[0]['message']; } // Add custom translations $dv->addTranslations([ 'validation.siret' => 'El campo {field} debe ser un SIRET válido' ], 'es');
Why DataVerify?
- ✅ Zero dependencies - Pure PHP 8.1+, no vendor bloat
- ✅ Fluent API - Readable, chainable validations
- ✅ Extensible - Custom strategies with auto-documentation
- ✅ Fast - ~50μs simple validation, ~4.9MB memory (benchmarks)
- ✅ i18n ready - Built-in translation support (EN, FR)
- ✅ Framework agnostic - Works with WordPress, Laravel, Symfony, vanilla PHP
- ✅ Production tested - 346 tests, 72% mutation score
Documentation
Guides:
- Conditional Validation -
when/and/or/thensyntax - Custom Strategies - Extend with your own rules
- Internationalization - Multi-language error messages
- Error Handling - Working with validation errors
- Validation Rules - All 40+ built-in rules
Examples:
- API Request Validation
- Basic Usage
- Conditional Validation
- Custom Validation Rules
- Translation (PHP)
- Translation (YAML)
Performance
DataVerify is designed for production with predictable sub-millisecond performance:
Simple validation: ~50μs (99% < 50μs)
Complex nested: ~72μs (99% < 72μs)
Batch mode (100 fields): 1.5ms
Fail-fast (100 fields): 0.7ms (2x faster)
Memory usage: ~4.9MB (stable)
See: Full benchmarks
Compatibility
| Platform | Status | Notes |
|---|---|---|
| PHP 8.1+ | ✅ Required | Minimum version |
| WordPress 6.0+ | ✅ Compatible | Use in plugins/themes |
| PrestaShop 8.0+ | ✅ Excellent fit | Native Composer support |
| Laravel/Symfony | ✅ Compatible | Use as alternative validator |
| Moodle 4.3+ | ⚠️ Partial | Best for webservices/APIs |
Examples
Basic validation
$dv = new DataVerify($data); $dv ->field('name')->required->string->minLength(3) ->field('email')->required->email ->field('age')->int->between(18, 120); if (!$dv->verify()) { print_r($dv->getErrors()); }
Batch vs fail-fast
$dv->verify(); // Batch mode: all errors $dv->verify(batch: false); // Fail-fast: first error only (2x faster)
Optional fields
$dv->field('phone')->string; // Optional: null OK, if present must be valid $dv->field('email')->required->email; // Required: must exist AND be valid
Custom error messages
$dv->field('password') ->required ->minLength(8)->errorMessage('Password too weak - min 8 characters') ->containsUpper->errorMessage('Password must include uppercase letters');
Nested validation
// Simple object nesting $dv->field('user')->required->object ->subfield('profile')->required->object ->subfield('address')->required->object ->subfield('city')->required->string ->subfield('country')->required->string; // Deep array nesting with indices // Validates: data.orders[0].items[2].name $dv->field('orders')->required->array ->subfield('0', 'items', '2', 'name')->required->string->minLength(3); // Complex nested structures (arrays + objects) // Validates: data.warehouses[0].inventory[1].product.sku $dv->field('warehouses')->required->array ->subfield('0', 'inventory', '1', 'product', 'sku')->required->alphanumeric ->subfield('0', 'inventory', '1', 'product', 'stock')->required->int->between(0, 9999);
FAQ
Is sanitization included?
No. DataVerify validates data but does NOT sanitize it. Always sanitize user input before validation:
$data->email = filter_input(INPUT_POST, 'email', FILTER_SANITIZE_EMAIL); $data->name = htmlspecialchars($_POST['name'], ENT_QUOTES, 'UTF-8'); $dv = new DataVerify($data); $dv->field('email')->required->email;
Can I reuse a DataVerify instance?
No. Each validation requires a new instance to prevent state corruption:
// ✅ Correct foreach ($users as $user) { $dv = new DataVerify($user); // New instance $dv->field('email')->required->email; $dv->verify(); } // ❌ Wrong - throws LogicException $dv = new DataVerify($user1); $dv->verify(); $dv->verify(); // Error: already verified
How do I validate arrays of items?
Loop and validate each item individually:
foreach ($data->items as $item) { $dv = new DataVerify($item); $dv->field('sku')->required->alphanumeric ->field('qty')->required->int->between(1, 100); if (!$dv->verify()) { $errors[] = $dv->getErrors(); } }
Contributing
Contributions welcome! Please see CONTRIBUTING.md for guidelines.
Changelog
See CHANGELOG.md for version history.
License
MIT License - see LICENSE file for details.
Made with ❤️ by Romain Feregotto