PHP code example of elie29 / validator

1. Go to this page and download the library: Download elie29/validator library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

elie29 / validator example snippets




use Elie\Validator\Rule\EmailRule;
use Elie\Validator\Rule\MultipleAndRule;
use Elie\Validator\Rule\NumericRule;
use Elie\Validator\Rule\RangeRule;
use Elie\Validator\Rule\StringRule;
use Elie\Validator\Validator;

/**
 * A key could have multiple rules
 *  - name could not be empty (
    ['age', NumericRule::class, NumericRule::MAX => 60],
    ['age', RangeRule::class, RangeRule::RANGE => [30, 40, 50]],
    // Use composition instead of validating the key twice
    ['email', MultipleAndRule::class, MultipleAndRule::REQUIRED => true, MultipleAndRule::RULES => [
        [StringRule::class, StringRule::MAX => 255],
        [EmailRule::class],
    ]],
];

$validator = new Validator($_POST, $rules, true); // stop processing on error.

if ($validator->validate()) {
    // Validation passed - use validated context
    $validatedData = $validator->getValidatedContext();
    // Process $validatedData safely
} else {
    // Validation failed - handle errors
    $errors = $validator->getErrors(); // array of error messages
    // or get formatted string:
    echo $validator->getImplodedErrors(); // errors separated by <br/>
}

use Elie\Validator\Validator;
use Elie\Validator\Rule\{EmailRule, StringRule, NumericRule};

// Validate a contact form
$rules = [
    ['name', StringRule::class, StringRule::MIN => 2, StringRule::MAX => 100, StringRule::REQUIRED => true],
    ['email', EmailRule::class, EmailRule::REQUIRED => true],
    ['age', NumericRule::class, NumericRule::MIN => 18, NumericRule::MAX => 120],
    ['message', StringRule::class, StringRule::MIN => 10, StringRule::MAX => 1000],
];

$validator = new Validator($_POST, $rules);

if ($validator->validate()) {
    $data = $validator->getValidatedContext();
    // All values are trimmed by default and validated
    sendEmail($data['email'], $data['name'], $data['message']);
} else {
    // Display all errors to user
    foreach ($validator->getErrors() as $error) {
        echo "<p class='error'>$error</p>";
    }
}

use Elie\Validator\Validator;
use Elie\Validator\Rule\{ChoicesRule, BooleanRule, NumericRule};

// Validate API query parameters
$rules = [
    ['page', NumericRule::class, NumericRule::MIN => 1, NumericRule::CAST => true],
    ['limit', NumericRule::class, NumericRule::MIN => 1, NumericRule::MAX => 100, NumericRule::CAST => true],
    ['sort', ChoicesRule::class, ChoicesRule::LIST => ['asc', 'desc']],
    ['active', BooleanRule::class, BooleanRule::CAST => true],
];

$validator = new Validator($_GET, $rules);
$validator->appendExistingItemsOnly(true); // Don't 

// Fields that aren't name', StringRule::class, StringRule::MIN => 3, StringRule::REQUIRED => true],
    ['bio', StringRule::class, StringRule::MAX => 500], // Optional, only validated if provided
    ['website', EmailRule::class], // Optional URL field
];

$validator = new Validator($data, $rules);
$validator->appendExistingItemsOnly(true); // Exclude missing optional fields from output

if ($validator->validate()) {
    $validatedData = $validator->getValidatedContext();
    // $validatedData only contains 'username' and any optional fields that were provided
}

use Elie\Validator\Rule\{MultipleOrRule, EmailRule, MatchRule};

// Accept either email OR phone number
$rules = [
    ['contact', MultipleOrRule::class, MultipleOrRule::REQUIRED => true, MultipleOrRule::RULES => [
        [EmailRule::class],
        [MatchRule::class, MatchRule::PATTERN => '/^\+?[1-9]\d{1,14}$/'], // E.164 phone format
    ]],
];

$validator = new Validator(['contact' => '[email protected]'], $rules);
$validator->validate(); // true - email is valid

$validator->setContext(['contact' => '+1234567890']);
$validator->validate(); // true - phone is valid

use Elie\Validator\Rule\{StringRule, RuleInterface};

$rules = [
    ['username', StringRule::class, 
        StringRule::MIN => 3,
        StringRule::MAX => 20,
        StringRule::REQUIRED => true,
        RuleInterface::MESSAGES => [
            RuleInterface::EMPTY_KEY => 'Username is  $validator->getImplodedErrors(); // "Username must be at least 3 characters"
}

// By default, all string values are trimmed
$rules = [
    ['title', StringRule::class, StringRule::MIN => 1], // Leading/trailing spaces removed
];

// To preserve whitespace:
$rules = [
    ['code', StringRule::class, StringRule::MIN => 1, 'trim' => false],
];

$validator = new Validator(['title' => '  Hello  '], $rules);
$validator->validate();
$validated = $validator->getValidatedContext();
// With trim=true (default): $validated['title'] = 'Hello'
// With trim=false: $validated['title'] = '  Hello  '

// Third parameter controls error handling behavior
$validator = new Validator($data, $rules, true); // Stops at first error
$validator->validate();

// OR set it later
$validator = new Validator($data, $rules);
$validator->setStopOnError(true);

if (!$validator->validate()) {
    // Only the first error will be in getErrors()
    $firstError = $validator->getErrors()[0];
}



use Elie\Validator\Rule\AbstractRule;

class MyValueRule extends AbstractRule
{
    public const INVALID_MY_VALUE = 'invalidMyValue';

    protected mixed $my_value = null;

    public function __construct(int|string $key, mixed $value, array $params = [])
    {
        parent::__construct($key, $value, $params);

        if (isset($params['my_value'])) {
            $this->my_value = $params['my_value'];
        }

        // + to add a non-existent key
        $this->messages += [
            $this::INVALID_MY_VALUE => '%key%: %value% my message %my_value%'
        ];
    }

    public function validate(): int
    {
        $run = parent::validate();

        if ($run !== $this::CHECK) {
            return $run;
        }

        if ($this->value !== $this->my_value) {
            return $this->setAndReturnError($this::INVALID_MY_VALUE, [
                '%my_value%' => $this->stringify($this->my_value)
            ]);
        }

        return $this::VALID;
    }
}

use Elie\Validator\Rule\{StringRule, NumericRule, BooleanRule};

$input = [
    'name' => '  John Doe  ',    // Has whitespace
    'age' => '25',               // String representation
    'active' => 'true',          // String boolean
];

$rules = [
    ['name', StringRule::class],
    ['age', NumericRule::class, NumericRule::CAST => true],
    ['active', BooleanRule::class, BooleanRule::CAST => true],
];

$validator = new Validator($input, $rules);
$validator->validate();

$validated = $validator->getValidatedContext();

// Results:
// $validated['name'] = 'John Doe'     // Trimmed
// $validated['age'] = 25              // Cast to int
// $validated['active'] = true         // Cast to bool

// Original input is unchanged:
// $input['name'] = '  John Doe  '
// $input['age'] = '25'

$input = ['username' => 'john'];

$rules = [
    ['username', StringRule::class],
    ['email', EmailRule::class], // Not in input
];

$validator = new Validator($input, $rules);
$validator->validate();

// Default behavior:
$validated = $validator->getValidatedContext();
// $validated = ['username' => 'john', 'email' => null]

// To exclude missing keys:
$validator->appendExistingItemsOnly(true);
$validator->validate();
$validated = $validator->getValidatedContext();
// $validated = ['username' => 'john']

// Example: Partial user profile update
$rules = [
    ['name', StringRule::class, StringRule::MAX => 100],
    ['bio', StringRule::class, StringRule::MAX => 500],
    ['website', StringRule::class, StringRule::MAX => 255],
];

$validator = new Validator($_POST, $rules);
$validator->appendExistingItemsOnly(true);

if ($validator->validate()) {
    $updates = $validator->getValidatedContext();
    // Only update fields that were actually submitted
    updateUserProfile($userId, $updates);
}



use Assert\Assertion;
use Elie\Validator\Rule\EmailRule;
use Elie\Validator\Rule\NumericRule;
use Elie\Validator\Rule\RuleInterface;
use Elie\Validator\Rule\StringRule;
use Elie\Validator\Validator;
use Webmozart\Assert\Assert;

$rules =[
    ['age', NumericRule::class, NumericRule::MAX => 60],
    ['name', StringRule::class, StringRule::MIN => 1, StringRule::REQUIRED => true],
    ['email', EmailRule::class, EmailRule::REQUIRED => true],
];

$validator = new Validator($_POST, $rules);

// Using webmozart/assert
Assert::true($validator->validate(), $validator->getImplodedErrors());

// OR using beberlei/assert
Assertion::true($validator->validate(), $validator->getImplodedErrors());

// OR using PHPUnit in tests
$this->assertSame(RuleInterface::VALID, $validator->validate(), $validator->getImplodedErrors());

use Elie\Validator\Rule\JsonRule;
use Elie\Validator\Rule\MatchRule;
use Elie\Validator\Rule\NumericRule;
use Elie\Validator\Validator;

$rules = [
    ['user', JsonRule::class, JsonRule::REQUIRED => true],
];

$validator = new Validator($_POST, $rules);

Assertion::true($validator->validate()); // this assertion validates that the user is in JSON format

$validatedPost = $validator->getValidatedContext();

// But we need to validate user data as well (suppose it should contain name and age):

$rules = [
    ['name', MatchRule::class, MatchRule::PATTERN => '/^[a-z]{1,20}$/i'],
    ['age', NumericRule::class, NumericRule::MAX => 80],
];
$validator->setRules($rules);

// Decode user as it is a valid JSON
$user = json_decode($validatedPost['user'], true);
$validator->setContext($user); // the new context is now user data

Assertion::true($validator->validate()); // this assertion validates user data

/*
Validate accepts a boolean argument - mergedValidatedContext - which is false by default. If set to true, 
$validator->getValidatedContext() would return:

array:4 [▼
  "email" => "[email protected]"
  "user" => "{"name": "John", "age": 25}"
  "name" => "John"
  "age" => 25
]
*/

