You are here

unique_field_ajax.module in Unique field ajax 8

Same filename and directory in other branches
  1. 2.x unique_field_ajax.module

Unique value for cck fields check module.

File

unique_field_ajax.module
View source
<?php

/**
 * @file
 * Unique value for cck fields check module.
 */
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\field\Entity\FieldConfig;

/**
 * Implements hook_help().
 */
function unique_field_ajax_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {

    // Main module help for the unique_field_ajax module.
    case 'help.page.unique_field_ajax':
      $output = '';
      $output .= '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . t('The Unique Field module allows administrators to require that content supplied for specified fields is unique.') . '</p>';
      return $output;
    default:
  }
}

/**
 * Implements hook_form_BASE_FORM_ID_alter().
 *
 * Removes the default values form from the field settings page.
 * Users expect to use the default value form to predefine only certain values
 * on the widget, but Drupal expects the default value to be complete, and used
 * whenever an actual address isn't provided. Therefore it's preferable to
 * hide this functionality and implement our own via custom widget settings.
 */
function unique_field_ajax_form_field_config_edit_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $field = $form_state
    ->getFormObject()
    ->getEntity();
  $unique_field_ajax_types = [
    'string',
    'list_string',
    'text',
    'email',
    'entity_reference',
    'path',
    'uri',
  ];
  if (!$field
    ->getFieldStorageDefinition()
    ->isMultiple()) {
    if (in_array($field
      ->getType(), $unique_field_ajax_types)) {
      $form['third_party_settings']['unique_field_ajax']['unique'] = array(
        '#type' => 'checkbox',
        '#title' => t("Unique"),
        '#default_value' => $field
          ->getThirdPartySetting('unique_field_ajax', 'unique'),
        '#weight' => -10,
      );
      $form['third_party_settings']['unique_field_ajax']['per_lang'] = array(
        '#type' => 'checkbox',
        '#title' => t("Per Language"),
        '#description' => t("Do not allow duplicated content per language"),
        '#default_value' => $field
          ->getThirdPartySetting('unique_field_ajax', 'per_lang'),
        '#weight' => -9,
        '#states' => array(
          'visible' => array(
            ':input[name="third_party_settings[unique_field_ajax][unique]"]' => array(
              'checked' => TRUE,
            ),
          ),
        ),
      );
      $form['third_party_settings']['unique_field_ajax']['use_ajax'] = array(
        '#type' => 'checkbox',
        '#title' => t("Use Ajax"),
        '#description' => t("Use ajax for validation."),
        '#default_value' => $field
          ->getThirdPartySetting('unique_field_ajax', 'use_ajax'),
        '#weight' => -8,
        '#states' => array(
          'visible' => array(
            ':input[name="third_party_settings[unique_field_ajax][unique]"]' => array(
              'checked' => TRUE,
            ),
          ),
        ),
      );
      $form['third_party_settings']['unique_field_ajax']['message'] = array(
        '#type' => 'textarea',
        '#title' => t("Error message"),
        '#description' => t("The message to show under the field when the value is not unique"),
        '#default_value' => $field
          ->getThirdPartySetting('unique_field_ajax', 'message'),
        '#weight' => -7,
        '#states' => array(
          'visible' => array(
            ':input[name="third_party_settings[unique_field_ajax][unique]"]' => array(
              'checked' => TRUE,
            ),
          ),
        ),
      );
    }
  }
}

/**
 * Attaching data to unique fields.
 *
 * @param $element
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 * @param $context
 */
function unique_field_ajax_field_widget_form_alter(&$element, FormStateInterface $form_state, $context) {
  $field_definition = $context['items']
    ->getFieldDefinition();
  $name = $field_definition
    ->getFieldStorageDefinition()
    ->getName();
  if ($field_definition instanceof FieldConfig) {
    $is_unique_per_lang = NULL;
    if (\Drupal::moduleHandler()
      ->moduleExists('language') && \Drupal::languageManager()
      ->getCurrentLanguage()
      ->getId()) {
      $is_unique_per_lang = $field_definition
        ->getThirdPartySetting('unique_field_ajax', 'per_lang');
    }
    if ($field_definition
      ->getThirdPartySetting('unique_field_ajax', 'unique')) {
      $element['value']['#unique_field_ajax_settings'] = [
        'per_lang' => $is_unique_per_lang,
        'field_definition' => $field_definition,
        'field_name' => $name,
      ];
      $element['value']['#element_validate'][] = 'unique_field_ajax_validate_unique';
      if ($field_definition
        ->getThirdPartySetting('unique_field_ajax', 'use_ajax')) {
        $element['#process'] = [
          '_unique_field_ajax_process',
        ];
      }
    }
  }
}

/**
 * @param array $form
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 * @return mixed
 */
function _unique_field_ajax(array &$form, FormStateInterface $form_state) {
  $element = $form_state
    ->getTriggeringElement();
  return NestedArray::getValue($form, $element['#array_parents']);
}

/**
 * Attach ajax to unique field.
 *
 * @param $element
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 * @param $form
 *
 * @return mixed
 */
