PHP Standalone library for validating data. Inspired by Illuminate\Validation
Laravel.
$_FILES
validation with multiple file support.composer require "rakit/validation"
There are two ways to validating data with this library. Using make
to make validation object,
then validate it using validate
. Or just use validate
.
Examples:
Using make
:
<?php
require('vendor/autoload.php');
use Rakit\Validation\Validator;
$validator = new Validator;
// make it
$validation = $validator->make($_POST + $_FILES, [
'name' => 'required',
'email' => 'required|email',
'password' => 'required|min:6',
'confirm_password' => 'required|same:password',
'avatar' => 'required|uploaded_file:0,500K,png,jpeg',
'skills' => 'array',
'skills.*.id' => 'required|numeric',
'skills.*.percentage' => 'required|numeric'
]);
// then validate
$validation->validate();
if ($validation->fails()) {
// handling errors
$errors = $validation->errors();
echo "<pre>";
print_r($errors->firstOfAll());
echo "</pre>";
exit;
} else {
// validation passes
echo "Success!";
}
or just validate
it:
<?php
require('vendor/autoload.php');
use Rakit\Validation\Validator;
$validator = new Validator;
$validation = $validator->validate($_POST + $_FILES, [
'name' => 'required',
'email' => 'required|email',
'password' => 'required|min:6',
'confirm_password' => 'required|same:password',
'avatar' => 'required|uploaded_file:0,500K,png,jpeg',
'skills' => 'array',
'skills.*.id' => 'required|numeric',
'skills.*.percentage' => 'required|numeric'
]);
if ($validation->fails()) {
// handling errors
$errors = $validation->errors();
echo "<pre>";
print_r($errors->firstOfAll());
echo "</pre>";
exit;
} else {
// validation passes
echo "Success!";
}
In this case, 2 examples above will output the same results.
But with make
you can setup something like custom invalid message, custom attribute alias, etc before validation running.
By default we will transform your attribute into more readable text. For example confirm_password
will be displayed as Confirm password
.
But you can set it anything you want with setAlias
or setAliases
method.
Example:
$validator = new Validator;
// To set attribute alias, you should use `make` instead `validate`.
$validation->make([
'province_id' => $_POST['province_id'],
'district_id' => $_POST['district_id']
], [
'province_id' => 'required|numeric',
'district_id' => 'required|numeric'
]);
// now you can set aliases using this way:
$validation->setAlias('province_id', 'Province');
$validation->setAlias('district_id', 'District');
// or this way:
$validation->setAliases([
'province_id' => 'Province',
'district_id' => 'District'
]);
// then validate it
$validation->validate();
Now if province_id
value is empty, error message would be 'Province is required'.
Before register/set custom messages, here are some variables you can use in your custom messages:
:attribute
: will replaced into attribute alias.:value
: will replaced into stringify value of attribute. For array and object will replaced to json.And also there are several message variables depends on their rules.
Here are some ways to register/set your custom message(s):
With this way, anytime you make validation using make
or validate
it will set your custom messages for it.
It is useful for localization.
To do this, you can set custom messages as first argument constructor like this:
$validator = new Validator([
'required' => ':attribute harus diisi',
'email' => ':email tidak valid',
// etc
]);
// then validation belows will use those custom messages
$validation_a = $validator->validate($dataset_a, $rules_for_a);
$validation_b = $validator->validate($dataset_b, $rules_for_b);
Or using setMessages
method like this:
$validator = new Validator;
$validator->setMessages([
'required' => ':attribute harus diisi',
'email' => ':email tidak valid',
// etc
]);
// now validation belows will use those custom messages
$validation_a = $validator->validate($dataset_a, $rules_for_dataset_a);
$validation_b = $validator->validate($dataset_b, $rules_for_dataset_b);
Sometimes you may want to set custom messages for specific validation.
To do this you can set your custom messages as 3rd argument of $validator->make
or $validator->validate
like this:
$validator = new Validator;
$validation_a = $validator->validate($dataset_a, $rules_for_dataset_a, [
'required' => ':attribute harus diisi',
'email' => ':email tidak valid',
// etc
]);
Or you can use $validation->setMessages
like this:
$validator = new Validator;
$validation_a = $validator->make($dataset_a, $rules_for_dataset_a);
$validation_a->setMessages([
'required' => ':attribute harus diisi',
'email' => ':email tidak valid',
// etc
]);
...
$validation_a->validate();
Sometimes you may want to set custom message for specific rule attribute.
To do this you can use :
as message separator or using chaining methods.
Examples:
$validator = new Validator;
$validation_a = $validator->make($dataset_a, [
'age' => 'required|min:18'
]);
$validation_a->setMessages([
'age:min' => '18+ only',
]);
$validation_a->validate();
Or using chaining methods:
$validator = new Validator;
$validation_a = $validator->make($dataset_a, [
'photo' => [
'required',
$validator('uploaded_file')->fileTypes('jpeg|png')->message('Photo must be jpeg/png image')
]
]);
$validation_a->validate();
Translation is different with custom messages.
Translation may needed when you use custom message for rule in
, not_in
, mimes
, and uploaded_file
.
For example if you use rule in:1,2,3
we will set invalid message like "The Attribute only allows '1', '2', or '3'"
where part "'1', '2', or '3'" is comes from ":allowed_values" tag.
So if you have custom Indonesian message ":attribute hanya memperbolehkan :allowed_values",
we will set invalid message like "Attribute hanya memperbolehkan '1', '2', or '3'" which is the "or" word is not part of Indonesian language.
So, to solve this problem, we can use translation like this:
// Set translation for words 'and' and 'or'.
$validator->setTranslations([
'and' => 'dan',
'or' => 'atau'
]);
// Set custom message for 'in' rule
$validator->setMessage('in', ":attribute hanya memperbolehkan :allowed_values");
// Validate
$validation = $validator->validate($inputs, [
'nomor' => 'in:1,2,3'
]);
$message = $validation->errors()->first('nomor'); // "Nomor hanya memperbolehkan '1', '2', atau '3'"
Actually, our built-in rules only use words 'and' and 'or' that you may need to translates.
Errors messages are collected in Rakit\Validation\ErrorBag
object that you can get it using errors()
method.
$validation = $validator->validate($inputs, $rules);
$errors = $validation->errors(); // << ErrorBag
Now you can use methods below to retrieves errors messages:
all(string $format = ':message')
Get all messages as flatten array.
Examples:
$messages = $errors->all();
// [
// 'Email is not valid email',
// 'Password minimum 6 character',
// 'Password must contains capital letters'
// ]
$messages = $errors->all('<li>:message</li>');
// [
// '<li>Email is not valid email</li>',
// '<li>Password minimum 6 character</li>',
// '<li>Password must contains capital letters</li>'
// ]
firstOfAll(string $format = ':message', bool $dotNotation = false)
Get only first message from all existing keys.
Examples:
$messages = $errors->firstOfAll();
// [
// 'email' => Email is not valid email',
// 'password' => 'Password minimum 6 character',
// ]
$messages = $errors->firstOfAll('<li>:message</li>');
// [
// 'email' => '<li>Email is not valid email</li>',
// 'password' => '<li>Password minimum 6 character</li>',
// ]
Argument $dotNotation
is for array validation.
If it is false
it will return original array structure, if it true
it will return flatten array with dot notation keys.
For example:
$messages = $errors->firstOfAll(':message', false);
// [
// 'contacts' => [
// 1 => [
// 'email' => 'Email is not valid email',
// 'phone' => 'Phone is not valid phone number'
// ],
// ],
// ]
$messages = $errors->firstOfAll(':message', true);
// [
// 'contacts.1.email' => 'Email is not valid email',
// 'contacts.1.phone' => 'Email is not valid phone number',
// ]
first(string $key)
Get first message from given key. It will return string
if key has any error message, or null
if key has no errors.
For example:
if ($emailError = $errors->first('email')) {
echo $emailError;
}
toArray()
Get all messages grouped by it's keys.
For example:
$messages = $errors->toArray();
// [
// 'email' => [
// 'Email is not valid email'
// ],
// 'password' => [
// 'Password minimum 6 character',
// 'Password must contains capital letters'
// ]
// ]
count()
Get count messages.
has(string $key)
Check if given key has an error. It returns bool
if a key has an error, and otherwise.
For example you have validation like this:
$validation = $validator->validate([
'title' => 'Lorem Ipsum',
'body' => 'Lorem ipsum dolor sit amet ...',
'published' => null,
'something' => '-invalid-'
], [
'title' => 'required',
'body' => 'required',
'published' => 'default:1|required|in:0,1',
'something' => 'required|numeric'
]);
You can get validated data, valid data, or invalid data using methods in example below:
$validatedData = $validation->getValidatedData();
// [
// 'title' => 'Lorem Ipsum',
// 'body' => 'Lorem ipsum dolor sit amet ...',
// 'published' => '1' // notice this
// 'something' => '-invalid-'
// ]
$validData = $validation->getValidData();
// [
// 'title' => 'Lorem Ipsum',
// 'body' => 'Lorem ipsum dolor sit amet ...',
// 'published' => '1'
// ]
$invalidData = $validation->getInvalidData();
// [
// 'something' => '-invalid-'
// ]
Click to show details.
Another way to use custom validation rule is to create a class extending Rakit\Validation\Rule
.
Then register it using setValidator
or addValidator
.
For example, you want to create unique
validator that check field availability from database.
First, lets create UniqueRule
class:
<?php
use Rakit\Validation\Rule;
class UniqueRule extends Rule
{
protected $message = ":attribute :value has been used";
protected $fillableParams = ['table', 'column', 'except'];
protected $pdo;
public function __construct(PDO $pdo)
{
$this->pdo = $pdo;
}
public function check($value): bool
{
// make sure required parameters exists
$this->requireParameters(['table', 'column']);
// getting parameters
$column = $this->parameter('column');
$table = $this->parameter('table');
$except = $this->parameter('except');
if ($except AND $except == $value) {
return true;
}
// do query
$stmt = $this->pdo->prepare("select count(*) as count from `{$table}` where `{$column}` = :value");
$stmt->bindParam(':value', $value);
$stmt->execute();
$data = $stmt->fetch(PDO::FETCH_ASSOC);
// true for valid, false for invalid
return intval($data['count']) === 0;
}
}
Then you need to register UniqueRule
instance into validator like this:
use Rakit\Validation\Validator;
$validator = new Validator;
$validator->addValidator('unique', new UniqueRule($pdo));
Now you can use it like this:
$validation = $validator->validate($_POST, [
'email' => 'email|unique:users,email,exception@mail.com'
]);
In UniqueRule
above, property $message
is used for default invalid message. And property $fillable_params
is used for fillParameters
method (defined in Rakit\Validation\Rule
class). By default fillParameters
will fill parameters listed in $fillable_params
. For example unique:users,email,exception@mail.com
in example above, will set:
$params['table'] = 'users';
$params['column'] = 'email';
$params['except'] = 'exception@mail.com';
If you want your custom rule accept parameter list like
in
,not_in
, oruploaded_file
rules, you just need to overridefillParameters(array $params)
method in your custom rule class.
Note that unique
rule that we created above also can be used like this:
$validation = $validator->validate($_POST, [
'email' => [
'required', 'email',
$validator('unique', 'users', 'email')->message('Custom message')
]
]);
So you can improve UniqueRule
class above by adding some methods that returning its own instance like this:
<?php
use Rakit\Validation\Rule;
class UniqueRule extends Rule
{
...
public function table($table)
{
$this->params['table'] = $table;
return $this;
}
public function column($column)
{
$this->params['column'] = $column;
return $this;
}
public function except($value)
{
$this->params['except'] = $value;
return $this;
}
...
}
Then you can use it in more funky way like this:
$validation = $validator->validate($_POST, [
'email' => [
'required', 'email',
$validator('unique')->table('users')->column('email')->except('exception@mail.com')->message('Custom message')
]
]);
Implicit rule is a rule that if it's invalid, then next rules will be ignored. For example if attribute didn't pass required*
rules, mostly it's next rules will also be invalids. So to prevent our next rules messages to get collected, we make required*
rules to be implicit.
To make your custom rule implicit, you can make $implicit
property value to be true
. For example:
<?php
use Rakit\Validation\Rule;
class YourCustomRule extends Rule
{
protected $implicit = true;
}
In some case, you may want your custom rule to be able to modify it's attribute value like our default/defaults
rule. So in current and next rules checks, your modified value will be used.
To do this, you should implements Rakit\Validation\Rules\Interfaces\ModifyValue
and create method modifyValue($value)
to your custom rule class.
For example:
<?php
use Rakit\Validation\Rule;
use Rakit\Validation\Rules\Interfaces\ModifyValue;
class YourCustomRule extends Rule implements ModifyValue
{
...
public function modifyValue($value)
{
// Do something with $value
return $value;
}
...
}
You may want to do some preparation before validation running. For example our uploaded_file
rule will resolves attribute value that come from $_FILES
(undesirable) array structure to be well-organized array structure, so we can validate multiple file upload just like validating other data.
To do this, you should implements Rakit\Validation\Rules\Interfaces\BeforeValidate
and create method beforeValidate()
to your custom rule class.
For example:
<?php
use Rakit\Validation\Rule;
use Rakit\Validation\Rules\Interfaces\BeforeValidate;
class YourCustomRule extends Rule implements BeforeValidate
{
...
public function beforeValidate()
{
$attribute = $this->getAttribute(); // Rakit\Validation\Attribute instance
$validation = $this->validation; // Rakit\Validation\Validation instance
// Do something with $attribute and $validation
// For example change attribute value
$validation->setValue($attribute->getKey(), "your custom value");
}
...
}