Apr 11 2016
Apr 11

Recently, I have been working on a site which has a big mutli-step form which is using a lot of custom form elements, custom auto-completes, custom form api states and ajax based sub-forms. It is all built using Drupal form api. The best thing about this form is that all the fields and sub-forms map to a data model. This gives us the benefit of validating the form fields using the Symfony validation component. This is good because we can write all the validation separately and test it using phpunit without bootstrapping Drupal. To convert this data model into form fields we wrote a form factory and connected it all together using the service container module.

Whenever you are working with complex multistep forms and updating a sub-form based on user input then you can't exactly show the form errors in the order in which the fields appeared on the form. In this post I'll explain a process in which we can achieve just that - keeping the form error messages in the same order as the form fields.

In short, the workflow is:

  • initiate the form factory;
  • create a model object;
  • pass the model object to the form factory, which derives the form API fields; and
  • show the form

After form submission the process is:

  • hydrate the model objects from user input; and
  • validate the objects using Symfony validation component.
  • If there are errors set the form errors else store objects in local storage.

This was all working nicely but the problem was that all the validation errors were showing in the order they are validated not in the order in which they are displayed on the form. For most of the fields it was working correctly but when the mutli-value custom form elements were validated the order of all the single value field errors were inconsistent with the order on the form. The reason was that the multi-value fields were loaded using ajax and were validated after the single value fields. This was a poor experience from a usability point of view. One way of fixing this problem was by using inline form errors but we didn't want to go down that road. Another way to fix this is to sort the form errors according to fields weight in the form after all the errors are set.

There is a form_get_errors function which returns all the errors of the form keyed by their string version of '#parents' key of the element. The solution was simple, get all the errors recursively parse through all the sorted fapi elements in $form and create a new list of errors and set them again. I added a new custom validator to all the steps because we have the complete form with all the fields in the validator and as it was the last validator all the form errors were already set.

 * Sorts the form errors according to the fields weight in form.
 * @param array $form
 *   The form array.
 * @param array $form_state
 *   The form state array.
