By default, you have very few options for field validation in Drupal. You can make a field required, set its length if you have a text field, or set the allowed number of values -- but that's just about it. Fortunately, we have a very powerful mechanism for adding field validation in the form of Entity validation API.
Let's say that you want to enforce your users to add exactly 3 images to a field. The easiest way to do this is by writing some custom code using Entity validation API and you can use validation constraints to do it.
First, let's create our Constraint:
src/Plugin/Validation/Constraint/ThreeValuesConstraint.php
<?php
namespace Drupal\MY_MODULE\Plugin\Validation\Constraint;
use Symfony\Component\Validator\Constraint;
/**
* Checks that we have exactly 3 values.
*
* @Constraint(
* id = "ThreeValuesConstraint",
* label = @Translation("Three Values Constraint", context = "Validation"),
* type = "string"
* )
*/
class ThreeValuesConstraint extends Constraint {
/**
* Constraint message.
*
* @var string
*/
public $message = 'You must add exactly 3 images.';
}
As you can see this class basically just defines the validation message. You don't have to wrap the string in the t() function because Drupal core does this for you here: \Drupal\Core\TypedData\Validation\ExecutionContext::addViolation
Now let's create our Validator and add some field validation logic.
src/Plugin/Validation/Constraint/ThreeValuesConstraintValidator.php
<?php
namespace Drupal\MY_MODULE\Plugin\Validation\Constraint;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
/**
* Validates the ThreeValuesConstraint constraint.
*/
class ThreeValuesConstraintValidator extends ConstraintValidator {
/**
* {@inheritdoc}
*/
public function validate($entity, Constraint $constraint) {
if ($entity->get('field_images')->count() != 3) {
$this->context->addViolation($constraint->message);
}
}
}
And that's it. That's our new field validator. We just have to add the constraint to an entity type.
To add it to an entity type that's not defined in your custom module you can use the hook_entity_type_alter() hook like this:
/**
* Implements hook_entity_type_alter().
*/
function MY_MODULE_entity_type_alter(array &$entity_types) {
$entity_types['node']->addConstraint('ThreeValuesConstraint');
}
or if you want to add it to an entity type that's defined in your custom module just update the annotation:
/**
* @MyEntityType(
* ...
* ...
* constraints = {
* "ThreeValuesConstraint" = {}
* }
* ...
* ...
* )
*/
For testing, I added this validation to an image field on my Article content type, and if I hit the Save button with only two images added I will get the error message like this:
Obviously, this validator is extremely simple, but you can do whatever you want in the validate() method. Now go on and add some fancy constraints to your entity fields and make sure that your users don't add something you don't want.