How would you prevent a user from being allowed to enter duplicate entity reference items on an entity reference field?
1 Answer
Using form alter, you could add an #element_validate function to the field.
function mymodule_form_alter(&$form, FormStateInterface $form_state, $form_id) {
if (isset($form['field_articles'])) {
if (empty($form['field_articles']['widget']['#element_validate'])) {
$form['field_articles']['widget']['#element_validate'] = ['mymodule_prevent_duplicate_entity_reference'];
}
else {
$form['field_articles']['widget']['#element_validate'][] = 'mymodule_prevent_duplicate_entity_reference';
}
}
}
Then in your custom validation function, if there are duplicate entity reference items, set a form error.
function mymodule_prevent_duplicate_entity_reference(array &$element, FormStateInterface $form_state, array &$complete_form) {
$input = NestedArray::getValue($form_state->getValues(), $element['#parents']);
$ids = array_filter(array_column($input, 'target_id'));
// Check that there aren't duplicate entity_id values.
if (count($ids) !== count(array_flip($ids))) {
$form_state->setError($element, 'Field "' . $element['#title'] . '" doesn\'t allow duplicates.');
}
}
If you would like to create a reusable widget, you could extend one of the entity reference widgets, for example, EntityReferenceAutocompleteWidget:
namespace Drupal\mymodule\Plugin\Field\FieldWidget;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Field\Plugin\Field\FieldWidget\EntityReferenceAutocompleteWidget;
use Drupal\Component\Utility\NestedArray;
/**
* Plugin implementation of the 'entity_reference_autocomplete' widget.
*
* @FieldWidget(
* id = "no_duplicate_entity_reference_autocomplete",
* label = @Translation("Autocomplete - Disallow Duplicates"),
* description = @Translation("An autocomplete text field that validates against duplicates."),
* field_types = {
* "entity_reference"
* }
* )
*/
class NoDuplicateEntityAutocomplete extends EntityReferenceAutocompleteWidget {
/**
* {@inheritdoc}
*/
public static function afterBuild(array $element, FormStateInterface $form_state) {
parent::afterBuild($element, $form_state);
$class = get_class();
$element['#element_validate'][] = [$class, 'validateNoDuplicates'];
return $element;
}
/**
* Set a form error if there are duplicate entity ids.
*/
public static function validateNoDuplicates(array &$element, FormStateInterface $form_state, array &$complete_form) {
$input = NestedArray::getValue($form_state->getValues(), $element['#parents']);
$ids = array_filter(array_column($input, 'target_id'));
// Check that there aren't duplicate entity_id values.
if (count($ids) !== count(array_flip($ids))) {
$form_state->setError($element, 'Field "' . $element['#title'] . '" doesn\'t allow duplicates.');
}
}
}