Before and after validation, it may be necessary to perform some data processing operations such as formatting numeric values, setting default values, etc. Once the validation is complete, the data can be encrypted, decrypted, formatted, or otherwise manipulated using a data processor.
Usage
In Class Properties
To define a preprocessor for a validator, set the $preprocessor
property. To define a postprocessor, set the $postprocessor
property.
Here's a simple example:
use Itwmw\Validate\Support\Processor\ProcessorExecCond;
use Itwmw\Validate\Support\Processor\ProcessorOptions;
use Itwmw\Validate\Support\Processor\ProcessorParams;
use Itwmw\Validate\Validate;
class Test extends Validate
{
protected $rule = [
'name' => 'nullable|string',
];
protected $preprocessor = [
'name' => ['Default Name', ProcessorExecCond::WHEN_EMPTY]
];
protected $postprocessor = [
'name' => ['trim', ProcessorParams::Value]
];
}
The code above means that before validation, if the name
field is empty, it will be set to a default value of Default Name
. After validation, the value of the name
field will be trimmed using the trim function and the trimmed value will be passed as a parameter. For more information on optional parameters, please refer to the Data Processor Parameters section.
Execution Timing
By default, data processors will execute at all times. If you don't want a data processor to execute, you can use ProcessorExecCond::WHEN_NOT_EMPTY
or ProcessorExecCond::WHEN_EMPTY
to specify when the processor should execute.
Usage Multiple Processors
You can define multiple processors for a field by providing the ProcessorOptions::MULTIPLE
option. For example:
use Itwmw\Validate\Support\Processor\ProcessorExecCond;
use Itwmw\Validate\Support\Processor\ProcessorOptions;
use Itwmw\Validate\Support\Processor\ProcessorParams;
use Itwmw\Validate\Validate;
class Test extends Validate
{
protected $rule = [
'name' => 'nullable|string',
];
protected $preprocessor = [
'name' => [
ProcessorOptions::MULTIPLE,
['Default Name', ProcessorExecCond::WHEN_EMPTY],
['trim', ProcessorParams::Value],
]
];
}
The code above means that multiple data processors have been defined by using ProcessorOptions::MULTIPLE
. Before validation, if the name
field is empty, it will be set to a default value of Default Name
. Then, the value of the name
field will be trimmed using the trim function, and the trimmed value will be passed as a parameter for further processing.
In Validation Scenes
If you want to use data processors with validation scenes, you can use the preprocessor and postprocessor methods of the validation scene class, for example:
class Test extends Validate
{
protected $rule = [
'name' => 'nullable|string',
];
protected function sceneSave(ValidateScene $scene): void
{
$scene->only(true)
->preprocessor('name', 'Default Name', ProcessorExecCond::WHEN_EMPTY)
->postprocessor('name', 'trim', ProcessorParams::Value);
}
}
$data = Test::make()->scene('save')->check([]);
var_dump($data);
//array(1) {
// ["name"]=>
// string(12) "Default Name"
//}
$data = Test::make()->check([]);
var_dump($data);
//array(0) {
//}
In the example code above, a preprocessor has been defined in the save
scene that sets the value of the name
field to a default value of Default Name
if it is empty. Additionally, a postprocessor has been defined that trims the value of the name
field using the trim function and passes the validated value as a parameter.
Definition
Data processors can be defined in several ways:
- Using a scalar value
- Using a function name
- Using a method name in the current class
- Using a class that implements the
ProcessorInterface
interface or its fully qualified name - Using a closure in a validation scene
Closure
In a validation scene, a closure can be directly passed as the processor method, like so:
class Test extends Validate
{
protected $rule = [
'name' => 'nullable|string',
];
protected function sceneSave(ValidateScene $scene): void
{
$scene->only(true)
->preprocessor('name', function (mixed $value, string $attribute, array $data) {
if (empty($value)) {
return 'Default Name';
}
return $value;
}, ProcessorParams::Value, ProcessorParams::Attribute, ProcessorParams::OriginalData);
}
}
$data = Test::make()->scene('save')->check([]);
var_dump($data);
//array(1) {
// ["name"]=>
// string(12) "Default Name"
//}
Parameter Order
The order of the parameters passed to the processor is the same as the order in which they are defined. If additional parameters are needed, the constants in ProcessorParams
can be used to obtain them.
Class Method
A method can be defined in the current class, and its name can be used as the processor method. The method name should follow this convention: lowercase method name + Processor
, for example:
class Test extends Validate
{
protected $rule = [
'name' => 'nullable|string',
];
protected $preprocessor = [
'name' => 'setDefaultName',
];
protected function setDefaultNameProcessor(mixed $value)
{
return empty($value) ? 'Default Name' : $value;
}
}
$data = Test::make()->check([]);
var_dump($data);
//array(1) {
// ["name"]=>
// string(12) "Default Name"
//}
Unspecified Parameters
If no parameters are specified, the default order in which they are passed is: ProcessorParams::Value
, ProcessorParams::Attribute
, ProcessorParams::OriginalData
, ProcessorParams::DataAttribute
.
Processor Class
To define a processor class, implement the Itwmw\Validate\Support\Concerns\ProcessorInterface
interface and use the class directly without specifying any parameters.
Here's an example of a processor class:
class RemoveScriptProcessor implements ProcessorInterface
{
public function handle($value, string $attribute, array $originalData)
{
// This is a demo for remove scripts, for display purposes only
$value = preg_replace('/<script.*?>.*?<\/script>/si', '', $value);
return strip_tags($value);
}
}
Using Processor Classes:
class Test extends Validate
{
protected $rule = [
'name' => 'nullable|string',
];
protected $postprocessor = [
'name' => RemoveScriptProcessor::class,
];
}
$data = Test::make()->check([
'name' => '<script>alert(1)</script>Name'
]);
var_dump($data);
//array(1) {
// ["name"]=>
// string(6) "Name"
//}
Data Processor Parameters
ProcessorExecCond
is used to specify when the data processor should execute. It can take one of three values:ProcessorOptions::WHEN_NOT_EMPTY
: Execute when the field is not emptyProcessorOptions::WHEN_EMPTY
: Execute when the field is emptyProcessorOptions::ALWAYS
: Always execute (default behavior)
ProcessorParams
is used to specify where the data processor's parameter comes from. It can take one of four values:ProcessorParams::Value
: Use the field's value as the parameterProcessorParams::Attribute
: Use the field's key as the parameterProcessorParams::OriginalData
: Use the original data as the parameterProcessorParams::DataAttribute
: Provide aDataAttribute
object as the parameter
ProcessorOptions
is used to specify optional parameters for the data processor. It can take one of two values:ProcessorOptions::MULTIPLE
: Used when multiple processors are added to the same fieldProcessorOptions::VALUE_IS_ARRAY
: Used when the value is an array. When this option is added, the validator will pass all parameters except forProcessorExecCond
to the processor. If this option is not added, the validator will pass the first value as the parameter to the processor.