Skip to content

Validate an Afform field in an extension

The challenge

In our extension we want to validate a field from an form created with FormBuilder.

The example

As an example we will look at the Simple Orders extension. In this extension we have a form to add a new item which was built with FormBuilder.

On the form for a new item there are 3 fields: 1. name 2. description 3. type (options, initially with values digital and physical)

New Item

We want to add validation that the name that is entered in the form does not already exists for another item.

The solution

We will add a listener for the hook civi.afform.validate and add a static method to perform the validation.

Add the listener

In the extension the listeners for hooks are added in the simpleorders.php file using the simpleorders_civicrm_config method. So we will add the listener for civi.afform.validate to the list that is already there (and note the priority Events::W_EARLY)

Hook listeners

There are more ways in which you can add a listener for a hook, see the Symfony method documentation

use Civi\API\Events;

function simpleorders_civicrm_config(&$config): void {
  Civi::dispatcher()->addListener('civi.afform.validate', ['Civi\Simpleorders\HookHandler', 'onAfformValidate'], Events::W_EARLY);
  _simpleorders_civix_civicrm_config($config);
}

Add the validation method

We will add the validation method onAfformValidate as specified in the listener to the HookHandler class.

use Civi\Afform\Event\AfformValidateEvent;

public static function onAfformValidate(AfformValidateEvent $event): void {
  $values = $event->getSubmittedValues();
  if ($values['SoItem1']) {
    foreach ($values['SoItem1'][0]['fields'] as $fieldName => $fieldValue) {
      if ($fieldName == 'name' && \CRM_Simpleorders_BAO_SoItem::isExistingName($fieldValue)) {
        $event->setError(E::ts('Item name already exists in the database'));
      }
    }
  }
}

The result

Error message