fieldry-1.0.x-dev/src/Plugin/WrapperBase.php

src/Plugin/WrapperBase.php
<?php

namespace Drupal\fieldry\Plugin;

use Drupal\Core\Plugin\PluginBase;
use Drupal\Core\Field\FieldItemInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FormatterInterface;
use Drupal\Core\Form\FormStateInterface;

/**
 * Base FieldryWrapper implementation with the most common settings.
 */
abstract class WrapperBase extends PluginBase implements ConfigurableWrapperInterface {

  /**
   * Create a new instance of a FieldryWrapperInterface plugin object.
   *
   * Overrides the defaults PluginBase::__construct() mostly to improve
   * configuration defaults setting. Since FieldWrapperInterface uses the
   * \Drupal\Component\Plugin\ConfigurableInterface we can assume a proper
   * configuration setter method, and is likely to handle any business logic
   * need to clean and prepare the configurations.
   *
   * @param array $configuration
   *   Configurations for this fieldry wrapper plugin.
   * @param string $plugin_id
   *   The unique fieldry wrapper plugin ID of this plugin.
   * @param mixed $plugin_definition
   *   The plugin definition.
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition) {
    $this->pluginId = $plugin_id;
    $this->pluginDefinition = $plugin_definition;

    // Use the static::setConfiguration() method to apply any defaults or
    // other configuration business logic before assigning.
    $this->setConfiguration($configuration);
  }

  /**
   * {@inheritdoc}
   */
  public static function isApplicable($plugin_definition, FormatterInterface $formatter, FieldDefinitionInterface $field_definition): bool {
    // @todo determine if a formatter will render individual field items
    // separately earlier so that unsupport wrappers won't show as options.
    // Currently formatters do not indicate if they render multiple or use a
    // different theme function, before building the field items.
    return empty($plugin_definition['field_types'])
      || in_array($field_definition->getType(), $plugin_definition['field_types']);
  }

