Creating a custom validator type

Creating a custom validator is very easy. In principle, you have two options: extending / modifying / overriding one of the existing validators, or creating a completely custom validator from scratch – a brand new validator type. Let's see how to do it.

Extending / Modifying an Existing Validator

The principle is simple: using inheritance, you modify the original class and bind it to the given type using the factory system. Here is an example:

namespace JetApplication;

use 
Jet\Validator_Date;

class 
MyDateValidator extends Validator_Date {
    public const 
ERROR_CODE_FORBIDDEN_DAY = 'forbidden_day';
    
    public function 
validate_value( mixed $value ): bool
    
{
        if(!
parent::validate_value( $value )) {
            return 
false;
        }
        
        if(
$value=='1980-08-13') {
            
$this->setError(static::ERROR_CODE_FORBIDDEN_DAY);
            return 
false;
        }
        
        return 
true;
    }
    
    public function 
getErrorCodeScope() : array
    {
        
$codes = parent::getErrorCodeScope();
        
        
$codes[] = static::ERROR_CODE_FORBIDDEN_DAY;
        
        return 
$codes;
    }
}

And then all you need to do is replace the old validator with the new one. This means adding this line of code to the initialization script application/Init/Factory.php:

use Jet\Factory_Validator;

Factory_Validator::setValidatorClassName( MyDateValidator::getType(), MyDateValidator::class );

Creating a Completely Custom Validator

Creating a custom validator uses the exact same principle, with the difference that your class will inherit directly from the Validator class and must implement more methods. At the same time, we will use this example to demonstrate how to define attributes for the validator definition.

use Jet\Validator;
use 
Jet\Entity_Validator_Definition_ValidatorOption;


class 
MySuperbValidator extends Validator {
    
    protected static 
string $type = 'my_superb_validator';
    
    public const 
ERROR_CODE_EXAMPLE = 'example_error_code';
    
    protected array 
$error_messages = [
        
self::ERROR_CODE_EMPTY   => 'Missing value',
        
self::ERROR_CODE_EXAMPLE => 'Example error message',
    ];
    
    #[
Entity_Validator_Definition_ValidatorOption(
        
type: Entity_Validator_Definition_ValidatorOption::TYPE_INT,
        
label: 'Minimal value',
        
getter: 'getMinimalValue',
        
setter: 'setMinimalValue',
    )]
    protected ?
int $minimal_value = null;
    
    public function 
getMinimalValue(): ?int
    
{
        return 
$this->minimal_value;
    }
    
    public function 
setMinimalValue( ?int $minimal_value ): void
    
{
        
$this->minimal_value = $minimal_value;
    }
    
    
    
    
    public function 
validate_value( mixed $value ): bool
    
{
        if(
            
$this->minimal_value!==null &&
            
$value < $this->minimal_value
        
) {
            
$this->setError(static::ERROR_CODE_EXAMPLE, ['minimal_value'=>$this->minimal_value]);
            return 
false;
        }
        
        return 
true;
    }
    
    public function 
getErrorCodeScope(): array
    {
        
$codes = [
            static::
ERROR_CODE_EXAMPLE
        
];
        
        if(
$this->is_required) {
            
$codes[] = static::ERROR_CODE_EMPTY;
        }
        
        return 
$codes;
    }
}

Please note the usage of Entity_Validator_Definition_ValidatorOption. This is how attributes are defined for validators. The Entity_Validator_Definition_ValidatorOption class takes care of complete validator attribute management; you just need to define the attribute like this.

Now all that remains is to register the new validator. This again means adding this line of code to the initialization script application/Init/Factory.php:

use Jet\Factory_Validator;

Factory_Validator::registerNewValidatorType( MySuperbValidator::getType(), MySuperbValidator::class );
Previous chapter
Jet\Validator_Week
Next chapter
Jet\Entity_Validator_Definition_ValidatorOption