location_selector-8.x-1.x-dev/src/Plugin/Field/FieldWidget/LocationSelectorWidget.php

src/Plugin/Field/FieldWidget/LocationSelectorWidget.php
<?php

namespace Drupal\location_selector\Plugin\Field\FieldWidget;

use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Field\WidgetBase;

/**
 * Plugin implementation of the 'location_selector' widget.
 *
 * @FieldWidget(
 *   id = "location_selector_widget",
 *   label = @Translation("Location Selector"),
 *   field_types = {
 *     "location_selector_type"
 *   },
 * )
 */
class LocationSelectorWidget extends WidgetBase {

  /**
   * {@inheritdoc}
   */
  public static function defaultSettings() {
    $settings_default = [
      'force_deepest' => FALSE,
      'save_last' => FALSE,
      'limit_level' => 0,
      'basic_parent_id' => '6295630',
      'parent_include' => FALSE,
    ];
    return $settings_default + parent::defaultSettings();
  }

  /**
   * {@inheritdoc}
   */
  public function settingsForm(array $form, FormStateInterface $form_state) {
    $element['force_deepest'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Force selection of deepest level'),
      '#default_value' => $this->getSetting('force_deepest'),
      '#description' => $this->t('Force users to select terms from the deepest level.'),
    ];
    $element['save_last'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Save only the last selected GeoNames ID'),
      '#default_value' => $this->getSetting('save_last'),
      '#description' => $this->t('Save only the last selected GeoNames ID and not the parents.'),
    ];
    $element['limit_level'] = [
      '#type' => 'number',
      '#title' => $this->t('Children Level limitation'),
      '#default_value' => $this->getSetting('limit_level'),
      '#description' => $this->t('Choose how many children levels you want to display. Set 0 for no limitation.'),
      '#min' => 0,
      '#max' => $this->maxLevel ?? 100,
      '#step' => 1,
      '#required' => TRUE,
    ];
    $element['basic_parent_id'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Basic Parent ID'),
      '#default_value' => $this->getSetting('basic_parent_id'),
      '#description' => $this->t('Go to geonames.org and search for your wanted parent location. 6295630 e.g. is the ID of the Earth.'),
      '#size' => 20,
      '#maxlength' => 128,
      '#required' => TRUE,
    ];
    $element['parent_include'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Include the Basic Parent ID data'),
      '#default_value' => $this->getSetting('parent_include'),
      '#description' => $this->t('Display also the Basic Parent ID data in the first select list.'),
    ];

    return $element;
  }

  /**
   * {@inheritdoc}
   */
  public function settingsSummary() {
    $summary = parent::settingsSummary();
    if ($this->getSetting('force_deepest')) {
      $summary[] = $this->t('Force selection of deepest level');
    }
    else {
      $summary[] = $this->t('Do not force selection of deepest level');
    }
    if ($this->getSetting('save_last')) {
      $summary[] = $this->t('Saving only the last selected GeoNames ID');
    }
    else {
      $summary[] = $this->t("Saving all selected GeoNames ID's");
    }
    if (!empty($levels = $this->getSetting('limit_level'))) {
      $summary[] = $this->t('Children levels: @levels.', ['@levels' => $levels]);
    }
    else {
      $summary[] = $this->t('Children levels: @levels.', ['@levels' => 'no limitations']);
    }
    if (!empty($basic_parent_id = $this->getSetting('basic_parent_id'))) {
      $summary[] = $this->t('Basic Parent ID: @basic_parent_id.', ['@basic_parent_id' => $basic_parent_id]);
    }
    if ($this->getSetting('parent_include')) {
      $summary[] = $this->t('Include the Basic Parent ID data.');
    }
    else {
      $summary[] = $this->t("Not including Basic Parent ID data.");
    }
    return $summary;
  }

