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

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

namespace Drupal\a12s_page_context\Entity;

use Drupal\a12s_page_context\Form\PageContextForm as ContextEditForm;
use Drupal\a12s_page_context\Plugin\FormDisplayPluginInterface;
use Drupal\a12s_page_context\RecordSet;
use Drupal\Component\Plugin\Exception\PluginException;
use Drupal\Component\Render\MarkupInterface;
use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\Core\Config\Entity\ConfigEntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Markup;
use Drupal\Core\Serialization\Yaml;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Utility\Error;

/**
 * Defines the page context form entity type.
 *
 * @ConfigEntityType(
 *   id = "a12s_page_context_form",
 *   label = @Translation("Page context form"),
 *   label_collection = @Translation("Page context forms"),
 *   label_singular = @Translation("Page context form"),
 *   label_plural = @Translation("Page context forms"),
 *   label_count = @PluralTranslation(
 *     singular = "@count page context form",
 *     plural = "@count page context forms",
 *   ),
 *   handlers = {
 *     "list_builder" =
 *   "Drupal\a12s_page_context\Entity\PageContextFormListBuilder",
 *     "form" = {
 *       "add" = "Drupal\a12s_page_context\Form\PageContextForm",
 *       "edit" = "Drupal\a12s_page_context\Form\PageContextForm",
 *       "delete" = "Drupal\Core\Entity\EntityDeleteForm",
 *     },
 *     "access" =
 *   "\Drupal\a12s_page_context\Access\PageContextFormAccessControlHandler",
 *     "route_provider" = {
 *       "html" = "Drupal\Core\Entity\Routing\AdminHtmlRouteProvider",
 *     }
 *   },
 *   config_prefix = "form",
 *   admin_permission = "administer a12s_page_context forms",
 *   links = {
 *     "collection" = "/admin/config/workflow/a12s-page-context",
 *     "add-form" = "/admin/config/workflow/a12s-page-context/add",
 *     "edit-form" =
 *   "/admin/config/workflow/a12s-page-context/{a12s_page_context_form}",
 *     "delete-form" =
 *   "/admin/config/workflow/a12s-page-context/{a12s_page_context_form}/delete"
 *   },
 *   entity_keys = {
 *     "id" = "id",
 *     "label" = "label",
 *     "uuid" = "uuid"
 *   },
 *   config_export = {
 *     "id",
 *     "label",
 *     "description",
 *     "definition",
 *     "all_themes",
 *     "themes",
 *     "display_settings"
 *   }
 * )
 */
class PageContextForm extends ConfigEntityBase implements PageContextFormInterface {

  use StringTranslationTrait;

  /**
   * The page context form ID.
   *
   * @var string
   */
  protected string $id;

  /**
   * The page context form label.
   *
   * @var string
   */
  protected string $label;

  /**
   * The page context form status.
   *
   * @var bool
   */
  protected $status;

  /**
   * The page context form description.
   *
   * @var string
   */
  protected string $description = '';

  /**
   * The definition of the form elements, as defined by the form API.
   *
   * @var string
   */
  protected string $definition;

  /**
   * Whether the page context form applies to all active themes.
   *
   * @var bool
   */
  protected bool $all_themes;

  /**
   * The list of themes for which the form is available.
   *
   * This applies only when the "all_themes" option is enabled.
   *
   * @var array
   */
  protected array $themes;

  /**
   * The list of plugins used for displaying the form.
   *
   * @var array
   */
  protected array $display_settings;

  /**
   * The list of enabled display plugin, as plugin instances.
   *
   * @var array<string, \Drupal\a12s_page_context\Plugin\FormDisplayPluginInterface>
   */
  protected array $display_plugins;

  /**
   * {@inheritdoc}
   */
  public function setThemes(array $themes): void {
    $this->themes = $themes;
  }

  /**
   * {@inheritdoc}
   */
  public function getDisplaySettings(): array {
    return $this->display_settings ?? [];
  }

  /**
   * The stored setting.
   *
   * @param array $setting
   *   The stored setting.
   *
   * @return \Drupal\a12s_page_context\Plugin\FormDisplayPluginInterface|null
   *   The plugin instance.
   */
  protected function createDisplayInstance(array $setting): ?FormDisplayPluginInterface {
    $setting += ['plugin_id' => NULL, 'configuration' => []];

    if ($setting['plugin_id']) {
      try {
        return \Drupal::service('plugin.manager.a12s_page_context_form_display')->createInstance($setting['plugin_id'], $setting['configuration']);
      }
      catch (PluginException $e) {
        Error::logException(\Drupal::logger('a12s_page_context'), $e);
      }
    }

    return NULL;
  }

  /**
   * {@inheritdoc}
   */
  public function getDisplayPlugins(): array {
    if (!isset($this->display_plugins)) {
      $initPlugins = fn($plugins, array $setting) => ($plugin = $this->createDisplayInstance($setting)) ? array_merge($plugins, [$plugin->getPluginId() => $plugin]) : $plugins;
      $this->display_plugins = array_reduce($this->getDisplaySettings(), $initPlugins, []);
    }

    return $this->display_plugins;
  }

