fieldry-1.0.x-dev/src/FieldryWrapperFormBuilder.php

src/FieldryWrapperFormBuilder.php
<?php

namespace Drupal\fieldry;

use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Form\SubformState;
use Drupal\Core\Field\FormatterInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\fieldry\Plugin\FieldryWrapperManagerInterface;
use Drupal\fieldry\Plugin\ConfigurableWrapperInterface;

/**
 * Form builder for field wrapper plugin configurations.
 *
 * Builds form elements for configuring field wrapper plugins and containts all
 * the required callbacks to rebuild, and update form when wrapper plugins are
 * changed.
 */
class FieldryWrapperFormBuilder {

  use StringTranslationTrait;
  use DependencySerializationTrait;

  /**
   * Creates a new instance of the FieldWrapperFormBuilder object.
   *
   * @param \Drupal\fieldry\Plugin\FieldryWrapperManagerInterface $fieldWrapperManager
   *   Plugin manager for discovery and instantiation of field wrapper plugins.
   */
  public function __construct(protected FieldryWrapperManagerInterface $fieldWrapperManager) {
  }

  /**
   * Generate the form elements for configuring field wrappers for a field.
   *
   * @param array $form
   *   The entire form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   Form build info, state and values.
   * @param \Drupal\Core\Field\FormatterInterface $formatter
   *   The field formatter to configure a field wrapper for.
   * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
   *   The field definition to configure a field wrapper for.
   * @param \Drupal\Core\Session\AccountInterface $account
   *   The account to build this form element for. Field wrapper options are
   *   only available to users with the permissions to control them.
   *
   * @return array
   *   Renderable array for use as form elements in the overall field wrapper
   *   configuration form.
   */
  public function buildForm(array &$form, FormStateInterface $form_state, FormatterInterface $formatter, FieldDefinitionInterface $field_definition, AccountInterface $account): array {
    // Get the current field wrapper settings for this formatter.
    $settings = $formatter->getThirdPartySettings('fieldry') + [
      'wrapper' => 'default',
      'config' => [],
    ];

    // Check if user has permission to alter the wrapper configurations.
    // Otherwise set the current values for this third party settings and
    // do not allow the user to alter any of the existing settings.
    if ($account->hasPermission('administer fieldry field wrappers')) {
      $options = $this->fieldWrapperManager->getFieldWrappers($formatter, $field_definition);

      // Only present these form elements if there are valid field wrappers
      // available, otherwise the settings are locked in, and should only
      // be the default wrapper.
      if (!empty($options)) {
        return [
          '#type' => 'details',
          '#title' => $this->t('Field wrapper'),
          '#process' => [[$this, 'processWrapperConfig']],
          '#field_wrapper_settings' => $settings['config'],

          'wrapper' => [
            '#type' => 'select',
            '#title' => $this->t('Field wrapper type'),
            '#options' => [
              'default' => $this->t('Default field wrapper'),
            ] + $options,
            '#default_value' => $settings['wrapper'],
            '#description' => $this->t('This option only overrrides the default field theme, creating more specific field templates will still take precedence.'),
          ],
        ];
      }
    }

    // Ensure the current settings remain intact if user did not have access.
    return [
      '#type' => 'value',
      '#value' => $settings,
    ];
  }

  /**
   * Form element callback to apply AJAX and update form values.
   *
   * @param array $elements
   *   Form elements for the entire field wrapper configuration form. This is
   *   the form element to get process, and updated.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current form state, build information and values.
   * @param array $complete_form
   *   The complete form elements array, for the form being built.
   *
   * @return array
   *   Form elements processed to include the AJAX for the field wrapper
   *   configuration, and update the configuration form on wrapper type change.
   */
  public function processWrapperConfig(array $elements, FormStateInterface $form_state, array &$complete_form): array {
    $values = $form_state->getValue($elements['#parents']);
    $wrapper = $values ? $values['wrapper'] : $elements['wrapper']['#default_value'];

    if ($wrapper !== 'default') {
      try {
        // Initialize the wrapper plugin, with the current form configurations.
        $config = $values['config'] ?? $elements['#field_wrapper_settings'];
        $plugin = $this->fieldWrapperManager->createInstance($wrapper, $config);

        if ($plugin instanceof ConfigurableWrapperInterface) {
          $subform = &$elements['config'];
          $subform['#parents'] = array_merge($elements['#parents'], ['config']);
          $subform['#array_parents'] = array_merge($elements['#array_parents'], ['config']);

          $subformState = SubformState::createForSubform($subform, $complete_form, $form_state);
          $elements['config'] = $plugin->buildConfigurationForm($subform, $subformState);
        }
      }
      catch (PluginNotFoundException $e) {
        $elements['config']['#markup'] = $this->t('Field wrapper @label is not available.', [
          '@label' => $wrapper,
        ]);
      }
    }

    // Ensure a consistent wrapper for the AJAX content replace to target.
    $htmlId = Html::cleanCssIdentifier(implode('-', $elements['#array_parents'])) . '-field-wrapper-config';
    $elements['config']['#prefix'] = '<div id="' . $htmlId . '">';
    $elements['config']['#suffix'] = '</div>';
    $elements['config']['#tree'] = TRUE;

    // Update the plugin configuration when the field wrapper is changed.
    $elements['wrapper']['#ajax'] = [
      'callback' => static::class . '::updateWrapperAjax',
      'wrapper' => $htmlId,
    ];

    return $elements;
  }

  /**
   * AJAX callback to update the field wrapper configuration options.
   *
   * @param array $form
   *   Reference to the complete form elements for the configuration form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state, build information and values.
   *
   * @return \Drupal\Core\Ajax\AjaxResponse|array
   *   Either a AJAX response or renderable elements to update the field wrapper
   *   configuration form.
   */
  public static function updateWrapperAjax(array &$form, FormStateInterface $form_state): array|AjaxResponse {
    $trigger = $form_state->getTriggeringElement();
    $parents = array_slice($trigger['#array_parents'], 0, -1);
    $parents[] = 'config';

    return NestedArray::getValue($form, $parents) ?? [];
  }

}

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

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