  /**
   * {@inheritdoc}
   */
  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {

    // Create individual ID for this field.
    $element_unique_id = $this->fieldDefinition->getUniqueIdentifier();
    $element_ids = [
      'id' => $element_unique_id . '-ls',
      'id_ajax' => $element_unique_id . '-ls-ajax',
    ];

    $wrapper_class = 'ls--field--type-location-selector-type';
    $form_type = 'ls--entity-form';

    $widget_default_values = $items[$delta]->value ?: NULL;
    if (!empty($widget_default_values)) {
      // Save the value to the session.
      // @see \Drupal\location_selector\LocationSelectorController::validateGeoNames
      // Because on submit, the method formElement is called again,
      // so check if the ajax callback has already been made.
      $session = \Drupal::request()->getSession();
      if (!$session->get($element_ids['id_ajax'])) {
        $session->set($element_ids['id'], $widget_default_values);
      }
    }

    $element['value'] = $element + [
      '#type' => 'textarea',
      '#default_value' => $items[$delta]->value,
      '#prefix' => '<div class="' . $wrapper_class . ' ' . $form_type . '">',
      '#suffix' => '</div>',
      '#rows' => 5,
      '#attributes' => [
        'class' => [
          'js-text-full',
          'text-full',
        ],
        'readonly' => 'readonly',
      ],
    ];

    // Set the ids for using in validate function.
    $element['#ls_ids'] = $element_ids;

    // Get the form element settings.
    $formElementSettings = $this->getSettings();

    if (empty($element['#attributes'])) {
      $element['#attributes'] = [];
    }
    $element['#attributes'] = array_merge($element['#attributes'], [
      'class' => ['location-selector__enabled'],
    ]);
    if (empty($element['#attached'])) {
      $element['#attached'] = [];
    }
    // Change default values if user has changed the input.
    // Because on validate function it happens that an error occur
    // and then the value must be from the user.
    if ($user_input = $form_state->getUserInput()) {
      $widget_default_values = $user_input['field_location_selector'][$delta]['value'];
    }
    $element['#attached'] = array_merge($element['#attached'], [
      'library' => ['location_selector/location_selector.form'],
      'drupalSettings' => [
        'location_selector' => [
          'form_element_settings' => $formElementSettings,
          'form_element_default_values' => $widget_default_values,
          'form_element_ids' => $element_ids,
          'form_type' => $form_type,
          'form_wrapper_class' => $wrapper_class,
        ],
      ],
    ]);
    $element['#element_validate'][] = [get_called_class(), 'validateJsonStructure'];
    return $element;
  }

  /**
   * Validates the input to see if it is a properly formatted JSON object.
   *
   * If not, PgSQL will throw fatal errors upon insert.
   *
   * @param array $element
   *   The element array.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state.
   * @param array $form
   *   The form array.
   */
  public static function validateJsonStructure(array &$element, FormStateInterface $form_state, array $form) {
    $session = \Drupal::request()->getSession();

    // @todo: check separate limit level without force deepest option.
    $settings = $element['#attached']['drupalSettings']['location_selector']['form_element_settings'];

    // Check if it's json.
    if (mb_strlen($element['value']['#value'])) {
      if (json_last_error() !== JSON_ERROR_NONE) {
        $form_state->setError($element['value'], t('The field %name must contain a valid JSON object.', ['%name' => $element['value']['#title']]));
      }
      // Prevent value manipulation.
      $value = $element['value']['#value'];
      $session_value = $session->get($element['#ls_ids']['id']);
      if ($session_value !== $value) {
        $form_state->setError($element['value'], t('It is not allowed to change the JSON object of the field %name.', ['%name' => $element['value']['#title']]));
      }
    }

    // Check for the foce_deepest setting.
    if ($settings['force_deepest']) {
      if (empty($form_state->getErrors())) {

        $last_selected_values = json_decode($element['value']['#value'], TRUE);
        $last_selected_path = $last_selected_values['path'];

        // Because:
        // @see https://stackoverflow.com/questions/48382457/mysql-json-column-change-array-order-after-saving
        if (is_array($last_selected_path)) {
          ksort($last_selected_path);
          $last_selected_value = end($last_selected_path);
          $last_selected_value = [['children' => $last_selected_value['val']]];
          $geonames_service = \Drupal::service('location_selector.geonames');
          // Check limit level too.
          if ($settings['limit_level']) {
            $current_level = max(array_keys($last_selected_path));
            if ($current_level < $settings['limit_level']) {
              $data = $geonames_service->getGeoNamesAndIds($last_selected_value);
            }
          }
          else {
            $data = $geonames_service->getGeoNamesAndIds($last_selected_value);
          }
          if (!empty($data)) {
            $form_state->setError($element['value'], t('You must choose the deepest level of the field %name.', ['%name' => $element['value']['#title']]));
          }
        }
      }
    }

    if (empty($form_state->getErrors())) {
      // If no errors appear, delete the session.
      $session->remove($element['#ls_ids']['id_ajax']);
    }
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc