layout_builder_ipe-1.0.x-dev/src/Controller/PageVariantController.php

src/Controller/PageVariantController.php
<?php

namespace Drupal\layout_builder_ipe\Controller;

use Drupal\Core\Form\FormState;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatch;
use Drupal\gin_lb\GinLayoutBuilderUtility;
use Drupal\layout_builder\SectionStorageInterface;
use Drupal\page_manager\PageVariantInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Defines an edit controller controller for page manager variant entities.
 *
 * @internal
 *   Controller classes are internal.
 */
class PageVariantController extends BaseController {

  /**
   * The route provider service.
   *
   * @var \Drupal\Core\Routing\RouteProviderInterface
   */
  protected $routeProvider;

  /**
   * The ctools wizard factory.
   *
   * @var \Drupal\ctools\Wizard\WizardFactoryInterface
   */
  protected $wizardFactory;

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    $instance = parent::create($container);
    $instance->routeProvider = $container->get('router.route_provider');
    $instance->wizardFactory = $container->get('ctools.wizard.factory');
    return $instance;
  }

  /**
   * Check access to the Layout Builder IPE frontend.
   *
   * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
   *   The section storage.
   *
   * @return \Drupal\Core\Access\AccessResult
   *   An access result object.
   */
  public function access(SectionStorageInterface $section_storage) {
    return $this->layoutBuilderIpe->access($section_storage);
  }

  /**
   * Get the edit part of a layout builder page.
   *
   * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
   *   The section storage.
   *
   * @return \Drupal\Core\Ajax\AjaxResponse
   *   The response containing the layout builder form.
   */
  public function edit(SectionStorageInterface $section_storage) {
    return $this->buildAjaxResponse($section_storage);
  }

  /**
   * Build an ajax response.
   *
   * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
   *   The section storage.
   *
   * @return \Drupal\Core\Ajax\AjaxResponse
   *   The response containing the layout builder form.
   */
  protected function buildAjaxResponse(SectionStorageInterface $section_storage) {
    $layout_builder_layout = NULL;
    $layout_builder_form = NULL;
    $layout_builder_message = NULL;

    /** @var \Drupal\page_manager\PageVariantInterface $entity */
    $entity = $this->layoutBuilderIpe->getEntityFromSectionStorage($section_storage);

    $editing = FALSE;
    // Get the layout builder form.
    $form_class = $entity->getEntityType()->getFormClass('layout_builder');
    if ($entity && $form_class) {
      $editing = TRUE;

      /** @var \Drupal\page_manager\Entity\Page $page */
      $page = $entity->getPage();
      $form_object = $this->classResolver->getInstanceFromDefinition($form_class);
      $form_state = new FormState();
      $form_state->setTemporaryValue('wizard', [
        'page_variant' => $entity,
        'page' => $page,
      ]);
      $layout_builder_form = $this->formBuilder()->buildForm($form_object, $form_state);
      $layout_builder_layout = $layout_builder_form['layout_builder'];
      $layout_builder_message = $layout_builder_form['layout_builder_message'] ?? NULL;
      unset($layout_builder_form['layout_builder']);
      unset($layout_builder_form['layout_builder_message']);

      $this->processPageManagerForm($layout_builder_form, $form_state, $entity, $section_storage);

      if ($form_state->isSubmitted()) {
        // If the form has been submitted, render the page variant entity to
        // replace the current form.
        $layout_builder_layout = $this->renderPageVariantEntity($entity);
        $layout_builder_form = NULL;
        // Also include any messages to notify the user about the status of
        // the operation.
        $layout_builder_message = [
          '#type' => 'container',
          '#attributes' => [
            'class' => [
              'layout-builder__message',
              'layout-builder__message--defaults',
            ],
          ],
          'message' => [
            '#theme' => 'status_messages',
            '#message_list' => $this->messenger()->all(),
            '#status_headings' => [
              'status' => $this->t('Status message'),
            ],
          ],
          '#weight' => -900,
        ];
        $this->messenger()->deleteAll();
        $editing = FALSE;
      }
    }
    return $this->ajaxResponse([
      $layout_builder_layout,
      $layout_builder_form,
      $layout_builder_message,
    ], $editing);
  }

  /**
   * Process the layout builder form as part of a page manager wizard form.
   *
   * This is complicated, but basically necessary in order to get the form
   * actions in and properly setup.
   *
   * @param array $layout_builder_form
   *   The already build form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state object.
   * @param \Drupal\page_manager\PageVariantInterface $entity
   *   The page variant entity.
   * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
   *   The section storage.
   */
  private function processPageManagerForm(array &$layout_builder_form, FormStateInterface $form_state, PageVariantInterface $entity, SectionStorageInterface $section_storage) {
    /** @var \Drupal\page_manager\Entity\Page $page */
    $page = $entity->getPage();

    // Setup some things to be able to use the wizard factory.
    $form_arg = 'Drupal\page_manager_ui\Wizard\PageEditWizard';
    $step = 'page_variant__' . $entity->id() . '__layout_builder';
    $tempstore_id = $section_storage->getPluginId() . '.' . $page->getEntityTypeId();
    $machine_name = $page->id();

    $route_name = 'entity.page.edit_form';
    $route = $this->routeProvider->getRouteByName($route_name);
    $route_match = new RouteMatch($route_name, $route, [
      'tempstore_id' => $tempstore_id,
      'page' => $page,
      'machine_name' => $machine_name,
      'step' => $step,
    ], [
      'machine_name' => $machine_name,
      'step' => $step,
    ]);
    $parameters = $route_match->getParameters()->all();
    $parameters += $form_arg::getParameters();
    $parameters['route_match'] = $route_match;

    /** @var \Drupal\page_manager_ui\Wizard\PageEditWizard $wizard */
    $wizard = $this->wizardFactory->createWizard($form_arg, $parameters);
    $wizard->initValues();
    $wizard_form = $wizard->buildForm($layout_builder_form, $form_state);
    unset($wizard_form['actions']['submit']);
    unset($wizard_form['actions']['update_and_save']);

    // Extract the actions and make some adjustments. Keep a reference to the
    // original form, which is processed later by the form builder class.
    $actions = &$wizard_form['actions'];
    $actions['#type'] = 'actions';
    $actions['#attributes']['role'] = 'region';
    $actions['#attributes']['aria-label'] = $this->t('Layout Builder tools');
    $actions['#attributes']['class'][] = 'form-actions';
    $actions['preview_toggle'] = $layout_builder_form['preview_toggle'];
    $actions['preview_toggle']['#weight'] = 10;
    unset($layout_builder_form['preview_toggle']);

    // Again, keep a reference so that form processing later just works.
    $layout_builder_form['actions'] = &$actions;

    if ($this->moduleHandler()->moduleExists('gin_lb')) {
      // To support Gin LB, we'll call their form alter and attach functions
      // directly.
      gin_lb_form_alter($layout_builder_form, $form_state, $form_state->getFormObject()->getFormId());
      GinLayoutBuilderUtility::attachGinLbForm($layout_builder_form);
      // And also fix a missing property. It's probably missing because we are
      // doing this after the form has been build and processed already.
      $layout_builder_form['actions']['preview_regions']['#name'] = 'preview_regions';
      // Add class to the submit button to make sure that the save button still
      // works.
      $layout_builder_form['actions']['finish']['#attributes']['class'][] = 'js-glb-button--primary';
    }

    // Make some more adjustments, mainly to have similar wording as in the
    // core layout manager.
    $layout_builder_form['actions']['finish']['#button_type'] = 'primary';
    $layout_builder_form['actions']['finish']['#value'] = $this->t('Save Layout');
    $layout_builder_form['actions']['cancel']['#value'] = $this->t('Discard changes');

    // And make the form ajax submittable.
    $layout_builder_form['actions']['finish']['#attributes']['class'][] = 'use-ajax-submit';
    $layout_builder_form['actions']['cancel']['#attributes']['class'][] = 'use-ajax-submit';

    // Add dependencies: https://www.drupal.org/project/drupal/issues/2897120
    $layout_builder_form['actions']['#attached']['library'][] = 'core/jquery.form';
    $layout_builder_form['actions']['#attached']['library'][] = 'core/drupal.ajax';

    // We process the form, so that handling of submission data can happen.
    $this->formBuilder()->processForm($wizard->getFormId(), $wizard_form, $form_state);

    // We also handle form submission here in order to make the entity actually
    // save. Not sure why this doesn't work out of the box like for the content
    // entity based controllers. Those ctools wizards are complicated.
    $action = $form_state->getTriggeringElement() ? end($form_state->getTriggeringElement()['#parents']) : NULL;
    if (array_key_exists($action, $actions)) {
      if ($action == 'finish') {
        $cached_values = $form_state->getTemporaryValue('wizard');
        $cached_values['id'] = $page->id();
        $cached_values['label'] = $page->label();
        $form_state->setTemporaryValue('wizard', $cached_values);
        $wizard->finish($wizard_form, $form_state);
        $entity->save();
      }
      if ($action == 'cancel' || $action == 'finish') {
        // Remove all temporary data and mark the form as submitted.
        $wizard->clearTempstore($wizard_form, $form_state);
        $this->layoutTempstoreRepository->delete($section_storage);
        $this->tempstore->get('page_manager.layout_builder')->delete($entity->id());
        $this->tempstore->get('page_manager.page_variant')->delete($entity->id());
        $form_state->setSubmitted();
      }
    }
  }

  /**
   * Render a page variant entity.
   *
   * In order to render properly, we need to simulate the original request for
   * the edited page, so that access checks and conditions can apply correctly.
   *
   * @param \Drupal\page_manager\PageVariantInterface $entity
   *   The page variant to render.
   */
  private function renderPageVariantEntity(PageVariantInterface $entity) {
    $current_path = $this->layoutBuilderIpe->getCurrentEditPath();
    if (!$current_path) {
      return NULL;
    }
    // Reload the entity so that rendering takes in the latest updates.
    $_entity = $this->entityTypeManager()->getStorage($entity->getEntityTypeId())->load($entity->id());
    $view_builder = $this->entityTypeManager()->getViewBuilder($_entity->getEntityTypeId());
    $build = $view_builder->view($_entity);
    return $build;
  }

}

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

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