pluginreference-2.0.0/src/Plugin/Field/FieldType/PluginReferenceItem.php

src/Plugin/Field/FieldType/PluginReferenceItem.php
<?php

namespace Drupal\pluginreference\Plugin\Field\FieldType;

use Drupal\Component\Plugin\ConfigurableInterface;
use Drupal\Component\Plugin\PluginBase;
use Drupal\Component\Plugin\PluginInspectionInterface;
use Drupal\Component\Plugin\PluginManagerInterface;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Field\Attribute\FieldType;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Field\PreconfiguredFieldUiOptionsInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\TypedData\DataDefinition;
use Drupal\Core\TypedData\MapDataDefinition;
use Drupal\Core\TypedData\OptionsProviderInterface;
use Drupal\Core\Validation\Plugin\Validation\Constraint\AllowedValuesConstraint;
use Drupal\pluginreference\PluginReferenceSelectionInterface;

/**
 * Plugin implementation of the 'plugin_reference' entity field type.
 */
#[FieldType(
  id: 'plugin_reference',
  label: new TranslatableMarkup('Plugin reference'),
  description: new TranslatableMarkup('This field stores a soft reference to a plugin.'),
  category: 'plugin_reference',
  default_widget: 'plugin_reference_select',
  default_formatter: 'plugin_reference_id',
  list_class: '\Drupal\pluginreference\Plugin\Field\FieldType\PluginReferenceFieldItemList',
)]
class PluginReferenceItem extends FieldItemBase implements OptionsProviderInterface, PreconfiguredFieldUiOptionsInterface {

  /**
   * {@inheritdoc}
   */
  public static function defaultStorageSettings() {
    return [
      'target_type' => '',
    ] + parent::defaultStorageSettings();
  }

  /**
   * {@inheritdoc}
   */
  public static function defaultFieldSettings() {
    return [
      'handler' => 'default',
      'handler_settings' => [],
    ] + parent::defaultFieldSettings();
  }

  /**
   * {@inheritdoc}
   */
  public static function mainPropertyName() {
    return 'plugin_id';
  }

  /**
   * {@inheritdoc}
   */
  public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
    // Prevent early t() calls by using the TranslatableMarkup.
    $properties['plugin_id'] = DataDefinition::create('string')
      ->setLabel(new TranslatableMarkup('Text value'))
      ->addConstraint('Length', ['max' => 255])
      ->setRequired(TRUE);

    $properties['configuration'] = MapDataDefinition::create()
      ->setLabel(t('Configuration'));

    return $properties;
  }

  /**
   * {@inheritdoc}
   */
  public static function schema(FieldStorageDefinitionInterface $field_definition) {
    $schema = [
      'columns' => [
        'plugin_id' => [
          'type' => 'varchar',
          'length' => 255,
        ],
        'configuration' => [
          'description' => 'Serialized array of plugin configuration.',
          'type' => 'blob',
          'size' => 'big',
          'serialize' => TRUE,
        ],
      ],
      'indexes' => ['plugin_id' => ['plugin_id']],
    ];

    return $schema;
  }

  /**
   * {@inheritdoc}
   */
  public static function generateSampleValue(FieldDefinitionInterface $field_definition) {
    $values = [];
    $plugin_manager = \Drupal::service('plugin_reference.plugin_type_helper')->getPluginManager($field_definition->getSetting('target_type'));
    if ($plugin_manager instanceof PluginManagerInterface) {
      $definitions = $plugin_manager->getDefinitions();
      shuffle($definitions);
      $values['plugin_id'] = key($definitions);
      $values['configuration'] = [];
    }
    return $values;
  }

  /**
   * {@inheritdoc}
   */
  public function storageSettingsForm(array &$form, FormStateInterface $form_state, $has_data) {
    $elements = [];

    $elements['target_type'] = [
      '#type' => 'select',
      '#title' => new TranslatableMarkup('Type of plugin to reference'),
      '#options' => \Drupal::service('plugin_reference.plugin_type_helper')->getPluginTypeOptions(),
      '#default_value' => $this->getSetting('target_type'),
      '#required' => TRUE,
      '#disabled' => $has_data,
      '#size' => 1,
    ];

    return $elements;
  }

  /**
   * {@inheritdoc}
   */
  public function fieldSettingsForm(array $form, FormStateInterface $form_state) {
    /** @var \Drupal\Core\Entity\EntityFormInterface $form_object */
    $form_object = $form_state->getFormObject();
    /** @var \Drupal\field\FieldConfigInterface $field */
    $field = $form_object->getEntity();

    // Get all selection plugins for this plugin type.
    $plugin_reference_selection_manager = \Drupal::service('plugin.manager.plugin_reference_selection');
    $selection_plugins = $plugin_reference_selection_manager->getSelectionGroups($this->getSetting('target_type'));
    $handlers_options = [];
    foreach (array_keys($selection_plugins) as $selection_group_id) {
      // We only display base plugins (e.g. 'default', 'views', ...) and not
      // entity type specific plugins (e.g. 'default:node', 'default:user',
      // ...).
      if (array_key_exists($selection_group_id, $selection_plugins[$selection_group_id])) {
        $handlers_options[$selection_group_id] = Html::escape($selection_plugins[$selection_group_id][$selection_group_id]['label']);
      }
      elseif (array_key_exists($selection_group_id . ':' . $this->getSetting('target_type'), $selection_plugins[$selection_group_id])) {
        $selection_group_plugin = $selection_group_id . ':' . $this->getSetting('target_type');
        $handlers_options[$selection_group_plugin] = Html::escape($selection_plugins[$selection_group_id][$selection_group_plugin]['base_plugin_label']);
      }
    }

    $form = [
      '#type' => 'container',
      '#process' => [[static::class, 'fieldSettingsAjaxProcess']],
      '#element_validate' => [[static::class, 'fieldSettingsFormValidate']],

    ];
    $form['handler'] = [
      '#type' => 'details',
      '#title' => t('Reference type'),
      '#open' => TRUE,
      '#tree' => TRUE,
      '#process' => [[static::class, 'formProcessMergeParent']],
    ];

    $form['handler']['handler'] = [
      '#type' => 'select',
      '#title' => t('Reference method'),
      '#options' => $handlers_options,
      '#default_value' => $field->getSetting('handler'),
      '#required' => TRUE,
      '#ajax' => TRUE,
      '#limit_validation_errors' => [],
    ];
    $form['handler']['handler_submit'] = [
      '#type' => 'submit',
      '#value' => t('Change handler'),
      '#limit_validation_errors' => [],
      '#attributes' => [
        'class' => ['js-hide'],
      ],
      '#submit' => [[static::class, 'settingsAjaxSubmit']],
    ];

    $form['handler']['handler_settings'] = [
      '#type' => 'container',
      '#attributes' => ['class' => ['plugin_reference-settings']],
    ];

    $handler = $plugin_reference_selection_manager->getSelectionHandler($field);
    $form['handler']['handler_settings'] += $handler->buildConfigurationForm([], $form_state);

    return $form;
  }

  /**
   * Form element validation handler; Invokes selection plugin's validation.
   *
   * @param array $form
   *   The form where the settings form is being included in.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state of the (entire) configuration form.
   */
  public static function fieldSettingsFormValidate(array $form, FormStateInterface $form_state): void {
    /** @var \Drupal\Core\Entity\EntityFormInterface $form_object */
    $form_object = $form_state->getFormObject();
    $field = $form_object->getEntity();
    $handler = \Drupal::service('plugin.manager.plugin_reference_selection')->getSelectionHandler($field);
    $handler->validateConfigurationForm($form, $form_state);
  }

  /**
   * Render API callback.
   *
   * Processes the field settings form and allows access to the form state.
   *
   * @see static::fieldSettingsForm()
   */
  public static function fieldSettingsAjaxProcess(array $form, FormStateInterface $form_state): array {
    static::fieldSettingsAjaxProcessElement($form, $form);
    return $form;
  }

  /**
   * Adds plugin reference specific properties to AJAX form elements.
   *
   * @see static::fieldSettingsAjaxProcess()
   */
  public static function fieldSettingsAjaxProcessElement(array &$element, array $main_form): void {
    if (!empty($element['#ajax'])) {
      $element['#ajax'] = [
        'callback' => [static::class, 'settingsAjax'],
        'wrapper' => $main_form['#id'],
        'element' => $main_form['#array_parents'],
      ];
    }

    foreach (Element::children($element) as $key) {
      static::fieldSettingsAjaxProcessElement($element[$key], $main_form);
    }
  }

  /**
   * Render API callback.
   *
   * Moves plugin reference specific Form API elements(i.e. 'handler_settings')
   * up a level for easier processing by the validation and submission handlers.
   */
  public static function formProcessMergeParent(array $element): array {
    $parents = $element['#parents'];
    array_pop($parents);
    $element['#parents'] = $parents;
    return $element;
  }

  /**
   * Ajax callback for the handler settings form.
   *
   * @see static::fieldSettingsForm()
   */
  public static function settingsAjax(array $form, FormStateInterface $form_state): array {
    $triggering_element = (array) $form_state->getTriggeringElement();
    return NestedArray::getValue($form, $triggering_element['#ajax']['element']);
  }

  /**
   * Submit handler for the non-JS case.
   *
   * @see static::fieldSettingsForm()
   */
  public static function settingsAjaxSubmit(array $form, FormStateInterface $form_state): void {
    $form_state->setRebuild();
  }

  /**
   * {@inheritdoc}
   */
  public static function calculateDependencies(FieldDefinitionInterface $field_definition) {
    $dependencies = parent::calculateDependencies($field_definition);

    /** @var \Drupal\pluginreference\PluginTypeHelperInterface $plugin_type_helper */
    $plugin_type_helper = \Drupal::service('plugin_reference.plugin_type_helper');
    $target_type = $field_definition->getFieldStorageDefinition()->getSetting('target_type');
    $plugin_manager = $plugin_type_helper->getPluginManager($target_type);
    if (!$plugin_manager instanceof PluginManagerInterface) {
      return $dependencies;
    }

    // Depend on the modules defining the plugins stored as default value.
    if ($default_value = $field_definition->getDefaultValueLiteral()) {
      foreach ($default_value as $value) {
        if (is_array($value) && isset($value['plugin_id']) && $plugin_manager->hasDefinition($value['plugin_id'])) {
          $plugin_definition = $plugin_manager->getDefinition($value['plugin_id']);
          $dependencies['module'][] = $plugin_definition['provider'];
        }
      }
    }

    // Depend on the module providing the selection handler and the
    // dependencies provided by the selection handler.
    $selection_handler = \Drupal::service('plugin.manager.plugin_reference_selection')->getSelectionHandler($field_definition);
    if ($selection_handler instanceof PluginReferenceSelectionInterface) {
      $dependencies['module'][] = $selection_handler->getPluginDefinition()['provider'];
      $dependencies = NestedArray::mergeDeep($dependencies, $selection_handler->calculateDependencies());
    }

    return $dependencies;
  }

  /**
   * {@inheritdoc}
   */
  public static function calculateStorageDependencies(FieldStorageDefinitionInterface $field_definition) {
    $dependencies = parent::calculateStorageDependencies($field_definition);

    // Add a dependency on the module providing the plugin manager service.
    $target_type = $field_definition->getSetting('target_type');
    /** @var \Drupal\pluginreference\PluginTypeHelperInterface $plugin_type_helper */
    $plugin_type_helper = \Drupal::service('plugin_reference.plugin_type_helper');
    $provider = $plugin_type_helper->getPluginTypeProvider($target_type);
    if ($provider !== NULL) {
      $dependencies['module'][] = $provider;
    }

    return $dependencies;
  }

  /**
   * {@inheritdoc}
   */
  public static function onDependencyRemoval(FieldDefinitionInterface $field_definition, array $dependencies) {
    /** @var \Drupal\Core\Field\FieldConfigInterface $field_definition */
    $changed = parent::onDependencyRemoval($field_definition, $dependencies);

    /** @var \Drupal\pluginreference\PluginTypeHelperInterface $plugin_type_helper */
    $plugin_type_helper = \Drupal::service('plugin_reference.plugin_type_helper');
    $target_type = $field_definition->getFieldStorageDefinition()->getSetting('target_type');
    $plugin_manager = $plugin_type_helper->getPluginManager($target_type);
    if (!$plugin_manager instanceof PluginManagerInterface) {
      return FALSE;
    }

    // When config dependencies are removed, check if a module is removed
    // that provides on of the default values. When that's the case, remove
    // that default value from the field config.
    if ($default_value = $field_definition->getDefaultValueLiteral()) {
      foreach ($default_value as $key => $value) {
        if (is_array($value) && isset($value['plugin_id'])) {
          $plugin_definition = $plugin_manager->getDefinition($value['plugin_id']);

          if ($plugin_definition && isset($dependencies['module']) && in_array($plugin_definition['provider'], $dependencies['module'], TRUE)) {
            unset($default_value[$key]);
            $changed = TRUE;
          }
        }
      }
      if ($changed) {
        // Pass the values through array_values so the delta's are reset.
        $field_definition->setDefaultValue(array_values($default_value));
      }
    }

    $selection_manager_changed = FALSE;
    $selection_handler_changed = FALSE;
    /** @var \Drupal\pluginreference\PluginReferenceSelectionManagerInterface $selection_manager */
    $selection_manager = \Drupal::service('plugin.manager.plugin_reference_selection');
    $selection_handler = $selection_manager->getSelectionHandler($field_definition);
    if ($selection_handler instanceof PluginReferenceSelectionInterface) {
      $provider = $selection_handler->getPluginDefinition()['provider'];
      // When the module, providing the selection handler, is removed, fallback
      // to the default handler.
      if (isset($dependencies['module']) && in_array($provider, $dependencies['module'], TRUE)) {
        /** @var  \Drupal\pluginreference\PluginReferenceSelectionInterface $selection_handler */
        $selection_handler = $selection_manager->getInstance([
          'target_type' => $target_type,
          'handler' => 'default:' . $target_type,
        ]);
        $field_definition->setSetting('handler', $selection_handler->getPluginId());
        $default_configuration = $selection_handler->defaultConfiguration();
        unset($default_configuration['entity'], $default_configuration['target_type']);
        $field_definition->setSetting('handler_settings', $default_configuration);
        $selection_manager_changed = TRUE;
      }
      // Handle dependency removal for the selection handler.
      $selection_handler_changed = $selection_handler->onDependencyRemoval($field_definition, $dependencies);
    }

    $changed |= $selection_manager_changed | $selection_handler_changed;

    return (bool) $changed;
  }

  /**
   * {@inheritdoc}
   */
  public function isEmpty() {
    $plugin_id = $this->get('plugin_id')->getValue();
    $plugin_manager = \Drupal::service('plugin_reference.plugin_type_helper')->getPluginManager($this->getFieldDefinition()->getSetting('target_type'));
    return empty($plugin_id) || !$plugin_manager instanceof PluginManagerInterface || !$plugin_manager->hasDefinition($plugin_id);
  }

  /**
   * {@inheritdoc}
   */
  public function getConstraints() {
    $constraints = parent::getConstraints();
    // Remove the 'AllowedValuesConstraint' validation constraint because plugin
    // reference fields already use the 'ValidPluginReference' constraint.
    foreach ($constraints as $key => $constraint) {
      if ($constraint instanceof AllowedValuesConstraint) {
        unset($constraints[$key]);
      }
    }
    return $constraints;
  }

  /**
   * {@inheritdoc}
   */
  public function setValue($values, $notify = TRUE): void {
    if ($values instanceof PluginInspectionInterface) {
      $values = [
        static::mainPropertyName() => $values->getPluginId(),
        'configuration' => $values instanceof ConfigurableInterface ? $values->getConfiguration() : [],
      ];
    }
    // Treat the values as property value of the main property, if no array is
    // given.
    if (!is_array($values)) {
      $values = [static::mainPropertyName() => $values];
    }
    // Unserialize the values.
    if (isset($values['configuration']) && is_string($values['configuration'])) {
      $values['configuration'] = unserialize($values['configuration']);
    }
    // Set the default value as an empty array.
    if (!isset($values['configuration']) || empty($values['configuration'])) {
      $values['configuration'] = [];
    }
    parent::setValue($values, $notify);
  }

  /**
   * Get the initialized plugin.
   *
   * @return \Drupal\Component\Plugin\PluginBase|null
   *   The initialized plugin.
   */
  public function referencedPlugin(): ?PluginBase {
    if ($this->isEmpty()) {
      return NULL;
    }

    $plugin_id = $this->get('plugin_id')->getValue();
    $configuration = $this->get('configuration')->getValue() ?? [];
    $plugin_manager = \Drupal::service('plugin_reference.plugin_type_helper')->getPluginManager($this->getFieldDefinition()->getSetting('target_type'));
    return $plugin_manager->createInstance($plugin_id, $configuration);
  }

  /**
   * {@inheritdoc}
   */
  public static function getPreconfiguredOptions() {
    $options = [];

    /** @var \Drupal\pluginreference\PluginTypeHelperInterface $plugin_type_helper */
    $plugin_type_helper = \Drupal::service('plugin_reference.plugin_type_helper');
    $plugin_references = $plugin_type_helper->getPluginTypeIds();
    foreach ($plugin_references as $plugin_type_id) {
      if ($plugin_type_helper->pluginTypeExists($plugin_type_id)) {
        $options[$plugin_type_id] = [
          'label' => $plugin_type_helper->getPluginTypeName($plugin_type_id),
          'field_storage_config' => [
            'settings' => [
              'target_type' => $plugin_type_id,
            ],
          ],
        ];
      }
    }

    return $options;
  }

  /**
   * {@inheritdoc}
   */
  public function getPossibleValues(?AccountInterface $account = NULL) {
    return $this->getSettableValues($account);
  }

  /**
   * {@inheritdoc}
   */
  public function getPossibleOptions(?AccountInterface $account = NULL) {
    return $this->getSettableOptions($account);
  }

  /**
   * {@inheritdoc}
   */
  public function getSettableValues(?AccountInterface $account = NULL) {
    return array_keys($this->getSettableOptions($account));
  }

  /**
   * {@inheritdoc}
   */
  public function getSettableOptions(?AccountInterface $account = NULL) {
    $field_definition = $this->getFieldDefinition();
    if (!$options = \Drupal::service('plugin.manager.plugin_reference_selection')->getSelectionHandler($field_definition, $this->getEntity())->getReferenceablePlugins()) {
      return [];
    }

    return $options;
  }

}

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

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