  /**
   * {@inheritdoc}
   */
  public function getDisplayPlugin(string $pluginId): ?FormDisplayPluginInterface {
    return $this->getDisplayPlugins()[$pluginId] ?? NULL;
  }

  /**
   * {@inheritdoc}
   */
  public function setDisplaySettings(array $displaySettings): void {
    $this->display_settings = $displaySettings;
  }

  /**
   * {@inheritdoc}
   */
  public function calculateDependencies(): ConfigEntityInterface {
    parent::calculateDependencies();

    if (empty($this->all_themes)) {
      foreach ($this->themes ?? [] as $theme) {
        $this->addDependency('theme', $theme);
      }
    }

    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getFullDescription(): MarkupInterface {
    $html = [];

    if ($description = $this->get('description')) {
      $html[] = nl2br($description);
    }

    if ($this->get('all_themes')) {
      $html[] = 'Used on all themes';
    }
    else {
      $themes = ContextEditForm::getThemesList();
      $themes = array_intersect_key($themes, array_flip($this->get('themes') ?? []));
      $html[] = $this->formatPlural(count($themes), 'Used on the following theme: %themes', 'Used on the following themes: %themes', [
        '%themes' => implode(', ', $themes),
      ]);
    }

    return Markup::create(implode('<br>', $html));
  }

  /**
   * {@inheritdoc}
   */
  public function getRecords(array $context = []): RecordSet {
    return RecordSet::load($this, $context);
  }

  /**
   * {@inheritdoc}
   */
  public function getData(array $context = []): array {
    return $this->getRecords($context)->getData();
  }

  /**
   * {@inheritdoc}
   */
  public function getForm(FormDisplayPluginInterface $plugin, array $context, array $form, FormStateInterface $form_state): array {
    if (!empty($this->definition)) {
      try {
        $parents = $form['#parents'] ?? ['a12s_page_context', $this->id()];
        $record = $plugin->getRecord($this->id(), $context);
        $form['id']['#value'] = $record['id'];
        $form['key']['#value'] = $record['key'];
        $form['data'] = [];
        $context['rel'] = 'edit_form';
        // @todo How to manage several themes?
        $context += ['theme' => \Drupal::service('theme_handler')->getDefault()];

        $records = $this->getRecords($context);
        $parentValues = [];

        // Try to find parent values by priority.
        foreach ($records as $currentRecord) {
          $pluginId = $currentRecord->getPluginId();

          if ($pluginId === $plugin->getPluginId()) {
            break;
          }

          if ($displayPlugin = $this->getDisplayPlugin($pluginId)) {
            $contextCopy = $displayPlugin->getCurrentContext($context);

            // Plugins which does not have a storage key, like the "path"
            // plugin, are ignored here. This is expected as they can have
            // multiple values, and it is not possible to know which one will
            // apply.
            if ($displayPlugin->getStorageKey($contextCopy)) {
              $parentValues = $records->compileRecordData($currentRecord->getData(), $parentValues);
            }
          }
        }

        $elements = Yaml::decode($this->definition);

        if (is_array($elements)) {
          $this->buildElementsRecursive($elements, $form['data'], $record['data'], array_merge($parents, ['data']), $parentValues);
          return $form;
        }
      }
      catch (\Exception $e) {
        Error::logException(\Drupal::logger('a12s_page_context'), $e);
      }
    }

    return [];
  }

  /**
   * Build page context form elements.
   *
   * @param array $elements
   *   The page context form elements.
   * @param array $builtElements
   *   The built elements.
   * @param array $data
   *   The stored data.
   * @param array $parents
   *   The array of #parents where the field lives in the COMPLETE form, not
   *   only the subform.
   * @param array $parentValues
   *   The values defined by parent plugins.
   *
   * @todo Manage translations.
   */
  protected function buildElementsRecursive(array &$elements, array &$builtElements, array $data = [], array $parents = [], array $parentValues = []): void {
    foreach ($elements as $key => &$element) {
      // Ignore non-form elements.
      if ((isset($key[0]) && $key[0] === '#') || !is_array($element)) {
        continue;
      }

      $builtElements[$key] = ['#a12s_page_context_form_id' => $this->id()];
      $elementParents = array_merge($parents, [$key]);

      foreach ($element as $propertyKey => $value) {
        if ($propertyKey && is_string($propertyKey) && $propertyKey[0] === '#') {
          $builtElements[$key][$propertyKey] = $value;
        }
      }

      if (!empty($element['#type']) && !in_array($element['#type'], ['submit', 'button'])) {
        $elementInfo = \Drupal::service('element_info')->getInfo($element['#type']);

        if (!empty($elementInfo['#input'])) {
          if (array_key_exists($key, $data)) {
            $builtElements[$key]['#default_value'] = $data[$key];
          }

          if (array_key_exists($key, $parentValues)) {
            $overrideKey = $key . '_override';
            $override = !isset($data[$overrideKey]) || !empty($data[$overrideKey]);
            $builtElements[$key]['#parents'] = $elementParents;
            $builtElements[$key]['#wrapper_attributes']['class'][] = 'override-target';

            $overrideParents = array_merge($parents, [$overrideKey]);
            $inputName = reset($overrideParents);

            if (count($overrideParents) > 1) {
              $inputName .= '[' . implode('][', array_slice($overrideParents, 1)) . ']';
            }

            $builtElements[$key]['#states']['enabled'][':input[name="' . $inputName . '"]']['checked'] = TRUE;

            /* if (!$override) {
            $builtElements[$key]['#default_value'] = $parentValues[$key];
            }*/
            $builtElements[$key] = [
              '#type' => 'container',
              '#attributes' => ['class' => ['a12s-page-context-form-override']],
              '_override' => [
                '#type' => 'checkbox',
                '#title' => $this->t('Override'),
                '#default_value' => $override,
                '#label_attributes' => ['title' => $this->t('Override')],
                '#wrapper_attributes' => ['class' => ['override-toggle']],
                '#parents' => $overrideParents,
              ],
              '_value' => $builtElements[$key],
            ];
          }
        }
      }

      $childData = isset($data[$key]) && is_array($data[$key]) ? $data[$key] : [];
      $currentValues = isset($parentValues[$key]) && is_array($parentValues[$key]) ? $parentValues[$key] : [];
      $this->buildElementsRecursive($element, $builtElements[$key], $childData, $elementParents, $currentValues);
    }
  }

  /**
   * {@inheritdoc}
   */
  public static function alterForm(string $pluginId, array $context, array &$form, FormStateInterface $form_state, array $parents = ['a12s_page_context']): void {
    /** @var \Drupal\a12s_page_context\Entity\PageContextFormInterface $pageContextForm */
    foreach (static::loadMultiple() as $pageContextForm) {
      if ($pageContextForm->status()) {
        $plugin = $pageContextForm->getDisplayPlugin($pluginId);
        $plugin?->alterContextForm($pageContextForm, $context, $form, $form_state, $parents);
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  public static function saveRecord(array $form, FormStateInterface $formState): void {
    $logger = \Drupal::logger('a12s_page_context');

    foreach ($formState->getValue('a12s_page_context', []) as $values) {
      if (empty($values['plugin_id'])) {
        $logger->warning('Error while saving page context form: the plugin ID is missing.');
        continue;
      }

      if (empty($values['config_id'])) {
        $logger->warning('Error while saving page context form for plugin %plugin_id: the configuration ID is missing.', ['%plugin_id' => $values['plugin_id']]);
        continue;
      }

      if (!isset($values['key'])) {
        $logger->warning('Error while saving page context form for plugin %plugin_id: the key is missing.', ['%plugin_id' => $values['plugin_id']]);
        continue;
      }

      $pageContextForm = self::load($values['config_id']);

      if (!($pageContextForm instanceof PageContextFormInterface)) {
        $logger->warning('Error while saving page context form for plugin %plugin_id: the configuration ID is invalid.', ['%plugin_id' => $values['plugin_id']]);
        continue;
      }

      // Ensure the plugin_id is expected.
      if (!$pageContextForm->getDisplayPlugin($values['plugin_id'])) {
        $logger->warning('Error while saving page context form for plugin %plugin_id: the given plugin is not enabled or not valid.', ['%plugin_id' => $values['plugin_id']]);
        continue;
      }

      $connection = \Drupal::database();
      $values += [
        'settings' => [],
      ];

      if (empty($values['data'])) {
        // Delete data if we have an existing record, otherwise do nothing.
        if (!empty($values['id'])) {
          $connection->delete('a12s_page_context_record')
            ->condition('id', $values['id'])
            ->execute();
        }
      }
      else {
        if (!empty($values['id'])) {
          $status = $connection->update('a12s_page_context_record')
            ->fields([
              'data' => serialize($values['data']),
              'config_id' => $values['config_id'],
              'plugin_id' => $values['plugin_id'],
              'key' => $values['key'],
              'settings' => serialize($values['settings']),
            ])
            ->condition('id', $values['id'])
            ->execute();
        }
        else {
          $status = $connection->merge('a12s_page_context_record')
            ->fields([
              'data' => serialize($values['data']),
              'settings' => serialize($values['settings']),
            ])
            ->keys([
              'config_id' => $values['config_id'],
              'plugin_id' => $values['plugin_id'],
              'key' => $values['key'],
            ])
            ->execute();
        }

        if (!$status) {
          $logger->error('Could not save the page context form for plugin %plugin_id, with config ID %config_id and key %key.', [
            '%plugin_id' => $values['plugin_id'],
            '%config_id' => $values['config_id'],
            '%key' => $values['key'] ?: '""',
          ]);
        }
      }
    }
  }

}

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

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