Mapping validators to entities

Validators can be mapped to any class. What is this good for? For example, after creating an entity instance based on an import (from XML, JSON, and so on), it is possible to verify whether the populated data is truly valid and complies with the validation parameters.

As previously mentioned, validation can be mapped to properties of any class. You just need to satisfy these three conditions:

  • The class must implement the Entity_Validator_Interface interface.
  • The class must use the Entity_Validator_Trait trait.
  • The class properties you wish to validate must have a validator definition using the Entity_Validator_Definition attribute. A list of pre-configured validator types and their attributes can be found here.

The class then has a createValidator() method which, based on the definitions, creates an instance of the entity validator Entity_Validator associated with that specific entity instance.

On the generated entity validator, you then simply call the validate():bool method, and complete validation is performed.

Let's look at an example:

namespace JetApplication;

use 
Jet\BaseObject;
use 
Jet\Entity_Validator_Definition;
use 
Jet\Entity_Validator_Interface;
use 
Jet\Entity_Validator_Trait;
use 
Jet\Validator;
use 
Jet\Validator_Int;


class 
ExampleEntity extends BaseObject implements Entity_Validator_Interface
{
    
    use 
Entity_Validator_Trait;

    #[
Entity_Validator_Definition(
        
type: Validator::TYPE_INT,
        
min_value: 10,
        
max_value: 999,
        
error_messages: [
            
Validator_Int::ERROR_CODE_OUT_OF_RANGE => 'Number is out of range (10-999)'
        
]
    )]
    protected 
int $int_property = 0;
    
    public function 
getIntProperty(): int
    
{
        return 
$this->int_property;
    }
    
    public function 
setIntProperty( int $int_property ): void
    
{
        
$this->int_property = $int_property;
    }
    
}

$object = new ExampleEntity();
$object->setIntProperty( 10000 );

$validator = $object->createValidator();
if(
$validator->validate()) {
    echo 
"OK - object is valid";
} else {
    echo 
"Object is not valid<br><br>";
    
    foreach( 
$validator->getErrors() as $property_path=>$validation_errors ) {
        foreach( 
$validation_errors as $validation_error ) {
            echo 
$property_path.': '.$validation_error->getMessage().'<br>';
        }
    }
}

However, let's demonstrate another very useful application. In practice, any entity is composed of a main entity and its sub-entities, and it is necessary to validate the entity as a whole. This is also possible; let's see an example:

namespace JetApplication;

use 
Jet\BaseObject;
use 
Jet\Entity_Validator_Definition;
use 
Jet\Entity_Validator_Interface;
use 
Jet\Entity_Validator_Trait;
use 
Jet\Validator;
use 
Jet\Validator_Int;


class 
ExampleEntity extends BaseObject implements Entity_Validator_Interface
{
    
    use 
Entity_Validator_Trait;
    
    #[
Entity_Validator_Definition(
        
type: Validator::TYPE_INT,
        
min_value: 10,
        
max_value: 999,
        
error_messages: [
            
Validator_Int::ERROR_CODE_OUT_OF_RANGE => 'Number is out of range (10-999)'
        
]
    )]
    protected 
int $int_property = 0;
    
    public function 
__construct( int $int_property )
    {
        
$this->int_property = $int_property;
    }
}

class 
ExampleMasterEntity extends BaseObject implements Entity_Validator_Interface
{
    use 
Entity_Validator_Trait;
    
    
/**
     * @var array<int,ExampleEntity>
     */
    
#[Entity_Validator_Definition(
        
is_sub_validators: true
    
)]
    protected array 
$sub_entities = [];
    
    public function 
addSubEntity( ExampleEntity $sub_entity ) : void
    
{
        
$this->sub_entities[] = $sub_entity;
    }
}

$master_object = new ExampleMasterEntity();


$master_object->addSubEntity( new ExampleEntity( 10 ) );
$master_object->addSubEntity( new ExampleEntity( 500 ) );
$master_object->addSubEntity( new ExampleEntity( 0 ) );


$validator = $master_object->createValidator();
if(
$validator->validate()) {
    echo 
"OK - object is valid";
} else {
    echo 
"Object is not valid<br><br>";
    
    foreach( 
$validator->getErrors() as $property_path=>$validation_errors ) {
        foreach( 
$validation_errors as $validation_error ) {
            echo 
$property_path.': '.$validation_error->getMessage().'<br>';
        }
    }
}

The output of the example validation will be:

Object is not valid

/sub_entities/2/int_property: Number is out of range (10-999)
Previous chapter
Jet\Entity_Validator_Definition_ValidatorOption
Next chapter
Jet\Entity_Validator