$rules = [
    // With json-decode, a validated value will be decoded into an array
    ['users', JsonRule::class, JsonRule::REQUIRED => true, JsonRule::DECODE => true],
];

$validator = new Validator([
    'users' => '[{"name":"John","age":25},{"name":"Brad","age":42}]'
], $rules);

Assertion::true($validator->validate()); // this validates that users is a valid JSON format

// But we need to validate all user data as well (suppose it should contain name and age):
$validator->setRules([
    ['name', MatchRule::class, MatchRule::PATTERN => '/^[a-z]{1,20}$/i'],
    ['age', NumericRule::class, NumericRule::MAX => 80],
]);

$validatedContext = $validator->getValidatedContext();

$users = $validatedContext['users'];

Assertion::isArray($users);

foreach ($users as $user) {
    // each user is a new context
    $validator->setContext($user);
    // do not merge data !!
    Assertion::true($validator->validate()); // we could validate all users and determine which ones are invalid!
}


$rules = [
    ['users', CollectionRule::class, CollectionRule::JSON => true, CollectionRule::RULES => [
        ['name', MatchRule::class, MatchRule::PATTERN => '/^[a-z]{1,20}$/i'],
        ['age', NumericRule::class, NumericRule::MAX => 80],
    ]],
];

$data = [
    'users' => '[{"name":"John","age":25},{"name":"Brad","age":42}]'
];

