web-dev-qa-db-ja.com

重複するエンティティ参照アイテムがフィールドに入力されないようにするにはどうすればよいですか?

ユーザーがエンティティ参照フィールドに重複するエンティティ参照アイテムを入力できないようにするにはどうすればよいですか?

3
oknate

フォームの変更を使用して、#element_validate関数をフィールドに追加できます。

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';
    }
  }
}

次に、カスタム検証関数で、エンティティ参照アイテムが重複している場合は、フォームエラーを設定します。

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.');
  }

}

再利用可能なウィジェットを作成する場合は、エンティティ参照ウィジェットの1つ、たとえば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.');
    }

  }
}
2
oknate