  /**
   * {@inheritdoc}
   */
  public function defaultConfiguration(): array {
    return [
      'wrapper_tag' => 'div',
      'wrapper_classes' => [],
      'title_tag' => 'div',
      'title_classes' => [],
      'default_classes' => TRUE,
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function getConfiguration(): array {
    return $this->configuration;
  }

  /**
   * {@inheritdoc}
   */
  public function setConfiguration(array $configuration): void {
    $this->configuration = $configuration + $this->defaultConfiguration();
  }

  /**
   * Fetch a list of HTML tags available for use as the field wrapper.
   *
   * @return array<\Stringable|string>
   *   List of accepted HTML tags, which can be use to wrap the entire field.
   */
  public function getWrapperTagOptions(): array {
    return [
      '' => $this->t('-- NONE --'),
      'div' => 'DIV',
      'header' => 'HEADER',
      'footer' => 'FOOTER',
      'article' => 'ARTICLE',
      'blockquote' => 'BLOCKQUOTE',
      'section' => 'SECTION',
      'aside' => 'ASIDE',
    ];
  }

  /**
   * Get the outer field wrapper HTML tag.
   *
   * @return string|false
   *   The HTML tag to use for the outer field wrapper. FALSE is returned only
   *   if no wrapper should be used.
   */
  public function getWrapperTag(): string|false {
    $tag = $this->configuration['wrapper_tag'] ?? 'div';

    // Ensure that the wrapper tag is an allowed HTML tag or default to "div".
    return isset($this->getWrapperTagOptions()[$tag]) ? $tag : 'div';
  }

  /**
   * Get a list of HTML tags available for use as the field label wrapper.
   *
   * @return array<\Stringable|string>
   *   List of accepted HTML tags, which can be use to wrap the field label.
   */
  public function getTitleTagOptions(): array {
    return [
      'div' => 'DIV',
      'span' => 'SPAN',
      'p' => 'P',
      'h2' => 'H2',
      'h3' => 'H3',
      'h4' => 'H4',
      'h5' => 'H5',
      'h6' => 'H6',
    ];
  }

  /**
   * Get the HTML tag to use for the field label.
   *
   * @return string
   *   The HTML tag to use for the field label.
   */
  public function getTitleTag(): string {
    $tag = $this->configuration['title_tag'];

    // Unlike the wrapper or item tags, this cannot be empty, and must be at
    // the very least a "div" tag.
    return isset($this->getTitleTagOptions()[$tag]) ? $tag : 'div';
  }

  /**
   * Get the attributes for the field item HTML tags.
   *
   * @param \Drupal\Core\Field\FieldItemInterface $item
   *   The field item to fetch the attributes for.
   *
   * @return array
   *   Attributes array to apply to the field item HTML tag for the field item.
   */
  public function getItemAttributes(FieldItemInterface $item): array {
    return $item->_attributes ?? [];
  }

  /**
   * {@inheritdoc}
   */
  public function buildConfigurationForm(array $form, FormStateInterface $form_state): array {
    $elements = [];
    $elements['#after_build'][] = [$this, 'configurationAfterBuild'];

    $elements['wrapper_tag'] = [
      '#type' => 'select',
      '#title' => $this->t('Wrapper HTML element'),
      '#options' => $this->getWrapperTagOptions(),
      '#default_value' => $this->getWrapperTag(),
      '#description' => $this->t('HTML for wrapping the entire field label and wrappers.'),
    ];

    $elements['wrapper_classes'] = [
      '#type' => 'css_class',
      '#title' => $this->t('Wrapper CSS classes'),
      '#default_value' => $this->configuration['wrapper_classes'],
    ];

    $elements['title_tag'] = [
      '#type' => 'select',
      '#title' => $this->t('Label HTML element'),
      '#options' => $this->getTitleTagOptions(),
      '#default_value' => $this->getTitleTag(),
      '#description' => $this->t('HTML tag for wrapping the field label, when it is configured to display.'),
    ];

    $elements['title_classes'] = [
      '#type' => 'css_class',
      '#title' => $this->t('Label CSS classes'),
      '#default_value' => $this->configuration['title_classes'],
    ];

    $elements['default_classes'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Include standard field CSS classes'),
      '#default_value' => $this->configuration['default_classes'],
      '#weight' => 50,
    ];

    return $elements;
  }

  /**
   * Form after_build callback to validate options after AJAX plugin switching.
   *
   * @param array $element
   *   The wrapper plugin configuration form elements.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current form state and build information.
   *
   * @return array
   *   The updated elements with values set to defaults as needed.
   */
  public function configurationAfterBuild(array $element, FormStateInterface $form_state): array {
    $defaults = $this->defaultConfiguration();

    // Ensure a proper default value for these settings after AJAX switches the
    // the wrapper plugin. User input could have a value from the previous
    // plugin which is incompatible with the current wrapper and will show an
    // "invalid selection" error.
    // Instead just set the value to the configuration default for this plugin.
    foreach (['wrapper_tag', 'title_tag'] as $key) {
      $value = $element[$key]['#value'] ?? NULL;

      if (isset($value) && empty($element[$key]['#options'][$value])) {
        $element[$key]['#value'] = $defaults[$key];
      }
    }
    return $element;
  }

  /**
   * {@inheritdoc}
   *
   * Subclasses should override this to build the field $variables['items'] or
   * $variables['content'], this just applies the common wrapper and title
   * render properties.
   */
  public function preprocess(array $element, FieldItemListInterface $items, array &$variables): void {
    // Configure the field wrapper and CSS classnames.
    $variables['wrapper_tag'] = $this->getWrapperTag();
    $variables['title_tag'] = $this->getTitleTag();

    // Configure the field wrapper CSS classnames.
    if ($wrapperClasses = $this->configuration['wrapper_classes']) {
      $variables['attributes'] += ['class' => []];
      $variables['attributes']['class'] = array_merge($wrapperClasses, $variables['attributes']['class']);
    }

    // Configure the field label CSS classnames.
    if ($titleClasses = $this->configuration['title_classes']) {
      $variables['title_attributes'] += ['class' => []];
      $variables['title_attributes']['class'] = array_merge($titleClasses, $variables['title_attributes']['class']);
    }

    // Apply the default field classes to the wrappers?
    $variables['default_classes'] = $this->configuration['default_classes'] ?? FALSE;
  }

  /**
   * {@inheritdoc}
   */
  public function themeSuggestions(array &$suggestions, array $variables): void {
    // Only allow the altering of the theme suggestion if the default was
    // the default theme wrapper. Otherwise, we could be altering a formatter
    // that is not generating the expected field item output.
    if ($variables['theme_hook_original'] === 'field') {
      $pluginDef = $this->pluginDefinition;
      $element = $variables['element'];

      // Make this the most specific theme suggestion because it is configured
      // for a field, entity, view-mode and context (Views or entity).
      $suggestions = [
        $pluginDef['theme'],
        $pluginDef['theme'] . '__' . $element['#field_type'],
        $pluginDef['theme'] . '__' . $element['#field_name'],
        $pluginDef['theme'] . '__' . $element['#entity_type'] . '__' . $element['#bundle'],
        $pluginDef['theme'] . '__' . $element['#entity_type'] . '__' . $element['#field_name'],
        $pluginDef['theme'] . '__' . $element['#entity_type'] . '__' . $element['#bundle'] . '__' . $element['#field_name'],
      ];
    }
  }

}

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

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