1

I have a Constraint and ContraintValidator to validate a field of taxonomy terms. Its a hierarchical taxonomy called channel with a field field_product. It's required that a channel has the same product (term reference) set as it's parent channel term. It's working well on taxonomy term form, but on saving the taxonomy overview form after reorder (moving one channel to a parent with a different product set) – while xdebugging the code apparently the validation is not called at all.

Some pseudo-code:

In helper.module:

function helper_entity_bundle_field_info_alter(&$fields, EntityTypeInterface $entity_type, $bundle) {
  if (!empty($fields['field_product']) && 'taxonomy_term' === $entity_type->id() && 'channel' === $bundle) {
    $fields['field_product']->addConstraint('MatchParentChannelProduct', []);
  }
}

helper/src/Plugin/Validation/Constraint/MatchParentChannelProductConstraintValidator.php:

/**
 * Validates the MatchParentChannelProduct constraint.
 */
class MatchParentChannelProductConstraintValidator extends ConstraintValidator {

  /**
   * {@inheritdoc}
   */
  public function validate($items, Constraint $constraint) {
    // This is a single-item field so we only need to
    // validate the first item
    $product_reference = $items->first();

    if ($product_reference && $product_reference->target_id) {
      /** @var \Drupal\taxonomy\TermInterface $term */
      $term = $product_reference->getEntity();
      /** @var \Drupal\taxonomy\TermInterface $parent */
      $parent = $term->get('parent')[0]->entity ?? NULL;
      // Nothing to validate, when term has no parent it may have any product.
      if ($parent === NULL) {
        return;
      }

      $parent_tid = $parent->get('field_product')->target_id ?? NULL;
      if ( $parent_tid !== $product_reference->target_id ) {
        $parent_channel_product_name = $parent->get('field_product')->entity->name->value ?? 'unknown';
        $this->context->addViolation($constraint->productDoesNotMatchParentChannelProductMessage, ['%parent_channel_product_name' => $parent_channel_product_name]);
      }
    }
  }
}

\Drupal\taxonomy\Form\OverviewTerms::submitForm() calls $term->save(); I would have expected that this will invoke the entity validation API, but it seems that it doesn't do that. What does it need to validate the therm entity before it is saved? Do I need to implement hook_entity_presave() and there $entity->validate() or $entity->field_product->validate();, as in Using the (Entity Validation) API? Or is there a bug somewhere?

2
  • Did you ever solve this? I am having the same problem.
    – bletch
    Commented Jul 16, 2021 at 10:01
  • No, I didn't solve it, the issue still exists, but fixing has a low priority.
    – LarS
    Commented Jul 16, 2021 at 18:59

1 Answer 1

1

The entity validation API is only invoked if you explicitly call the validate function of the entity. This is normally done in the validateForm function of the form. In the OverviewTerms form no validation is called, so the validation API never gets invoked. I would recommend to add a custom validation callback in a form_alter hook and call the validation API for every changed term.

1
  • Thanks for answering. Sorry I missed to award your answer with the bounty in time, now it's not available.
    – LarS
    Commented Jul 11 at 15:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.