A validation library for PHP that uses the notification pattern.
- PHP 7.2+ or 8.0+
composer require selective/validation
A notification is a collection of errors
In order to use a notification, you have to create the ValidationResult
object. A ValidationResult
can be really
simple:
<?php
use Selective\Validation\Exception\ValidationException;
use Selective\Validation\ValidationResult;
$validationResult = new ValidationResult();
if (empty($data['username'])) {
$validationResult->addError('username', 'Input required');
}
You can now test the ValidationResult
and throw an exception if it contains errors.
<?php
if ($validationResult->fails()) {
throw new ValidationException('Please check your input', $validationResult);
}
Login example:
<?php
use Selective\Validation\Exception\ValidationException;
use Selective\Validation\ValidationResult;
// ...
// Get all POST values
$data = (array)$request->getParsedBody();
$validation = new ValidationResult();
// Validate username
if (empty($data['username'])) {
$validation->addError('username', 'Input required');
}
// Validate password
if (empty($data['password'])) {
$validation->addError('password', 'Input required');
}
// Check validation result
if ($validation->fails()) {
// Trigger error response (see validation middleware)
throw new ValidationException('Please check your input', $validation);
}
Validating a JSON request works like validating form data, because in PHP it's just an array from the request object.
<?php
use Selective\Validation\ValidationResult;
// Fetch json data from request as array
$jsonData = (array)$request->getParsedBody();
$validation = new ValidationResult();
// ...
if ($validation->fails()) {
throw new ValidationException('Please check your input', $validation);
}
In vanilla PHP you can fetch the JSON request as follows:
<?php
$jsonData = (array)json_decode(file_get_contents('php://input'), true);
// ...
The Selective\Validation\Regex\ValidationRegex
class allows you to validate if
a given string conforms a defined regular expression.
Example usage:
use Selective\Validation\Factory\CakeValidationFactory;
use Selective\Validation\Regex\ValidationRegex;
// ...
$data = [ /* ... */ ];
$validationFactory = new CakeValidationFactory();
$validator = $validationFactory->createValidator();
$validator
->regex('id', ValidationRegex::ID, 'Invalid')
->regex('country', ValidationRegex::COUNTRY_ISO_2, 'Invalid country')
->regex('date_of_birth', ValidationRegex::DATE_DMY, 'Invalid date format');
The ValidationExceptionMiddleware
PSR-15 middleware catches all exceptions and converts it into a nice JSON response.
Insert a container definition for ValidationExceptionMiddleware::class
:
<?php
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseFactoryInterface;
use Selective\Validation\Encoder\JsonEncoder;
use Selective\Validation\Middleware\ValidationExceptionMiddleware;
use Selective\Validation\Transformer\ErrorDetailsResultTransformer;
use Slim\App;
use Slim\Factory\AppFactory;
// ...
return [
ValidationExceptionMiddleware::class => function (ContainerInterface $container) {
$factory = $container->get(ResponseFactoryInterface::class);
return new ValidationExceptionMiddleware(
$factory,
new ErrorDetailsResultTransformer(),
new JsonEncoder()
);
},
ResponseFactoryInterface::class => function (ContainerInterface $container) {
$app = $container->get(App::class);
return $app->getResponseFactory();
},
App::class => function (ContainerInterface $container) {
AppFactory::setContainer($container);
return AppFactory::create();
},
// ...
];
Add the ValidationExceptionMiddleware
into your middleware stack:
<?php
use Selective\Validation\Middleware\ValidationExceptionMiddleware;
use Slim\Factory\AppFactory;
require_once __DIR__ . '/../vendor/autoload.php';
$app = AppFactory::create();
// ...
$app->add(ValidationExceptionMiddleware::class);
// ...
$app->run();
<?php
use Selective\Validation\ValidationException;
use Selective\Validation\ValidationResult;
$validation = new ValidationResult();
// Validate username
if (empty($data->username)) {
$validation->addError('username', 'Input required');
}
// Check validation result
if ($validation->fails()) {
// Trigger the validation middleware
throw new ValidationException('Please check your input', $validation);
}
You can combine this library with a validator that is doing the actual validation of your input data.
The converter pattern makes it easy to map instances of one class into instances of another class.
The cakephp/validation library provides features to build validators that can validate arbitrary arrays of data with ease.
Installation
composer require cakephp/validation
Usage
The Cake\Validation\Validator::validate()
method returns a non-empty array when
there are validation failures. The list of errors then can be converted into
a ValidationResult
using the Selective\Validation\Factory\CakeValidationFactory
or Selective\Validation\Converter\CakeValidationConverter
.
For example, if you want to validate a login form you could do the following:
use Selective\Validation\Factory\CakeValidationFactory;
use Selective\Validation\Exception\ValidationException;
// ...
// Within the Action class: fetch the request data, e.g. from a JSON request
$data = (array)$request->getParsedBody();
// Within the Application Service class: Do the validation
$validationFactory = new CakeValidationFactory();
$validator = $validationFactory->createValidator();
$validator
->notEmptyString('username', 'Input required')
->notEmptyString('password', 'Input required');
$validationResult = $validationFactory->createValidationResult(
$validator->validate($data)
);
if ($validationResult->fails()) {
throw new ValidationException('Please check your input', $validationResult);
}
Please note: The CakeValidationFactory
should be injected via constructor.
Read more: https://odan.github.io/2020/10/18/slim4-cakephp-validation.html
Installation
composer require symfony/validator
Usage
<?php
use Selective\Validation\Converter\SymfonyValidationConverter;
use Selective\Validation\Exception\ValidationException;
use Selective\Validation\Regex\ValidationRegex;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Validation;
// Note: This is just an example. Don't use the $request object within the domain layer.
$formData = (array)$request->getParsedBody();
// ...
// Create a Symfony validator instance
$validator = Validation::createValidator();
// Add rules
$constraint = new Assert\Collection(
[
'first_name' => new Assert\NotBlank(['message' => 'Input required']),
'last_name' => new Assert\NotBlank(['message' => 'Input required']),
'mobile' => new Assert\Optional(
[
new Assert\Regex(
[
'pattern' => ValidationRegex::PHONE_NUMBER,
'message' => 'Invalid',
]
),
]
),
'comment' => new Assert\Optional(
[
new Assert\Length(['max' => 255, 'maxMessage' => 'Too long']),
]
),
'email' => new Assert\Optional(
[
new Assert\Email(
[
'message' => 'Invalid',
]
),
]
)
]
);
$constraint->missingFieldsMessage = 'Input required';
$violations = $validator->validate($formData, $constraint);
// Convert symfony violations to ValidationResult
$validationResult = SymfonyValidationConverter::createValidationResult($violations);
// Optional: Do more complex validation and append it to the validation result
if ($this->existsUsername($formData['username'])) {
$validationResult->addError('username', 'Username is already taken');
}
if ($validationResult->fails()) {
throw new ValidationException('Please check your input', $validationResult);
}
If you want to implement a custom response data structure,
you can implement a custom transformer against the
\Selective\Validation\Transformer\ResultTransformerInterface
interface.
Example
<?php
namespace App\Transformer;
use Selective\Validation\Exception\ValidationException;
use Selective\Validation\Transformer\ResultTransformerInterface;
use Selective\Validation\ValidationResult;
final class MyValidationTransformer implements ResultTransformerInterface
{
public function transform(
ValidationResult $validationResult,
ValidationException $exception = null
): array {
// Implement your own data structure for the response
// ...
return [];
}
}
The MIT License (MIT). Please see License File for more information.