slideshare quotation-marks triangle book file-text2 file-picture file-music file-play file-video location calendar search wrench cogs stats-dots hammer2 menu download2 question cross enter google-plus facebook instagram twitter medium linkedin drupal GitHub quotes-close
Code

Entity validation refers to specifying criteria (constraints) which must be met before an entity can be saved (created or updated).

A traditional way to do this in Drupal has been to implement hook_form_alter() and add a custom form validation handler to the entity creation form - usually the node edit form.

Custom validation handlers are a perfectly good option, but their drawback is that your custom validation will only happen when entities are created via the entity creation form; validation will not happen when entities are created/updated via any other mechanism: data migration, creation via REST or JSON API web service, custom code snippets, ...

To ensure custom entity validation happens regardless of the method of creation, use the Entity Validation API.

Specifying constraints

Validation criteria are called constraints in the Entity Validation API. Each individual constraint is a Plugin and consists of a constraint and a constraint validator.

You must do three things:

  1. Create a new constraint.

  2. Create a matching constraint validator.

  3. Attach the constraint to the entity type as a whole, or to a specific field of the entity.

For now we'll keep things simple and add a constraint to an entity type as a whole, not to a specific field.

This example is a simplified version of the ArticleLimitConstraint you find in the sample code repository at https://github.com/codeenigma/entity-validation-examples. Be sure to open it alongside to this article to understand the structure of the Plugin and to see which files go where.

Step 1: Make your new constraint known to Drupal

Create a class for your constraint. Notice that the docblock contains an annotation that provides crucial information:

  • id: the unique name you choose for your constraint

  • label: your constraint's description

  • type: the type of constraint. In this case we're acting on entities.

use Symfony\Component\Validator\Constraint;

/**
 * Description here.
 *
 * @Constraint(
 *   id = "DemoFirstConstraint",
 *   label = @Translation("Description here", context="Validation"),
 *   type = "entity"
 * )
 */
class DemoConstraint extends Constraint {

  /**
   * Message shown when validation fails.
   *
   * @var string
   */
  public $message = 'Node creation failed: reason-goes-here.';

}

Step 2: Write your validation logic

Your actual validation logic goes in a ConstraintValidator class. Mind the naming convention: if your constraint is named DemoConstraint, your constraint validator has to be named DemoConstraintValidator.

You can write arbitrary validation logic here. When you decide certain criteria aren't met, and validation should fail, use the addViolation() method and pass along the message to display to the end user:

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
class DemoConstraintValidator extends ConstraintValidator {

  /**
   * {@inheritdoc}
   */
  public function validate($entity, Constraint $constraint) {
    if (!isset($entity)) {
      return;
    }

    // TODO: Write your actual validation here.
    if ($some_condition == TRUE) {
      $this->context->addViolation($constraint->message);
    }
  }
}a

Step 3: Attach your constraint to the entity type

In our example we want the validation to happen on entities of the type node, so we need to change the node entity type's definition and use the addConstraint() method:

/**
 * Implements hook_entity_type_alter().
 */
function demo_entity_type_alter(array &$entity_types) {

  /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */

  $entity = $entity_types['node'];
  $entity->addConstraint('DemoConstraint');
}

That's it. Put the code in a module and enable it. When modifying these classes don't forget to clear your caches if things don't seem to be working.

If all went well you should get an error message every time you try to create or update a node and your code has triggered a violation.

Have a look at the provided sample code. The ArticleLimitConstraint example shows how to limit the creation of article nodes to an arbitrary number.

In a later article we'll look at validating field values, and more complex things you can do with constraints.

Additional resources: