ztools-1.0.x-dev/src/Plugin/Field/FieldWidget/TextfieldListWidget.php

src/Plugin/Field/FieldWidget/TextfieldListWidget.php
<?php declare(strict_types = 1);

namespace Drupal\ztools\Plugin\Field\FieldWidget;

use Drupal\Component\Utility\EmailValidatorInterface;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\NestedArray;
use Drupal\Component\Utility\SortArray;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Field\InternalViolation;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Render\Element;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Validator\ConstraintViolationInterface;
use Symfony\Component\Validator\ConstraintViolationListInterface;

/**
 * Defines the 'ztools_textfield_list' field widget.
 *
 * @FieldWidget(
 *   id = "ztools_textfield_list",
 *   label = @Translation("Textfield List"),
 *   field_types = {"string", "email"},
 * )
 */
final class TextfieldListWidget extends WidgetBase {

  /**
   * {@inheritdoc}
   */
  public static function defaultSettings(): array {
    $setting = [
      'delimiter' => ',',
      'trim' => TRUE,
    ];
    return $setting + parent::defaultSettings();
  }

  /**
   * {@inheritdoc}
   */
  public function settingsForm(array $form, FormStateInterface $form_state): array {
    $element['delimiter'] = [
      '#type' => 'textfield',
      '#length' => 5,
      '#title' => $this->t('Delimiter'),
      '#default_value' => $this->getSetting('delimiter'),
    ];
    $element['trim'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Trim values'),
      '#default_value' => $this->getSetting('trim'),
    ];
    return $element;
  }

  /**
   * {@inheritdoc}
   */
  public function settingsSummary(): array {
    return [
      $this->t('Delimiter: @delimiter', ['@delimiter' => $this->getSetting('delimiter')]),
      $this->t('Trim: @trim', ['@trim' => $this->getSetting('trim') ? 'Yes' : 'No']),
    ];
  }

  protected function formMultipleElements(FieldItemListInterface $items, array &$form, FormStateInterface $form_state) {
    $field_name = $this->fieldDefinition->getName();
    $cardinality = $this->fieldDefinition->getFieldStorageDefinition()->getCardinality();
    $parents = $form['#parents'];
    switch ($cardinality) {
      case FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED:
        $field_state = static::getWidgetState($parents, $field_name, $form_state);
        $max = $field_state['items_count'];
        break;

      default:
        $max = $cardinality - 1;
        break;
    }
    $title = $this->fieldDefinition->getLabel();
    $description = $this->getFilteredDescription();

    $element = [
      '#title' => $title,
      '#type' => 'textfield',
      '#required' => $this->fieldDefinition->isRequired(),
      '#title_display' => 'before',
      '#description' => $description,
    ];

    $values = [];
    for ($delta = 0; $delta <= $max; $delta++) {
      $values[$delta] = $items->offsetExists($delta) ? $items[$delta]->value : NULL;
    }

    $element['#default_value'] = implode($this->getSetting('delimiter'), array_filter($values));

    return $element;
  }

  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
    return $element;
  }

  public function extractFormValues(FieldItemListInterface $items, array $form, FormStateInterface $form_state) {
    $field_name = $this->fieldDefinition->getName();

    // Extract the values from $form_state->getValues().
    $path = array_merge($form['#parents'], [$field_name]);
    $key_exists = NULL;
    $value = NestedArray::getValue($form_state->getValues(), $path, $key_exists);

    if ($key_exists) {
      $values = $this->explodeValues($value, $form, $form_state);

      // Assign the values and remove the empty ones.
      $items->setValue($values);
      $items->filterEmptyItems();

      // Put delta mapping in $form_state, so that flagErrors() can use it.
      $field_state = static::getWidgetState($form['#parents'], $field_name, $form_state);
      foreach ($items as $delta => $item) {
        $field_state['original_deltas'][$delta] = $item->_original_delta ?? $delta;
        unset($item->_original_delta, $item->_weight, $item->_actions);
      }
      static::setWidgetState($form['#parents'], $field_name, $form_state, $field_state);
    }
  }

  public function explodeValues(string $value, array $form, FormStateInterface $form_state) {

    $values = explode($this->getSetting('delimiter'), $value);
    if ($this->getSetting('trim')) {
      $values = array_map('trim', $values);
    }
    return $values;
  }

  /**
   * {@inheritdoc}
   */
  public function flagErrors(FieldItemListInterface $items, ConstraintViolationListInterface $violations, array $form, FormStateInterface $form_state) {
    $field_name = $this->fieldDefinition->getName();

    $field_state = static::getWidgetState($form['#parents'], $field_name, $form_state);

    if ($violations->count()) {
      // Locate the correct element in the form.
      $element = NestedArray::getValue($form_state->getCompleteForm(), $field_state['array_parents']);

      // Do not report entity-level validation errors if Form API errors have
      // already been reported for the field.
      // @todo Field validation should not be run on fields with FAPI errors to
      //   begin with. See https://www.drupal.org/node/2070429.
      $element_path = implode('][', $element['#parents']);
      if ($reported_errors = $form_state->getErrors()) {
        foreach (array_keys($reported_errors) as $error_path) {
          if (str_starts_with($error_path, $element_path)) {
            return;
          }
        }
      }

      // Only set errors if the element is visible.
      if (Element::isVisibleElement($element)) {
        $handles_multiple = $this->handlesMultipleValues();

        $violations_by_delta = $item_list_violations = [];
        foreach ($violations as $violation) {
          $violation = new InternalViolation($violation);
          // Separate violations by delta.
          $property_path = explode('.', $violation->getPropertyPath());
          $delta = array_shift($property_path);
          if (is_numeric($delta)) {
            $violations_by_delta[$delta][] = $violation;
          }
          // Violations at the ItemList level are not associated to any delta.
          else {
            $item_list_violations[] = $violation;
          }
          // @todo Remove BC layer https://www.drupal.org/i/3307859 on PHP 8.2.
          $violation->arrayPropertyPath = $property_path;
        }

        /** @var \Symfony\Component\Validator\ConstraintViolationInterface[] $delta_violations */
        foreach ($violations_by_delta as $delta => $delta_violations) {

          foreach ($delta_violations as $violation) {
            $error_element = $element;
            if ($error_element !== FALSE) {
              $form_state->setError($error_element, $violation->getMessage());
            }
          }
        }

        /** @var \Symfony\Component\Validator\ConstraintViolationInterface[] $item_list_violations */
        // Pass violations to the main element without going through
        // errorElement() if the violations are at the ItemList level.
        foreach ($item_list_violations as $violation) {
          $form_state->setError($element, $violation->getMessage());
        }
      }
    }
  }


}

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

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