HomeServiceContact
Drupal
min read
June 28, 2024

Exploring data integrity with API constraints in Drupal

Exploring data integrity with API constraints in Drupal
Table of contents

Drupal's powerful and flexible architecture allows developers to create complex websites and applications. One key feature that makes Drupal robust is its support for constraints. Constraints are rules that enforce data validation and integrity within your content.

They ensure that the data entered into the system adheres to specific criteria, enhancing the reliability and quality of the content. In this blog post, we'll explore how to work with constraints in Drupal, focusing on custom constraints and how they can be used effectively in your projects.

What are Constraints?

Constraints in Drupal are validation rules applied to data entities. They help ensure that data entered into fields or entities meets certain criteria. Constraints can be applied to:

  • Fields (e.g., ensuring an email field contains a valid email address).
  • Entities (e.g., ensuring a content type has required fields filled).
  • Custom conditions as defined by developers.

Drupal provides several built-in constraints, but you can define custom constraints for more complex scenarios.

Prerequisites

Before you begin, ensure you have:

  • A Drupal site is set up and running.
  • Administrative access to your Drupal site.
  • Basic knowledge of Drupal module development and PHP programming.

Building Constraints

Step 1: Understanding Built-In Constraints

Drupal comes with various built-in constraints that you can apply to your fields and entities. Some common examples include:

  • NotBlank: Ensures a field is not empty.
  • Email: Validates that the input is a valid email address.
  • Length: Restricts the length of the input to a specified range.

These constraints can be easily applied when creating or managing content types and fields through the Drupal administrative interface.

Step 2: Creating Custom Constraints

For more complex validation logic, you may need to create custom constraints. Let's create a custom constraint that ensures a field contains only uppercase letters.

  1. Create a Custom Module:
    First, create a folder for your module in the modules/custom directory, for example, uppercase_constraint. Inside this folder, create an .info.yml file:


name: Uppercase Constraint
type: module
description: 'A module to demonstrate custom constraints in Drupal.'
core_version_requirement: ^8 || ^9
package: Custom


      2. Define the Constraint:

Create a PHP class for the constraint in src/Plugin/Validation/Constraint/UppercaseConstraint.php: 


<?php


namespace Drupal\uppercase_constraint\Plugin\Validation\Constraint;


use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;


/**
* Validates the Uppercase constraint.
*/

class UppercaseConstraintValidator extends ConstraintValidator {


 /**
  * {@inheritdoc}
  */
 public function validate(mixed $field, Constraint $constraint): void {
   $value = strip_tags($field->getValue()[0]['value']);
   if (!ctype_upper($value)) {
     $this->context->addViolation($constraint->message,
     [
         '%field_label' => $constraint->field_label,
       ]
     );
   }


 }


}



   3. Define the Constraint Validator:

Create the validator class in src/Plugin/Validation/Constraint/UppercaseConstraintValidator.php:



<?php

namespace Drupal\uppercase_constraint\Plugin\Validation\Constraint;


use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;


/**
* Validates the Uppercase constraint.
*/
class UppercaseConstraintValidator extends ConstraintValidator {


 /**
  * {@inheritdoc}
  */
 public function validate(mixed $field, Constraint $constraint): void {
   $value = strip_tags($field->getValue()[0]['value']);
   if (!ctype_upper($value)) {
     $this->context->addViolation($constraint->message,
       [
         '%field_label' => $constraint->field_label,
       ]
     );
   }


 }


}



Step 3: Applying the Custom Constraint to a Field / Entity

Now that your custom constraint is defined, you can apply it to a field, entity type or custom entity.

  1. Adding a Constraint to a Field of an Entity Type

In .module, implement either
hook_entity_base_field_info_alter() (for base fields defined by the entity) or
hook_entity_bundle_field_info_alter() (for fields added to a bundle of the entity):

For fields like title, body, etc use hook_entity_base_field_info_alter()



/**
* Implements hook_entity_base_field_info_alter().
*/
function uppercase_constraint_entity_base_field_info_alter(&$fields, EntityTypeInterface $entity_type) {
 // Check if the entity type is 'node' and the bundle is 'recipe_reviews'.
 if ($entity_type->id() === 'node' && $entity_type->hasKey('bundle') && $entity_type->getBundleEntityType() === 'node_type') {
   $bundle_info = \Drupal::entityTypeManager()->getStorage('node_type')->loadMultiple();
   if (isset($bundle_info['blog']) && isset($fields['title'])) {
     $fields['title']->addConstraint('Uppercase');
   }
 }
}



For other fields than base fields used: hook_entity_bundle_field_info_alter()



/**
* Implements hook_entity_bundle_field_info_alter().
*/
function uppercase_constraint_entity_bundle_field_info_alter(&$fields, EntityTypeInterface $entity_type, $bundle) {
 if ($entity_type->id() === 'node' && $bundle === 'blog') {
   if (isset($fields['field_description'])) {
     $fields['field_description']->addConstraint('Uppercase');
   }
 }
}



  1. Adding a Constraint to a Base Field of a custom Entity Type

Constraints on base fields are added using BaseFieldDefinition::addConstraint() in overrides of ContentEntityBase::baseFieldDefinitions():



$fields['name'] = BaseFieldDefinition::create('string')
 ->setLabel(t('Name'))
 ->setDescription(t('The name of the Badge entity.'))
 ->setRevisionable(TRUE)
 ->setSettings([
   'max_length' => 50,
   'text_processing' => 0,
 ])
 ->addConstraint('Uppercase')
 ->setDisplayConfigurable('form', TRUE)
 ->setDisplayConfigurable('view', TRUE)
 ->setRequired(TRUE);


  1. Adding a Constraint to an Entity Type

In .module, implement hook_entity_type_alter():



/**
* Implements hook_entity_type_alter().
*
* @param array $entity_types
*/
function MODULENAME_entity_type_alter(array &$entity_types) {
 // Validation constraint on node entity
 $entity_types['node']->addConstraint('constraint_name');
}



  1. Adding a Constraint to a custom Entity Type

Add the constraint to the entity type annotation on the entity class. If the constraint plugin is configurable, the options can be set there. If it is not, specify an empty array with {}



/**
* Defines the Badge entity.
*
* @ingroup points_system
*
* @ContentEntityType(
*   id = "badge",
*   label = @Translation("Badge"),
*   constraints = {
*     "constraint_name" = {}
*   }
*   field_ui_base_route = "badge.settings"
* )
*/



Step 4: Testing Your Custom Constraint

To ensure your custom constraint works as expected, create or edit a content item of the type you applied the constraint to. Try entering a value in the field that doesn't meet the constraint criteria and verify that the validation error message is displayed.

In the example below, the description field must contain only uppercase letters. If the field is not in uppercase, the validation error message "The Description is not in uppercase." is displayed.

Testing Custom Constraint

Conclusion


Working with constraints in Drupal helps maintain the integrity and quality of your data. By leveraging built-in constraints and creating custom ones, you can ensure that your content meets specific validation criteria. This guide covered the basics of creating and applying custom constraints in Drupal. With this knowledge, you can build more robust and reliable Drupal applications.

Additional Resources

  1. Creating Custom Constraints in Symfony
  2. Defining constraints on Entities or fields

Written by
Editor
No art workers.
We'd love to talk about your business objectives