$validator = new Validator($data, $rules);

$this->assertSame(RuleInterface::VALID, $validator->validate());

$users = $validator->getValidatedContext()['users'];

$this->assertCount(2, $users);

// ✅ CORRECT
['age', NumericRule::class, NumericRule::MIN => 18, NumericRule::MAX => 120]

// ❌ WRONG - 'min' and 'max' as strings won't work
['age', NumericRule::class, 'min' => 18, 'max' => 120]

// Recommended pattern for all validations:
$validator = new Validator($inputData, $rules);

if (!$validator->validate()) {
    // Handle errors first
    logErrors($validator->getErrors());
    return ['success' => false, 'errors' => $validator->getErrors()];
}

// Only proceed with validated data
$safeData = $validator->getValidatedContext();
processData($safeData);

$validator = new Validator([], $userRules);

foreach ($batchData as $userData) {
    $validator->setContext($userData);
    
    if ($validator->validate()) {
        processUser($validator->getValidatedContext());
    } else {
        logErrors($userData['id'], $validator->getErrors());
    }
}

// When rules must ALL pass, use MultipleAndRule:
['email', MultipleAndRule::class, MultipleAndRule::RULES => [
    [StringRule::class, StringRule::MAX => 255],
    [EmailRule::class],
]]

// When ANY rule can pass, use MultipleOrRule:
['identifier', MultipleOrRule::class, MultipleOrRule::RULES => [
    [EmailRule::class],
    [MatchRule::class, MatchRule::PATTERN => '/^\d{10}$/'], // 10-digit ID
]]

// Avoid chaining the same key twice - use composition instead:
// ❌ Less efficient:
['email', StringRule::class, StringRule::MAX => 255],
['email', EmailRule::class],

// ✅ Better - uses composition:
['email', MultipleAndRule::class, MultipleAndRule::RULES => [
    [StringRule::class, StringRule::MAX => 255],
    [EmailRule::class],
]]

use PHPUnit\Framework\TestCase;
use Elie\Validator\Rule\RuleInterface;

class UserValidatorTest extends TestCase
{
    public function testValidUserData(): void
    {
        $validator = new Validator(
            ['username' => 'john', 'age' => 25],
            $this->getUserRules()
        );
        
        $this->assertTrue($validator->validate());
        $this->assertEmpty($validator->getErrors());
    }
    
    public function testInvalidAge(): void
    {
        $validator = new Validator(
            ['username' => 'john', 'age' => 150],
            $this->getUserRules()
        );
        
        $this->assertFalse($validator->validate());
        $this->assertNotEmpty($validator->getErrors());
        $this->assertStringContainsString('age', $validator->getImplodedErrors());
    }
}