Title: Validator Description: The validator class help you validate fields submitted by a form.
There are many times you need to validate fields submitted by a form. Take a look at an example validation:
$options = [
'email' => 'required|email',
'name' => 'required|min:3'
];
$validator = tr_validator($options, tr_request()->getFields())->validate(true);
$failed = $validator->failed();
$passed = $validator->passed();
Validation is best done for custom resources. Post types fields should not be required but should be expected to be empty just as all other post type fields are in WordPress. However, you can implement field validation for post types.
To get all validation errors use the getErrors()
method. This will return an array of stings with the error messages.
$errors = $validator->getErrors();
You can also get the errors used for inline form fields. This will return an array of stings with the error messages. These errors are shortened and do not include the field name.
$errorsForFields = $validator->getErrorFields();
Once getting the inline field errors, to display them, send them back to the form by redirecting the response. If you want the errors to include the field labels use $validator->getErrors()
instead of $validator->getErrorFields()
.
tr_redirect()->withErrors( ['fields' => $errorsForFields] )->back()->now();
Then in your form use useErrors()
.
tr_form()->useErrors();
You can redirect back right away, within a controller, when validation fails. When redirecting and validations fails a flash message, the old fields, and inline field errors will get set and sent as well.
// throws a RedirectError
$validator->redirectWithErrorsIfFailed();
You can modify the redirect used by passing a callback to the method.
$cb = function($redirect) {
return $redirect->toHome();
};
$validator->redirectWithErrorsIfFailed($cb);
Also, you can disable the error flash messages by passing false
as the second argument.
$validator->redirectWithErrorsIfFailed($cb, false);
To flash errors to the admin on the next request use the flashErrors()
method. This will flash the errors on the next request. So, you will need to redirect if validation has errors.
if($validator->failed() ) {
$validator->flashErrors();
tr_redirect()->back()->now();
}
If you need the errors to flash on the front-end use the \TypeRocket\Elements\Notice
class.
echo \TypeRocket\Elements\Notice::flash();
To get the passing validation rules use the getPasses()
method.
$passes = $validator->getPasses();
If check if validation passed, use the passed()
method.
$validator->passed();
$validator->failed();
There are 10 validation Rules: required
, key
, email
, min:{int}
, max:{int}
, size:{int}
, numeric
, url
, callback:{callback}:{[option]}
, and ( unique:{field}:{[id]}
and unique:{field}:{table[@column]}{[id]}
). You can make custom validation rules if you need more.
To set a character minimum, use the min
option.
$rules = [
'name' => 'min:3'
];
$validator = tr_validator($rules, tr_request()->getFields())->validate(true);
To set a character maximum, use the max
option.
$rules = [
'name' => 'max:3'
];
$validator = tr_validator($rules, tr_request()->getFields())->validate(true);
To set a character size requirement, use the size
option.
$rules = [
'state' => 'size:2'
];
$validator = tr_validator($rules, tr_request()->getFields())->validate(true);
May only contain lowercase alphanumeric characters and underscores.
$rules = [
'name' => 'key'
];
$validator = tr_validator($rules, tr_request()->getFields())->validate(true);
To set a URL requirement, use the url
option.
$rules = [
'website' => 'url'
];
$validator = tr_validator($rules, tr_request()->getFields())->validate(true);
To make a field required, use the required
option.
$rules = [
'email_address' => 'required'
];
$validator = tr_validator($rules, tr_request()->getFields())->validate(true);
To require a field but allow for NULL
, use the weak
option.
$rules = [
'email_address' => 'required:weak'
];
To require a field but first trim()
the value(s), use the strong
option.
$rules = [
'email_address' => 'required:strong'
];
To require a field and allow the value of 0
, use the allow_zero
option.
$rules = [
'email_address' => 'required:allow_zero'
];
To combine options separate them with a /
.
$rules = [
'email_address' => 'required:strong/allow_zero'
];
To make a field required to be an in the HTML5 input datetime-local field format <input type="datetime-local">
, use the datetime-local
option.
$rules = [
'datetime' => 'datetime-local'
];
$validator = tr_validator($rules, tr_request()->getFields())->validate(true);
To make a field required to be an email, use the email
option.
$rules = [
'email_address' => 'email'
];
$validator = tr_validator($rules, tr_request()->getFields())->validate(true);
To make a field unique use the unique
option. The unique option has a specific format and requirements. the requirements are:
field
- The database column that should be unique.id
(optional) - The ID of a row to ignore.
unique:{field}:{[id]}
For example, in a one to one relationship between a Seat
and Person
only one person can have a Seat
so it must be unique.
$rules['persons_id'] = 'unique:persons_id:3';
$validator = tr_validator($rules, tr_request()->getFields(), \App\Models\Seat)->validate(true);
If you want to check for uniqueness on a table, instead of a model, you can do the following.
unique:{field}:{table[@column]}:{[id]}
For example, the below will validate and check for uniqueness in the wp_options
table on the option_name
column.
$fields['option_name'] = 'mailserver_url';
$validator = tr_validator([
'option_name' => 'unique:option_name:wp_options'
], $fields);
You can also add an ignore check. For example, the below will validate and check for uniqueness in the wp_options
table on the option_name
column where the option_id
does not equal 14
.
$fields['option_name'] = 'mailserver_url';
$validator = tr_validator([
'option_name' => 'unique:option_name:wp_options@option_id:14'
], $fields);
To make your own validation use the callback
option. The callback option has a specific format and requirements. the requirements are:
callback
- A callback function for the validator to use on the field value.option
(optional) - A string you wish to pass to the callback.
callback:{callback}:{[option]}
For example, in a one to one relationship between a Seat
and Person
only one person can have a Seat
so it must be unique.
function checkCallback($args)
{
/**
* @var $option3
* @var $option
* @var $option2
* @var $name
* @var $field_name
* @var $value
* @var $type
* @var \TypeRocket\Utility\Validator $validator
*/
extract($args);
$error = null;
if( empty($value) ) {
return $field_name . ' is bad'; // has error
}
return true; // passed
}
// Validator
$rules = [
'persons_id' => 'callback:checkCallback:3'
];
$validator = tr_validator($rules, tr_request()->getFields())->validate(true);
You can also validate deeply embedded fields. This will require the group to be present for the value to validate.
$fields['person'][1]['email'] = '[email protected]';
$fields['person'][2]['email'] = '[email protected]';
$rules = [
'person.*.email' => 'email'
];
$validator = tr_validator($rules, $fields)->validate(true);
By using ?
instead of *
you can weakly validate a group. The ?
wildcard is helpful if the group is not required but you still want to validate the fields within the group when the group is there.
// Will still pass validation.
$fields['person'] = [];
$rules = [
'person.?.email' => 'required|email'
];
$validator = tr_validator($rules, $fields)->validate(true);
You will need to extend the \TypeRocket\Utility\Validators\ValidatorRule
class to create custom rules. You can make a custom validation rule using the Galaxy CLI using the command php galaxy make:rule <key> <class>
. For example, you might make a variation of the email validation rule with php galaxy make:rule domain_email DomainEmailValidator
:
<?php
namespace App\Validators;
use TypeRocket\Utility\Str;
use TypeRocket\Utility\Validator;
class DomainEmailValidator extends ValidatorRule
{
public CONST KEY = 'domain_email';
public function validate(): bool
{
/**
* @var $option
* @var $option2
* @var $option3
* @var $full_name
* @var $field_name
* @var $value
* @var $type
* @var Validator $validator
*/
extract($this->args);
if( ! filter_var($value, FILTER_VALIDATE_EMAIL) && ! Str::contains('example.com', $value) ) {
$this->error = "must be an example.com email address.";
}
return !$this->error;
}
}
Now you can validate using the class and combine it with other rules:
$validator = tr_validator([
'person.*.email' => [\App\Validators\DomainEmailValidator::new(), 'required']
], $fields)->validate(true);
You can add your own validation rules with the typerocket_validator_map
filter so you can access them by key. You can also use this feature to replace an existing rule with your own.
add_filter('typerocket_validator_map', function($map) {
$map[\App\Validators\DomainEmailValidator::KEY] = \App\Validators\DomainEmailValidator::class;
return $map;
});
Now you can access it by key:
$validator = tr_validator([
'person.*.email' => 'domain_email|required'
], $fields)->validate(true);
You can set custom error messages with setErrorMessages()
. When using this method {error}
will be replaced by the validation rules error message. {error}
is not required. When setting error messages the key will be a regular expression matched to the field name passed with a :
and the rule key as a suffix.
$fields['name'] = '[email protected]';
$fields['repeater'][2849573629]['name'] = 'TypeRocket';
$rules = [
'name' => 'required|email',
'repeater.?.name' => 'required',
];
$messages = [
'name:required' => 'Name is a must have!',
'name:email' => 'Email {error}',
'repeater.\d+.name:required' => 'Repeater name {error}',
];
$validator = tr_validator($rules, $fields)->setErrorMessages($messages, true)->validate(true);
You can manually apply an error message to the errors list with appendToFlashErrorMessage()
and prependToFlashErrorMessage()
.
$validator = tr_validator($rules, $fields)->validate(true);
$validator->appendToFlashErrorMessage('An error message appended.');
$validator->prependToFlashErrorMessage('An error message prepended.');
To use multiple options, use the |
(pipe) character to separate them.
$rules = [
'email' => 'required|email',
];
To skip validation when a field is not provided or is blank prepend ?
to the validation rule set.
$rules = [
'email' => '?required|email',
];