custom_field-1.0.x-dev/src/Plugin/CustomField/FieldWidget/EntityReferenceAutocompleteWidget.php

src/Plugin/CustomField/FieldWidget/EntityReferenceAutocompleteWidget.php
<?php

declare(strict_types=1);

namespace Drupal\custom_field\Plugin\CustomField\FieldWidget;

use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\custom_field\Attribute\CustomFieldWidget;
use Drupal\custom_field\Plugin\CustomFieldTypeInterface;
use Drupal\user\EntityOwnerInterface;

/**
 * Plugin implementation of the 'entity_reference_autocomplete' widget.
 */
#[CustomFieldWidget(
  id: 'entity_reference_autocomplete',
  label: new TranslatableMarkup('Autocomplete'),
  category: new TranslatableMarkup('Reference'),
  field_types: [
    'entity_reference',
  ],
)]
class EntityReferenceAutocompleteWidget extends EntityReferenceWidgetBase {

  /**
   * {@inheritdoc}
   */
  public static function defaultSettings(): array {
    return [
      'match_operator' => 'CONTAINS',
      'match_limit' => 10,
      'size' => 60,
      'placeholder' => '',
    ] + parent::defaultSettings();
  }

  /**
   * {@inheritdoc}
   */
  public function widgetSettingsForm(FormStateInterface $form_state, CustomFieldTypeInterface $field): array {
    $element = parent::widgetSettingsForm($form_state, $field);
    $settings = $this->getSettings() + static::defaultSettings();

    $element['match_operator'] = [
      '#type' => 'radios',
      '#title' => $this->t('Autocomplete matching'),
      '#default_value' => $settings['match_operator'],
      '#options' => $this->getMatchOperatorOptions(),
      '#description' => $this->t('Select the method used to collect autocomplete suggestions. Note that <em>Contains</em> can cause performance issues on sites with thousands of entities.'),
    ];
    $element['match_limit'] = [
      '#type' => 'number',
      '#title' => $this->t('Number of results'),
      '#default_value' => $settings['match_limit'],
      '#min' => 0,
      '#description' => $this->t('The number of suggestions that will be listed. Use <em>0</em> to remove the limit.'),
    ];
    $element['size'] = [
      '#type' => 'number',
      '#title' => $this->t('Size of textfield'),
      '#default_value' => $settings['size'],
      '#min' => 1,
      '#required' => TRUE,
    ];
    $element['placeholder'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Placeholder'),
      '#default_value' => $settings['placeholder'],
      '#description' => $this->t('Text that will be shown inside the field until a value is entered. This hint is usually a sample value or a brief description of the expected format.'),
    ];

    return $element;
  }

  /**
   * {@inheritdoc}
   */
  public function widget(FieldItemListInterface $items, int $delta, array $element, array &$form, FormStateInterface $form_state, CustomFieldTypeInterface $field): array {
    $element = parent::widget($items, $delta, $element, $form, $form_state, $field);
    $settings = $this->getSettings() + static::defaultSettings();
    $field_settings = $field->getFieldSettings();
    $entity = $items->getEntity();
    $target_type = $field->getTargetType();
    if (!isset($field_settings['handler'])) {
      $field_settings['handler'] = 'default:' . $target_type;
    }

    // Append the match operation to the selection settings.
    $selection_settings = $field_settings['handler_settings'] + [
      'match_operator' => $settings['match_operator'],
      'match_limit' => $settings['match_limit'],
    ];

    // Append the entity if it is already created.
    if (!$entity->isNew()) {
      $selection_settings['entity'] = $entity;
    }

    if (isset($selection_settings['target_bundles']) && $selection_settings['target_bundles'] === []) {
      $selection_settings['target_bundles'] = NULL;
    }

    $element += [
      '#type' => 'entity_autocomplete',
      '#target_type' => $target_type,
      '#selection_handler' => $field_settings['handler'],
      '#selection_settings' => $selection_settings,
      // Entity reference field items are handling validation themselves via
      // the 'ValidReference' constraint.
      '#validate_reference' => FALSE,
      '#maxlength' => 1024,
      '#default_value' => NULL,
      '#size' => $settings['size'],
      '#placeholder' => $settings['placeholder'],
    ];

    if (isset($element['#default_value'])) {
      $referenced_entity = $this->entityTypeManager
        ->getStorage($target_type)
        ->load($element['#default_value']);
      $element['#default_value'] = $referenced_entity;
    }

    if ($bundle = $this->getAutocreateBundle($field_settings['handler_settings'], $target_type, $field)) {
      $element['#autocreate'] = [
        'bundle' => $bundle,
        'uid' => ($entity instanceof EntityOwnerInterface) ? $entity->getOwnerId() : $this->currentUser->id(),
      ];
    }

    return ['target_id' => $element];
  }

  /**
   * {@inheritdoc}
   */
  public function massageFormValue(mixed $value, array $column): mixed {
    // The entity_autocomplete form element returns an array when an entity
    // was "autocreated", so we need to move it up a level.
    if (empty($value['target_id'])) {
      return NULL;
    }
    if (is_array($value['target_id'])) {
      $value += $value['target_id'];
      unset($value['target_id']);
    }

    return $value;
  }

  /**
   * Returns the name of the bundle which will be used for autocreated entities.
   *
   * @param array $handler_settings
   *   The field handler settings.
   * @param string $target_type
   *   The target_type setting for the field.
   * @param \Drupal\custom_field\Plugin\CustomFieldTypeInterface $field
   *   The custom field.
   *
   * @return string|null
   *   The bundle name. If autocreate is not active, NULL will be returned.
   */
  protected function getAutocreateBundle(array $handler_settings, string $target_type, CustomFieldTypeInterface $field): ?string {
    $bundle = NULL;
    $auto_create = $handler_settings['auto_create'] ?? FALSE;
    if ($auto_create) {
      $target_bundles = $handler_settings['target_bundles'];
      // If there's no target bundle at all, use the target_type. It's the
      // default for bundleless entity types.
      if (empty($target_bundles)) {
        $bundle = $target_type;
      }
      // If there's only one target bundle, use it.
      elseif (count($target_bundles) == 1) {
        $bundle = reset($target_bundles);
      }
      // If there's more than one target bundle, use the autocreate bundle
      // stored in selection handler settings.
      elseif (!$bundle = $handler_settings['auto_create_bundle']) {
        // If no bundle has been set as auto create target means that there is
        // an inconsistency in entity reference field settings.
        trigger_error(sprintf(
          "The 'Create referenced entities if they don't already exist' option is enabled but a specific destination bundle is not set. You should re-visit and fix the settings of the '%s' (%s) field.",
          $field->getLabel(),
          $field->getName()
        ), E_USER_WARNING);
      }
    }

    return $bundle;
  }

  /**
   * Returns the options for the match operator.
   *
   * @return String[]
   *   List of options.
   */
  protected function getMatchOperatorOptions(): array {
    return [
      'STARTS_WITH' => (string) $this->t('Starts with'),
      'CONTAINS' => (string) $this->t('Contains'),
    ];
  }

}

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

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