PHP – Create your own Data Validator in PHP: Step-by-Step

php-–-create-your-own-data-validator-in-php:-step-by-step

How to Create Your Own Data Validator in PHP

In this tutorial, I will teach you how to create a custom data validator in PHP by building our own validation library step by step. Data validators are essential tools for any developer who needs to ensure that user-submitted data is valid and secure. By the end of this tutorial, you will have a solid understanding of how to create custom data validators in PHP, which will allow you to better handle user inputs and ensure the security of your applications.

Step 1 : Creating the Validation Class

The first step is to create a class that will handle the validation. This class should be able to store the validation rules for each field that we want to validate, as well as validate those rules when called.

Here is an example of a simple validation class:



namespace DevCoderValidator;

use DevCoderValidatorAssertValidatorInterface;
use InvalidArgumentException;
use function get_class;
use function gettype;
use function is_array;
use function is_object;
use function sprintf;

class Validation
{
    /**
     * @var array
     */
    private $validators;

    /**
     * @var array
     */
    private $errors = [];

    /**
     * @var array
     */
    private $data = [];

    public function __construct(array $fieldValidators)
    {
        foreach ($fieldValidators as $field => $validators) {
            if (!is_array($validators)) {
                $validators = [$validators];
            }
            $this->addValidator($field, $validators);
        }
    }

    public function validate(array $data): bool
    {
        $this->data = $data;

        /**
         * @var $validators array
         */
        foreach ($this->validators as $field => $validators) {
            if (!isset($this->data[$field])) {
                $this->data[$field] = null;
            }

            foreach ($validators as $validator) {
                if ($validator->validate($this->data[$field]) === false) {
                    $this->addError($field, (string)$validator->getError());
                }
            }

        }
        return $this->getErrors() === [];
    }

    /**
     * @return array
     */
    public function getErrors(): array
    {
        return $this->errors;
    }

    /**
     * @return array
     */
    public function getData(): array
    {
        return $this->data;
    }

    private function addError(string $field, string $message): void
    {
        $this->errors[$field][] = $message;
    }

    /**
     * @param string $field
     * @param array $validators
     * @return void
     */
    private function addValidator(string $field, array $validators): void
    {
        foreach ($validators as $validator) {
            if (!$validator instanceof ValidatorInterface) {
                throw new InvalidArgumentException(sprintf(
                    $field . ' validator must be an instance of ValidatorInterface, "%s" given.',
                    is_object($validator) ? get_class($validator) : gettype($validator)
                ));
            }

            $this->validators[$field][] = $validator;
        }
    }
}

Step 2: Creating rule classes for data validation

Now that we have created the Validator class, the next step is to create our own validation rules. These rules will be used to check if the submitted data is valid or not. We will create them in separate files, one for each validation rule. Each validation rule file should contain a class named after the rule it implements. For example, if we have a validation rule to check if a value is an integer, we will name the class Integer.

ValidatorInterface



namespace DevCoderValidatorAssert;

interface ValidatorInterface
{
    public function validate($value): bool;
    public function getError(): ?string;
}

AbstractValidator



namespace DevCoderValidatorAssert;

abstract class AbstractValidator implements ValidatorInterface
{
    /**
     * @var string|null
     */
    protected $error;

    public function getError(): ?string
    {
        return $this->error;
    }

    protected function error(string $message, array $context): void
    {
        $replace = [];
        foreach ($context as $key => $value) {
            if (is_object($value)) {
                $value = method_exists($value, '__toString') ? (string)$value : get_class($value);
            } elseif (is_array($value)) {
                $value = json_encode($value);
            } else {
                $value = (string)$value;
            }
            $replace['{{ ' . $key . ' }}'] = $value;
        }

        $this->error = strtr($message, $replace);
    }
}

Integer



declare(strict_types=1);

namespace DevCoderValidatorAssert;

use function ctype_digit;
use function is_int;
use function strval;

