a12s-1.0.0-beta7/modules/page_context/src/Form/PageContextForm.php

modules/page_context/src/Form/PageContextForm.php
<?php

namespace Drupal\a12s_page_context\Form;

use Drupal\a12s_page_context\Entity\PageContextForm as PageContextFormEntity;
use Drupal\a12s_page_context\Entity\PageContextFormInterface;
use Drupal\a12s_page_context\Plugin\FormDisplayPluginInterface;
use Drupal\a12s_page_context\Plugin\FormDisplayPluginManager;
use Drupal\Component\Plugin\Exception\PluginException;
use Drupal\Component\Uuid\UuidInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Extension\Extension;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Form\SubformState;
use Drupal\Core\Serialization\Yaml;
use Drupal\Core\Utility\Error;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Page context form.
 *
 * @property \Drupal\a12s_page_context\Entity\PageContextFormInterface $entity
 */
class PageContextForm extends EntityForm implements ContainerInjectionInterface {

  /**
   * Constructs a page context form.
   *
   * @param \Drupal\a12s_page_context\Plugin\FormDisplayPluginManager $formDisplayPluginManager
   *   The manager for "page context form" plugins.
   * @param \Drupal\Component\Uuid\UuidInterface $uuidGenerator
   *   The UUID service.
   */
  public function __construct(protected FormDisplayPluginManager $formDisplayPluginManager, protected UuidInterface $uuidGenerator) {}

