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?