class Integer extends AbstractValidator
{
    /**
     * @var string
     */
    private $invalidMessage = 'This value should be of type {{ type }}.';
    private $minMessage = '{{ value }} should be {{ limit }} or more.';
    private $maxMessage = '{{ value }} should be {{ limit }} or less.';

    /**
     * @var int|null
     */
    private $min;
    /**
     * @var int|null
     */
    private $max;

    public function validate($value): bool
    {
        if ($value === null) {
            return true;
        }

        if (ctype_digit(strval($value)) === false) {
            $this->error($this->invalidMessage, ['value' => $value, 'type' => 'integer']);
            return false;
        }

        if (is_int($this->min) && $value < $this->min) {
            $this->error($this->minMessage, ['value' => $value, 'limit' => $this->min]);
            return false;
        }

        if (is_int($this->max) && $value > $this->max) {
            $this->error($this->maxMessage, ['value' => $value, 'limit' => $this->max]);
            return false;
        }

        return true;
    }

    public function invalidMessage(string $invalidMessage): self
    {
        $this->invalidMessage = $invalidMessage;
        return $this;
    }

    public function minMessage(string $minMessage): self
    {
        $this->minMessage = $minMessage;
        return $this;
    }

    public function maxMessage(string $maxMessage): self
    {
        $this->maxMessage = $maxMessage;
        return $this;
    }

    public function min(int $min): self
    {
        $this->min = $min;
        return $this;
    }

    public function max(int $max): self
    {
        $this->max = $max;
        return $this;
    }
}

NotNull



declare(strict_types=1);

namespace DevCoderValidatorAssert;

class NotNull extends AbstractValidator
{
    private $message = 'This value should not be null.';

    public function validate($value): bool
    {
        if ($value === null) {
            $this->error($this->message, ['value' => $value]);
            return false;
        }

        return true;
    }

    public function message(string $message): self
    {
        $this->message = $message;
        return $this;
    }
}

Step 3: Creating an instance of the Validation class

This object takes an array of validation options as input. The keys of the array are the names of the fields and the values are arrays of validators.


$validation = new Validator([
    'age' => [(new Integer())->min(18)->max(99), new NotNull()],
    'number_of_children' => [new NotNull(), new Integer()],
    'salary' => [new NotNull(), new Integer()],
]);

Step 4: Data Validation

Once you have created an instance of the Validation class, you can validate the data by calling the validate() method of the Validation class. This method will return true if all validation rules are satisfied and false otherwise.



if ($validation->validate($_POST) === true) {
    $data = $validation->getData();
    // save in database
    // redirect in another page
}

return render('template.html.php', [
    'errors' => $validation->getErrors()
]);

Example of other rules that can be added

$validation = new Validation([
    'email' => [new NotNull(), new Email()],
    'password' => new NotNull(),
    'firstname' => [new NotNull(), (new StringLength())->min(3), new Alphabetic()],
    'lastname' => [(new StringLength())->min(3)],
    'gender' => new Choice(['Mme', 'Mr', null]),
    'website' => [new NotNull(), new Url()],
    'age' => [new NotNull(), (new Integer())->min(18)],
    'invoice_total' => [new NotNull(), new Numeric()],
    'active' => [new NotNull(), new Custom(function ($value) {
        return is_bool($value);
    })]
]);

To see other validation rules that can be added, check out my GitHub repository at the following URL: https://github.com/devcoder-xyz/php-validator/tree/main/src/Assert

Ideal for small project
Simple and easy!
https://github.com/devcoder-xyz/php-validator

Total
0
Shares
Leave a Reply

Your email address will not be published. Required fields are marked *

Previous Post
14-universal-pros-and-cons-of-teamwork-you-should-know

14 Universal pros and cons of teamwork you should know

Next Post
15-easy-to-do-types-of-professional-development

15 Easy-to-Do Types of Professional Development

Related Posts