Dev Blog

When developing web applications human or robot input validation is crucial for data integrity. It is possible to set database constraints to keep data consistent - and it should be done - however to display informative message we use validators. These analyze situation and try to display useful information. The unique validator for instance prevents inserting duplicated elements into database.

Use case for extra criteria parameter

The case I stumbled upon was to validate domain added by anyone from around the internet and allow to validate this domain. The point is that anyone can add any domain, and it is perfectly fine. However only one domain having same host can be verified. This use case is supported by Mangan Unique Validator. It allows to set additional criteria, which will be merged with uniqueness checking parameters.

The parameters for property criteria is same as for Criteria class constructor. Which is rather deep array, but can be written in many lines.

Example criteria parameters on unique validator annotation

/**
 * @UniqueValidator(
* 'criteria' => [
* 'conditions' => [
* 'verified' => ['==' => true]
* ]
* ],
* 'message' => @Label('Domain {value} is already verified by another account')
* ) */ public $host = ''; public $verified = false;

Trashing domain

Additional criteria with verified attribute check is sufficient to prevent multiple hosts to be verified. When one of visitor verifies domain, the others have message displayed informing that the domain is verified by someone else. The first thing to do is to move domain to trash, as it is no longer usable. But the Unique Validator will prevent this, because the domain is already verified.

There is additional feature of Mangan, called scenarios. These allow different behaviors depending on what is going to happen with model. In our case we want to allow trashing domain even if it fails uniqueness constraint. Adding trash scenario to except property solves this issue.

Example of using except to allow trashing

/**
 * @UniqueValidator(
 *     'except' => ['trash'],
* 'criteria' => [
* 'conditions' => [
* 'verified' => ['==' => true]
* ]
* ],
* 'message' => @Label('Domain {value} is already verified by another account')
* ) */ public $host = ''; public $verified = false;

To avoid using magic string the constant TrashInterface::ScenarioTrash can be used.