  /**
   * {@inheritdoc}
   * @noinspection PhpParamsInspection
   */
  public static function create(ContainerInterface $container): static {
    return new static(
      $container->get('plugin.manager.a12s_page_context_form_display'),
      $container->get('uuid')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function form(array $form, FormStateInterface $form_state): array {
    $form = parent::form($form, $form_state);
    $form['#entity_builders'][] = '::buildEntityThemeSettings';
    $form['#entity_builders'][] = '::buildEntityDisplayPlugins';

    $form['label'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Label'),
      '#maxlength' => 255,
      '#default_value' => $this->entity->label(),
      '#description' => $this->t('Label for the form.'),
      '#required' => TRUE,
    ];

    $form['id'] = [
      '#type' => 'machine_name',
      '#default_value' => $this->entity->id(),
      '#machine_name' => [
        'exists' => [static::class, 'pathIdExists'],
      ],
      '#disabled' => !$this->entity->isNew(),
    ];

    $form['status'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Enabled'),
      '#default_value' => $this->entity->status(),
    ];

    $form['description'] = [
      '#type' => 'textarea',
      '#default_value' => $this->entity->get('description'),
      '#title' => $this->t('Description'),
    ];

    $form['definition'] = [
      '#type' => 'textarea',
      '#title' => $this->t('Form content (YAML)'),
      '#default_value' => $this->entity->get('definition') ?? '',
      '#description' => $this->t('The definition of the form, using form elements from the form API.'),
      '#cols' => 60,
      '#rows' => 5,
      '#resizable' => 'vertical',
      '#attributes' => ['style' => 'min-height: 300px'],
    ];

    $form['all_themes'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Enable this page context form for all themes'),
      '#default_value' => $this->entity->get('all_themes'),
    ];

    $themes = static::getThemesList();
    $defaultThemes = $this->entity->get('themes') ?? [];
    $defaultThemes = array_intersect($defaultThemes, array_keys($themes));

    $form['themes'] = [
      '#type' => 'checkboxes',
      '#title' => $this->t('Themes'),
      '#description' => $this->t('The page context form is only available for the selected themes.'),
      '#options' => $themes,
      '#default_value' => $defaultThemes,
      '#states' => [
        'visible' => [
          ':input[name="all_themes"]' => ['checked' => FALSE],
        ],
      ],
    ];

    $form['display'] = [
      '#title' => $this->t('Display settings'),
      '#type' => 'fieldset',
      '#tree' => TRUE,
      '#prefix' => '<div id="a12s-page-context-form-display-settings-ajax-wrapper">',
      '#suffix' => '</div>',
    ];

    $form['display']['plugins'] = [
      '#type' => 'table',
      '#header' => [
        'plugin' => $this->t('Plugin'),
        'configuration' => $this->t('Configuration'),
        'operations' => $this->t('Operations'),
        'weight' => $this->t('Weight'),
      ],
      '#empty' => $this->t('You need to add some plugins if you want to use this form.'),
      '#tabledrag' => [
        [
          'action' => 'order',
          'relationship' => 'sibling',
          'group' => 'weight',
        ],
      ],
    ];

    $inUsePlugins = [];

    foreach ($this->entity->getDisplaySettings() as $uuid => $settings) {
      try {
        $configuration = $settings['configuration'] ?? [];
        /** @var \Drupal\a12s_page_context\Plugin\FormDisplayPluginInterface $plugin */
        $plugin = $this->formDisplayPluginManager->createInstance($settings['plugin_id'], $configuration);
      }
      catch (PluginException $e) {
        Error::logException(\Drupal::logger('a12s_page_context'), $e);
        continue;
      }

      $inUsePlugins[] = $plugin->getPluginId();
      $subForm = ['#parents' => ['display', 'plugins', $uuid, 'configuration']];
      $subformState = SubformState::createForSubform($subForm, $form, $form_state);
      $subForm = $plugin->buildConfigurationForm($subForm, $subformState);
      $form['display']['plugins'][$uuid] = $this->buildPluginRow($uuid, $settings['weight'], $plugin, $subForm);
    }

    $pluginOptions = array_map(
      fn(array $definition) => $definition['description'] ?? $definition['label'],
      $this->formDisplayPluginManager->getDefinitions()
    );

    $pluginOptions = array_diff_key($pluginOptions, array_flip($inUsePlugins));

    $form['display']['add'] = [
      '#type' => 'fieldset',
      '#title' => $this->t('Add a new display plugin'),
      '#attributes' => [
        'class' => ['container-inline'],
      ],
      '#access' => !empty($pluginOptions),
    ];

    $form['display']['add']['plugin_id'] = [
      '#type' => 'select',
      '#title' => $this->t('Select plugin'),
      '#title_display' => 'invisible',
      '#options' => $pluginOptions,
    ];

    $form['display']['add']['submit'] = [
      '#type' => 'button',
      '#value' => $this->t('Add'),
      '#ajax' => $this->ajaxPluginSettings(),
    ];

    return $form;
  }

  /**
   * Default AJAX settings when updating the display plugins list.
   *
   * @param string|null $message
   *   The loading message.
   *
   * @return array
   *   The AJAX settings.
   */
  protected function ajaxPluginSettings(?string $message = NULL): array {
    if (!$message) {
      $message = $this->t('Loading plugin');
    }

    return [
      'callback' => '::updateDisplayPlugins',
      'wrapper' => 'a12s-page-context-form-display-settings-ajax-wrapper',
      '#limit_validation_errors' => [],
      'progress' => [
        'type' => 'throbber',
        'message' => $message,
      ],
    ];
  }

  /**
   * Build a single row, related to the given plugin.
   */
  protected function buildPluginRow(string $uuid, int $weight, FormDisplayPluginInterface $plugin, array $configuration_form): array {
    return [
      '#weight' => $weight,
      '#attributes' => ['class' => ['draggable']],
      'plugin' => [
        'label' => ['#plain_text' => $plugin->label()],
        'plugin_id' => [
          '#type' => 'hidden',
          '#value' => $plugin->getPluginId(),
          '#parents' => ['display', 'plugins', $uuid, 'plugin_id'],
        ],
      ],
      'configuration' => $configuration_form,
      'operations' => [
        'delete' => [
          '#type' => 'button',
          '#value' => $this->t('Delete'),
          '#ajax' => $this->ajaxPluginSettings($this->t('Deleting plugin')),
          '#op' => 'delete',
          '#name' => 'delete-' . $uuid,
          '#uuid' => $uuid,
        ],
      ],
      'weight' => [
        '#type' => 'weight',
        '#title' => $this->t('Weight'),
        '#title_display' => 'invisible',
        '#default_value' => $weight,
        '#attributes' => ['class' => ['weight']],
      ],
    ];
  }

  /**
   * AJAX callback to update the display plugins.
   *
   * @param array $form
   *   The form array.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state.
   */
  public function updateDisplayPlugins(array $form, FormStateInterface $form_state): array {
    return $form['display'];
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state): void {
    parent::validateForm($form, $form_state);
    $definition = $form_state->getValue('definition');

    try {
      $data = Yaml::decode($definition);

      if (!is_array($data) && $definition) {
        throw new \Exception($this->t('YAML must contain an associative array of elements.'));
      }

      $form_state->setValueForElement($form['definition'], Yaml::encode($data));
    }
    catch (\Exception $exception) {
      $form_state->setErrorByName('definition', $exception->getMessage());
    }

    // Validate display plugin configuration. We use the "entity" property and
    // not the $form_state values, as the entity has been built from those last.
    // So the entity contains a valid configuration for the plugin.
    foreach ($this->entity->getDisplaySettings() as $uuid => $settings) {
      try {
        /** @var \Drupal\a12s_page_context\Plugin\FormDisplayPluginInterface $plugin */
        $plugin = $this->formDisplayPluginManager->createInstance($settings['plugin_id'], $settings['configuration'] ?? []);
        $subForm = &$form['display']['plugins'][$uuid]['configuration'];

        if (isset($subForm)) {
          $subformState = SubformState::createForSubform($subForm, $form, $form_state);
          $plugin->validateConfigurationForm($subForm, $subformState);
        }
      }
      catch (PluginException $e) {
        continue;
      }
    }
  }

  /**
   * Custom entity builder for handling theme settings.
   *
   * @param string $entity_type
   *   The entity type.
   * @param \Drupal\a12s_page_context\Entity\PageContextFormInterface $entity
   *   The Page Context Form entity.
   * @param array $form
   *   The form array.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   */
  public function buildEntityThemeSettings(string $entity_type, PageContextFormInterface $entity, array &$form, FormStateInterface $form_state): void {
    $themes = $form_state->getValue('themes');

    if ($form_state->getValue('all_themes')) {
      $themes = [];
    }

    $entity->setThemes(array_filter(array_values($themes)));
  }

  /**
   * Custom entity builder for handling display plugins.
   *
   * @param string $entity_type
   *   The entity type.
   * @param \Drupal\a12s_page_context\Entity\PageContextFormInterface $entity
   *   The "Page Context Form" entity.
   * @param array $form
   *   The form array.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   */
  public function buildEntityDisplayPlugins(string $entity_type, PageContextFormInterface $entity, array &$form, FormStateInterface $form_state): void {
    unset($entity->display);
    $displaySettings = [];
    $maxWeight = -10;
    $validKeys = array_flip(['plugin_id', 'weight', 'configuration']);

    foreach ($form_state->getValue(['display', 'plugins']) ?: [] as $uuid => $values) {
      try {
        /** @var \Drupal\a12s_page_context\Plugin\FormDisplayPluginInterface $plugin */
        $plugin = $this->formDisplayPluginManager->createInstance($values['plugin_id']);

        if (!empty($values['configuration'])) {
          $plugin->setConfigurationFromFormInput($values['configuration']);
          $values['configuration'] = $plugin->getConfiguration();
        }
      }
      catch (PluginException $e) {
        // Remove invalid plugin from $form_state, before validating or
        // submitting the form.
        $form_state->unsetValue(['display', 'plugins', $uuid]);
        continue;
      }

      $displaySettings[$uuid] = array_intersect_key($values, $validKeys);

      if ($values['weight'] > $maxWeight) {
        $maxWeight = $values['weight'];
      }
    }

    $triggering_element = $form_state->getTriggeringElement();
    $pluginId = $form_state->getValue(['display', 'add', 'plugin_id']);

    if ($pluginId && $triggering_element['#parents'] === ['display', 'add', 'submit']) {
      try {
        /** @var \Drupal\a12s_page_context\Plugin\FormDisplayPluginInterface $plugin */
        $plugin = $this->formDisplayPluginManager->createInstance($pluginId);
        $uuid = $this->uuidGenerator->generate();
        $displaySettings[$uuid] = [
          'plugin_id' => $plugin->getPluginId(),
          'weight' => $maxWeight,
        ];
      }
      catch (PluginException $e) {
        // $this->messenger()->addWarning('Impossible to add the requested plugin.');
      }
    }

    if (isset($triggering_element['#op']) && $triggering_element['#op'] === 'delete' && !empty($triggering_element['#uuid'])) {
      unset($displaySettings[$triggering_element['#uuid']]);
      $form_state->unsetValue(['display', 'plugins', $triggering_element['#uuid']]);
    }

    $entity->setDisplaySettings($displaySettings);
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state): void {
    foreach ($this->entity->getDisplaySettings() as $uuid => $settings) {
      $subForm = &$form['display']['plugins'][$uuid]['configuration'];

      if (isset($subForm)) {
        /** @var \Drupal\a12s_page_context\Plugin\FormDisplayPluginInterface $plugin */
        $plugin = $this->formDisplayPluginManager->createInstance($settings['plugin_id'], $settings['configuration'] ?? []);
        $subformState = SubformState::createForSubform($subForm, $form, $form_state);
        $plugin->submitConfigurationForm($subForm, $subformState);
      }
    }

    parent::submitForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function save(array $form, FormStateInterface $form_state): int {
    $result = parent::save($form, $form_state);
    $message_args = ['%label' => $this->entity->label()];
    $message = $result == SAVED_NEW
      ? $this->t('Created new page context form %label.', $message_args)
      : $this->t('Updated page context form %label.', $message_args);
    $this->messenger()->addStatus($message);
    $form_state->setRedirectUrl($this->entity->toUrl('collection'));
    return $result;
  }

  /**
   * Callback for machine_name.
   *
   * @param string $id
   *   The ID to look for.
   *
   * @return bool
   *   TRUE if the ID is found.
   */
  public static function pathIdExists(string $id): bool {
    if ($id === 'paths') {
      return TRUE;
    }

    return (bool) PageContextFormEntity::load($id);
  }

  /**
   * Get the list of actives themes.
   *
   * @return array
   *   An array whose keys are machine names and values readable names.
   */
  public static function getThemesList(): array {
    $themes = \Drupal::service('theme_handler')->listInfo();
    return array_map(fn(Extension $theme) => $theme->info['name'] ?? $theme->getName(), $themes);
  }

}

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

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