function sort_form_errors($form, &$form_state) {
  $sorted_errors = [];
  $errors = form_get_errors();
  if ($errors) {
    // Clear errors.
    // Clear error messages.
    $error_messages = drupal_get_messages('error');
    // Get the sorted errors form the form recursively.
    get_sorted_errors($form, $sorted_errors, $errors);
    // Initialize an array where removed error messages are stored.
    $removed_messages = [];
    // Reinstate the errors.
    foreach (array_merge($sorted_errors, $errors) as $name => $error) {
      form_set_error($name, $error);
      // form_set_error() calls drupal_set_message(), so we have to filter out
      // these from the error messages as well.
      $removed_messages[] = $error;

    // Reinstate remaining error messages (which, at this point, are messages
    // that were originated outside of the validation process).
    foreach (array_diff($error_messages['error'], $removed_messages) as $message) {
      drupal_set_message($message, 'error');

 * Gets the sorted errors from the form recursively.
 * @param array $form
 *   The form element array.
 * @param array $sorted_errors
 *   The sorted errors array.
 * @param array $errors
 *   All the errors of the form.
function get_sorted_errors(&$form, &$sorted_errors, &$errors) {
  foreach (element_children($form, TRUE) as $child) {
    if (is_array($form[$child])) {
      $element = $form[$child];
      $parents = $element['#parents'];
      $name = implode('][', $parents);
      if (isset($errors[$name])) {
        $sorted_errors[$name] = $errors[$name];
      get_sorted_errors($element, $sorted_errors, $errors);

The original idea of this code was taken from https://api.drupal.org/comment/28464#comment-28464.

In closing

We have plans to port our form factory code to Drupal 8 and release as a contrib module. We've found decoupling our model objects from Drupal makes it much easier to test business logic and allows for rapid iteration with a focus on maximum business value.

Form API validation
Mar 31 2016
Mar 31

In the previous article of this series we’ve started our dive into the Entity Validation and Typed Data APIs. We’ve seen how DataType plugins interact with data definitions and how various constraints can be added to the latter at multiple levels and extension points.

Drupal 8 logo

In this part, we will cover the aspect of actual validation and violation handling. In addition, we will write our own constraint and validator so that we can use custom behaviors in the data validation process.

Validation and Violation Handling

Even though we don’t yet know exactly how constraints are built, we’ve seen how they can be added to Typed Data definitions, including entity fields. Let us now see how we can validate the entities and handle possible violations we find.

When talking about Typed Data we’ve already seen how the validate() method can be called on the DataType plugin instance which holds a data definition. When it comes to entities, this can happen both at entity and field levels.

For instance, we can validate the entire entity using the validate() method:

$entity->set('title', 'this is too long of a title');
$violations = $entity->validate();

In our previous article, we added the Length constraint to Node titles to prevent title strings longer than 5 characters. If that is still in place and we run the code above, the validation should obviously fail. The $violations object is now, however, an EntityConstraintViolationListInterface instance which provides some helper methods for accessing violation data specific to Drupal content entities. It’s worth looking into that interface for all the helper methods available.

To get a list of Entity level violations we can use the getEntityViolations() method but we can also loop through all of them. Once we have our individual ConstraintViolationInterface instances, we can inspect them for what went wrong. For instance, we can get the error message with getMessage(), the property path that failed with getPropertyPath() and the invalid value with getInvalidValue(), among other useful things.

When it comes to fields, the property path is in the following format: title.0.value. This includes the field name, the key (delta) of the individual field item in the list and the actual property name. This represents the property path of our violation above.

Apart from calling validation on the entire entity (which may be superfluous at times), we can also do so directly on each field:

$entity->set('title', 'this is too long of a title');
$violations = $entity->get('title')->validate();

In this case, $violations is again an instance of ConstraintViolationListInterface and can be looped over to inspect each violation. This time, though, the property path changes to no longer include the field name: 0.value.

And lastly, we can even validate the individual items in the list:

$violations = $entity->get('title')->get(0)->validate();

As we can expect, the difference now is that the property path will only show value in the violation since we know exactly what we are validating: the first data definition in the list.

Constraints and Validators

We only touched upon the aspect of constraints and validators but let us better understand how they work by creating one ourselves. We will create one single constraint and validator but that can be used for both Node entities and their fields. It’s always better to have constraints targeted to the data definition we want but for the sake of brevity, we’ll do it all in one constraint to see how all these options could be handled.

The business case of our example is to have a constraint that we can apply to any string-based content entity field that would force the string to contain a certain alphanumeric code. The latter will be passed on as an option so it can be reused. If it’s applied to a Node entity, we want to make sure the title of the node contains the code. So let’s get started.

First, inside our demo module, which can be found in this git repository, we need to create the Validation folder inside the Plugin folder of our namespace (the src/ directory). Inside that, we need the Constraint folder. This is because constraints are plugins expected to be defined in there.

Second, inside Constraint/, we can create our constraint class:


namespace Drupal\demo\Plugin\Validation\Constraint;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Exception\MissingOptionsException;

class HasCodeConstraint extends Constraint {

  public $messageNoCode = 'The string <em>%string</em> does not contain the necessary code: %code.';

  public $code;

  public function __construct($options = NULL) {
    if ($options !== NULL && is_string($options)) {
      parent::__construct(['code' => $options]);

    if ($options !== NULL && is_array($options) && isset($options['code'])) {

    if ($this->code === NULL) {
      throw new MissingOptionsException('The code option is required', __CLASS__);

As we mentioned earlier, the constraint plugin class is relatively simple. It has the expected annotation which, among boilerplate metadata, also specifies what type of data this constraint can be applied to. We chose both a simple string and the Node entity type. We then declare two public properties: a message to be used when the constraint fails (with placeholders being populated inside the validator) and the actual code to be checked for (populated by the constructor of the parent Constraint class). Inside our constructor, we check if the options passed are a string or array (just to be a bit flexible) and throw an exception if the code parameter is not passed as an option in any shape or form.

One of the tasks of the parent Constraint class is to specify which class will be used to validate this constraint. By default, it is a class named like the constraint itself but with Validate appended at the end (HasCodeConstraintValidator). If we wanted to create a differently named and/or namespaced class, we would have to override the validatedBy() method and return the fully qualified name of the class we want.

Let’s now see the HasCodeConstraintValidator class since for us the default is fine:


namespace Drupal\demo\Plugin\Validation\Constraint;

use Drupal\Core\Field\FieldItemListInterface;
use Drupal\node\NodeInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Violation\ConstraintViolationBuilderInterface;

class HasCodeConstraintValidator extends ConstraintValidator {

  protected $context;

  public function validate($data, Constraint $constraint) {
    if (!$constraint instanceof HasCodeConstraint) {
      throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\HasCodeConstraint');

       if ($data instanceof NodeInterface) {
      $this->validateNodeEntity($data, $constraint);

       if ($data instanceof FieldItemListInterface) {
      foreach ($data as $key => $item) {
        $violation = $this->validateString($item->value, $constraint);
        if ($violation instanceof ConstraintViolationBuilderInterface) {

       if (is_string($data)) {
      $violation = $this->validateString($data, $constraint);
      if ($violation instanceof ConstraintViolationBuilderInterface) {

  protected function validateNodeEntity($node, $constraint) {
    foreach ($node->title as $item) {
      $violation = $this->validateString($item->value, $constraint);
      if ($violation instanceof ConstraintViolationBuilderInterface) {

  protected function validateString($string, $constraint) {
    if (strpos($string, $constraint->code) === FALSE) {
      return $this->context->buildViolation($constraint->messageNoCode, array('%string' => $string, '%code' => $constraint->code));


The main job of this class is to implement the validate() method and build violations onto the current execution context if the data passed to it is somehow invalid. The latter can be more than one type of data, depending on what the constraint is applied to.

In our example, we use the constraint for entities, field item lists and primitive data as well. This is just to save us some space. But the logic is that if a Node entity is passed, the code is checked in its title while for the the field items an iteration is performed to check the values of the fields. And of course, the constraint can also be added to individual field items in which case the $data variable would be the value of the data definition.

The $context property has a handy buildViolation() method which allows us to specify a number of things related to what actually failed (path, message, etc).

So if we want to make use of this constraint, we can apply what we learned earlier and do one of the following 3 things:

Inside hook_entity_type_alter():

$node = $entity_types['node'];
$node->addConstraint('HasCode', ['code' => 'UPK']);

This adds the constraint to the Node entities so all node titles now have to contain the code UPK.

Inside hook_entity_base_field_info_alter() or hook_entity_bundle_field_info_alter(), one of the following two lines:

$title->addConstraint('HasCode', ['code' => 'UPK']);
$title->addPropertyConstraints('value', ['HasCode' => ['code' => 'UPK']]);

Where $title is a field definition and the first case adds the constraint to the entire list of items while the latter adds it straight to the individual item.

These three possibilities cover the three cases the constraint validator handles in our example. And that is pretty much it. Not too difficult.

In this article, we’ve continued our dive into the Entity Validation API by looking at two things: validation and violation handling, and the creation of custom constraints. We’ve seen that once applied onto entities or field data definitions, constraints can be very easily validated and inspected for violations. This API borrows a lot from Symfony and makes it a breeze to decouple validation from the Form API.

Also easy, as we’ve seen, is to extend the existing pool of validation criteria available. This is done via constraint plugins, all coupled with their own validators and which can be written in very reusable ways. It’s very interesting to play around with these and see how all the pieces interact. And it is also a great learning experience.

Daniel Sipos

Meet the author

Daniel Sipos is a Drupal developer who lives in Brussels, Belgium. He works professionally with Drupal but likes to use other PHP frameworks and technologies as well. He runs webomelette.com, a Drupal blog where he writes articles and tutorials about Drupal development, theming and site building.
Sep 17 2012
Sep 17

Drupal's Form API allows developers to easily integrate complex validation code into the workflow of a user input form. Unfortunately, the actual feedback from that form validation code is often a bit clunky by modern web standards. Fill out a form, submit it, and wait for a new page to load: only then do you discover that your cat's zip code was required. Providing speedy, immediate feedback on the client side is commonplace on modern web sites; fortunately, the Clientside Validation module makes it easy to implement on Drupal sites as well.

Screenshot of administration screen

Clientside Validation serves as a wrapper around the existing jQuery Validate plugin. It allows site administrators to set up the basic parameters for the plugin's work, like when validation actions should be triggered, where they should be displayed, and so on. Most of the display options look a bit clunky out of the box, but with some CSS styling to position them (positioned next to an invalid field, hovering contemptuously above an incorrect Zip code, etc.) they can be made to fit most designs.

Once the module is activated, basic FormAPI validations (required fields, for example) appear instantly on the client side without the need to submit the form. Even better, the module integrates with a host of additional modules like FormAPI Validation, Field Validation, and WebForm Validation. Custom validation rules added by those modules can be handled on the client-side, as well.

Screenshot of resulting change to site

If you're trying to smooth the rough edges off of complex input forms, providing better validation cues is a great place to start. The Clientside Validation module does a great job of integrating a slick jQuery library with a pile of other validation-related modules. Give it a try!


About Drupal Sun

Drupal Sun is an Evolving Web project. It allows you to:

  • Do full-text search on all the articles in Drupal Planet (thanks to Apache Solr)
  • Facet based on tags, author, or feed
  • Flip through articles quickly (with j/k or arrow keys) to find what you're interested in
  • View the entire article text inline, or in the context of the site where it was created

See the blog post at Evolving Web

Evolving Web