function _unique_field_ajax_process($element, FormStateInterface &$form_state, &$form) {
  $field_name = $element['value']['#unique_field_ajax_settings']['field_name'];
  $field_definition = $element['value']['#unique_field_ajax_settings']['field_definition'];
  $field_label = $field_definition
    ->label();
  $wrapper = 'unique-' . $field_name;
  if (!empty($form['#attached']['library']) && !in_array('unique_field_ajax/unique_event', $form['#attached']['library'])) {
    $form['#attached']['library'][] = 'unique_field_ajax/unique_event';
  }
  $settings = array(
    'id' => '#' . $wrapper . ' input',
  );
  $form['#attached']['drupalSettings']['unique_field_ajax'][] = $settings;
  $element['value']['#ajax'] = [
    'callback' => '_unique_field_ajax',
    'event' => 'finishedinput',
    'wrapper' => $wrapper,
    'progress' => array(
      'type' => 'throbber',
      'message' => t('Verifying @field_label...', array(
        '@field_label' => $field_label,
      )),
    ),
  ];
  $element['value']['#prefix'] = '<div id="' . $wrapper . '">';
  $element['value']['#suffix'] = '</div>';
  $value = $form_state
    ->getValue($field_name);
  $value = !empty($value) ? $value[0]['value'] : NULL;
  $entity = $form_state
    ->getFormObject()
    ->getEntity();
  $entity_type = $entity
    ->getEntityTypeId();
  $langcode = !empty($form_state
    ->getValues()['langcode'][0]['value']) ? $form_state
    ->getValues()['langcode'][0]['value'] : '0';
  $valid = unique_field_ajax_is_unique($entity_type, $langcode, $field_name, $value, $entity
    ->bundle(), $element['value']['#unique_field_ajax_settings']['per_lang'], $entity);
  $message = $field_definition
    ->getThirdPartySetting('unique_field_ajax', 'message');
  if (empty($message)) {
    $message = t('This field has to be unique.');
  }
  if (!$valid) {
    $element['value']['#attributes']['class'][] = 'error';
    $element['value']['#attributes']['aria-invalid'] = 'true';
    $element['value']['#suffix'] = '<div class="error">' . $message . '</div>' . $element['value']['#suffix'];
  }
  return $element;
}

/**
 * Ajax callback to validate the email field.
 */
function unique_field_ajax_validate_unique($element, FormStateInterface $form_state, array $form) {
  $entity = $form_state
    ->getFormObject()
    ->getEntity();

  // If !isset langcode set it to 0.
  $langcode = !empty($form_state
    ->getValues()['langcode'][0]['value']) && $form_state
    ->getValues()['langcode'][0]['value'] ? $form_state
    ->getValues()['langcode'][0]['value'] : '0';
  $field_name = $element['#unique_field_ajax_settings']['field_name'];
  $field_definition = $element['#unique_field_ajax_settings']['field_definition'];
  $field_label = $field_definition
    ->label();
  $value = $form_state
    ->getValue($field_name);
  $entity_type = $entity
    ->getEntityTypeId();

  // If field is not unique set error.
  $valid = unique_field_ajax_is_unique($entity_type, $langcode, $field_name, $value[0]['value'], $entity
    ->bundle(), $element['#unique_field_ajax_settings']['per_lang'], $entity);
  if (!$valid) {
    $form_state
      ->setErrorByName($field_name, t('The field @field_label has to be unique.', array(
      '@field_label' => $field_label,
    )));
    $form_state
      ->setRebuild();
  }
}

/**
 * Test if the field value already exist in the database.
 *
 * @param $entity_type
 * @param $langcode
 * @param $field_name
 * @param $field_value
 * @param $bundle
 * @param $is_unique_per_lang
 *
 * @return array|int
 */
function unique_field_ajax_is_unique($entity_type, $langcode, $field_name, $field_value, $bundle, $is_unique_per_lang, $entity) {
  $entity_type_definition = Drupal::entityTypeManager()
    ->getDefinition($entity_type);
  $query = Drupal::entityQuery($entity_type)
    ->condition($field_name, $field_value, '=');

  // Test if the entity has a bundle.
  if (!empty($entity_type_definition
    ->getKey('bundle'))) {
    $query
      ->condition($entity_type_definition
      ->getKey('bundle'), $bundle, '=');
  }

  // Test unique per language.
  if ($is_unique_per_lang) {
    $query
      ->condition('langcode', $langcode);
  }
  $entities = $query
    ->execute();
  if (!empty($entities)) {
    if ($id = $entity
      ->id()) {
      if (!in_array($id, $entities)) {
        return FALSE;
      }
    }
    else {
      return FALSE;
    }
  }
  return TRUE;
}

Functions

Namesort descending Description
unique_field_ajax_field_widget_form_alter Attaching data to unique fields.
unique_field_ajax_form_field_config_edit_form_alter Implements hook_form_BASE_FORM_ID_alter().
unique_field_ajax_help Implements hook_help().
unique_field_ajax_is_unique Test if the field value already exist in the database.
unique_field_ajax_validate_unique Ajax callback to validate the email field.
_unique_field_ajax
_unique_field_ajax_process Attach ajax to unique field.