commercetools-8.x-1.2-alpha1/modules/commercetools_demo/src/Form/CommercetoolsDemoForm.php

modules/commercetools_demo/src/Form/CommercetoolsDemoForm.php
<?php

declare(strict_types=1);

namespace Drupal\commercetools_demo\Form;

use Commercetools\Exception\NotFoundException;
use Commercetools\Exception\UnauthorizedException;
use Drupal\Core\Extension\ExtensionDiscovery;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Extension\ModuleInstallerInterface;
use Drupal\Core\Extension\ThemeHandlerInterface;
use Drupal\Core\Extension\ThemeInstallerInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Link;
use Drupal\Core\Plugin\CachedDiscoveryClearerInterface;
use Drupal\Core\Render\Markup;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Url;
use Drupal\commercetools\CommercetoolsApiServiceInterface;
use Drupal\commercetools\CommercetoolsConfiguration;
use Drupal\commercetools\CommercetoolsLocalization;
use Drupal\commercetools\Event\CommercetoolsConfigurationEvent;
use Drupal\commercetools\Exception\CommercetoolsOperationFailedException;
use Drupal\commercetools_demo\DemoConfigurationDeployer;
use Drupal\language\Entity\ConfigurableLanguage;
use GuzzleHttp\Exception\ConnectException;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Provides a Commercetools Demo setup form.
 */
class CommercetoolsDemoForm extends FormBase {

  const THEME_REPO_URL = 'https://www.drupal.org/project/';

  private const SECTION_TEMPLATE = '
    {% if data.status == "positive" %}
         {% set statusColorClass = "color-success" %}
    {% elseif data.status == "negative" %}
         {% set statusColorClass = "color-error" %}
    {% elseif data.status == "warning" %}
         {% set statusColorClass = "color-warning" %}
    {% else %}
         {% set statusColorClass = "color-error" %}
    {% endif %}
  <div class="card card-list__item">
    <div class="card__content-wrapper">
      <h3 class="card-title">{{ data.title }}: <span class="{{ statusColorClass }}">{{ data.statusText }}</h3>
      <div class="card-text">
      <p class="text-secondary">{{ data.description }}</p>
      {% for action in data.actions %}
          {{ action }}
      {% endfor %}
      </div>
      </div>
    </div>
  ';

  /**
   * The container service.
   *
   * @var \Symfony\Component\DependencyInjection\ContainerInterface
   */
  protected ContainerInterface $container;

  /**
   * The renderer service.
   *
   * @var \Drupal\Core\Render\RendererInterface
   */
  protected RendererInterface $renderer;

  /**
   * The Commercetools service.
   *
   * @var \Drupal\commercetools\CommercetoolsApiServiceInterface
   */
  protected CommercetoolsApiServiceInterface $ctApi;

  /**
   * The module handler service.
   *
   * @var \Drupal\Core\Extension\ModuleHandlerInterface
   */
  protected ModuleHandlerInterface $moduleHandler;

  /**
   * The module installer service.
   *
   * @var \Drupal\Core\Extension\ModuleInstallerInterface
   */
  protected ModuleInstallerInterface $moduleInstaller;

  /**
   * The theme handler service.
   *
   * @var \Drupal\Core\Theme\ThemeManagerInterface
   */
  protected ThemeHandlerInterface $themeHandler;

  /**
   * The theme installer service.
   *
   * @var \Drupal\Core\Extension\ThemeInstallerInterface
   */
  protected ThemeInstallerInterface $themeInstaller;

  /**
   * The commercetools configuration service.
   *
   * @var \Drupal\commercetools\CommercetoolsConfiguration
   */
  protected CommercetoolsConfiguration $ctConfig;

  /**
   * The demo configuration deployer service.
   *
   * @var \Drupal\commercetools_demo\DemoConfigurationDeployer
   */
  protected DemoConfigurationDeployer $demoConfigDeployer;

  /**
   * The event dispatcher service.
   *
   * @var \Symfony\Contracts\EventDispatcher\EventDispatcherInterface
   */
  protected $dispatcher;

  /**
   * The plugin cache clearer service.
   *
   * @var \Drupal\Core\Plugin\CachedDiscoveryClearerInterface
   */
  protected CachedDiscoveryClearerInterface $pluginCacheClearer;

  /**
   * The commercetools localization service.
   *
   * @var \Drupal\commercetools\CommercetoolsLocalization
   */
  protected CommercetoolsLocalization $ctLocalization;

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    $instance = parent::create($container);
    $instance->container = $container;
    $instance->renderer = $container->get('renderer');
    $instance->ctApi = $container->get('commercetools.api');
    $instance->moduleHandler = $container->get('module_handler');
    $instance->moduleInstaller = $container->get('module_installer');
    $instance->themeHandler = $container->get('theme_handler');
    $instance->themeInstaller = $container->get('theme_installer');
    $instance->configFactory = $container->get('config.factory');
    $instance->ctConfig = $container->get('commercetools.config');
    $instance->demoConfigDeployer = $container->get('commercetools_demo.configuration_deployer');
    $instance->dispatcher = $container->get('event_dispatcher');
    $instance->pluginCacheClearer = $container->get('plugin.cache_clearer');
    $instance->ctLocalization = $container->get('commercetools.localization');
    return $instance;
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId(): string {
    return 'commercetools_demo_commercetools_demo';
  }

  /**
   * The form section actions.
   *
   * @var array
   */
  protected array $formSectionsActions = [];

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state): array {
    $form['status']['theme'] = [
      '#type' => 'inline_template',
      '#template' => self::SECTION_TEMPLATE,
      '#context' => [
        'data' => $this->getThemeStatus(),
      ],
    ];

    $form['status']['commercetools_access'] = [
      '#type' => 'inline_template',
      '#template' => self::SECTION_TEMPLATE,
      '#context' => [
        'data' => $this->getCommercetoolsConnectionStatus(),
      ],
    ];

    $form['status']['localization'] = [
      '#type' => 'inline_template',
      '#template' => self::SECTION_TEMPLATE,
      '#context' => [
        'data' => $this->getLocalizationStatus(),
      ],
    ];

    $form['configurations']['title'] = [
      '#type' => 'html_tag',
      '#tag' => 'h2',
      '#value' => $this->t('commercetools UI modules'),
    ];
    $form['configurations']['content'] = [
      '#type' => 'inline_template',
      '#template' => self::SECTION_TEMPLATE,
      '#context' => [
        'data' => $this->getContentModuleStatus(),
      ],
    ];
    $form['configurations']['decoupled'] = [
      '#type' => 'inline_template',
      '#template' => self::SECTION_TEMPLATE,
      '#context' => [
        'data' => $this->getDecoupledModuleStatus(),
      ],
    ];

    // Add the default button, which will act (do nothing) if no matches found.
    array_unshift($this->formSectionsActions, [
      '#type' => 'submit',
      '#printed' => TRUE,
    ]);
    // To make the form actions, rendered in Twig, work well - we need to add
    // them to the form array, but skip rendering.
    $form['actions'] = $this->formSectionsActions;
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state): void {
    // All actions are implemented in the custom submit handlers.
    $form_state->setRebuild(FALSE);
  }

  /**
   * Gets the status of the theme.
   *
   * @return \Drupal\commercetools_demo\Form\FormSectionDto
   *   The theme status.
   */
  private function getThemeStatus(): FormSectionDto {
    $section = new FormSectionDto(
      title: $this->t('Bootstrap-compatible theme'),
    );

    $themeDefault = $this->demoConfigDeployer->getDefaultTheme();
    $suggestedThemes = $this->demoConfigDeployer->getSuggestedThemes();
    $themesInstalled = array_keys($this->themeHandler->listInfo());

    $extensionDiscovery = new ExtensionDiscovery($this->container->getParameter('app.root'));
    $themesDownloaded = array_keys($extensionDiscovery->scan('theme'));

    $statusMissing = -1;
    $statusDownloaded = 0;
    $statusInstalled = 1;
    $statusAlreadyActive = 2;
    foreach ($suggestedThemes as $name => $data) {
      $suggestedThemes[$name]['name'] = $name;
      if ($name === $themeDefault) {
        $suggestedThemes[$name]['status'] = $statusAlreadyActive;
      }
      elseif (in_array($name, $themesInstalled)) {
        $suggestedThemes[$name]['status'] = $statusInstalled;
      }
      elseif (in_array($name, $themesDownloaded)) {
        $suggestedThemes[$name]['status'] = $statusDownloaded;
      }
      else {
        $suggestedThemes[$name]['status'] = $statusMissing;
      }
    }
    usort($suggestedThemes, fn ($a, $b) => $b['status'] <=> $a['status']);

    $links = [
      '#theme' => 'item_list',
    ];
    $section->status = 'negative';
    foreach ($suggestedThemes as $theme) {
      $themeLink = Link::fromTextAndUrl($theme['label'], Url::fromUri(self::THEME_REPO_URL . $theme['name']))->toString();
      switch ($theme['status']) {
        case $statusAlreadyActive:
          $links['#items'][] = Markup::create($themeLink . ': <strong class="color-success">' . $this->t('Installed and used as default') . '</strong>');
          $section->status = 'positive';
          $section->statusText = $this->t('@label theme installed as default', [
            '@label' => $theme['label'],
          ]);
          break;

        case $statusMissing:
          $link = Link::fromTextAndUrl(
            $this->t('Download'),
            Url::fromUri(self::THEME_REPO_URL . $theme['name'], [
              'attributes' => [
                'class' => ['button', 'button--small'],
              ],
            ]),
          );
          $links['#items'][] = Markup::create($themeLink . ': ' . $link->toString());
          break;

        case $statusDownloaded:
        case $statusInstalled:
          if ($section->status != 'positive') {
            $section->status = 'warning';
            $section->statusText =
              $theme['status'] == $statusDownloaded
              ? $this->t('Downloaded but not installed')
              : $this->t('Installed but not enabled as default');
          }
          $action = [
            '#type' => 'submit',
            '#name' => 'set_theme_' . $theme['name'],
            '#submit' => ['::setThemeSubmitForm'],
            '#value' => match ($theme['status']) {
              $statusDownloaded => $this->t('Install and set as default'),
              $statusInstalled => $this->t('Set as default'),
            },
            '#attributes' => [
              'class' => [
                'button',
                match ($theme['status']) {
                  $statusDownloaded => 'button--secondary',
                  $statusInstalled => 'button--primary',
                },
                'button--small',
              ],
            ],
            '#theme' => $theme['name'],
          ];
          $buttonRendered = $this->renderer->renderRoot($action);
          $links['#items'][] = Markup::create($themeLink . ': ' . $buttonRendered);
          $action['#printed'] = TRUE;
          $this->formSectionsActions[] = $action;
          break;
      }
    }

    $section->description = $this->t('The module uses Bootstrap framework to render products and we recommend to use any Bootstrap-compatible Drupal theme for the Demo. But in your projects you can override the template and use any CSS framework you want. Suggested themes: @links', [
      '@links' => $this->renderer->renderRoot($links),
    ]);
    return $section;
  }

  /**
   * Gets the status of the Commercetools access configurations.
   *
   * @return \Drupal\commercetools_demo\Form\FormSectionDto
   *   The Commercetools access status.
   */
  private function getCommercetoolsConnectionStatus(): FormSectionDto {
    $section = new FormSectionDto(
      title: $this->t('commercetools connection'),
      description: $this->t('To demonstrate the functionality the module needs credentials of a commercetools account. You can use one of the provided demo accounts, using the buttons below, or configure your own account using the "Set custom credentials" button.'),
    );

    $buttonSetText = $this->t('Set demo credentials');
    $buttonExistText = $this->t('Configured now');

    $demoAccounts = $this->demoConfigDeployer->getDemoAccounts();
    $isDemoCredentialsSetUp = FALSE;
    foreach ($demoAccounts as $demoAccountKey => $demoAccountData) {
      $connectionConfig = $demoAccountData['config'][CommercetoolsConfiguration::CONFIGURATION_API];
      $isSetUp = FALSE;
      if ($this->ctConfig->isConnectionEqual($connectionConfig)) {
        $isSetUp = TRUE;
        $isDemoCredentialsSetUp = TRUE;
      }
      $button = [
        '#type' => 'submit',
        '#name' => 'set_demo_credentials_' . preg_replace("/[^A-Za-z0-9_]/", '_', $demoAccountKey),
        '#demo_account' => $demoAccountKey,
        '#submit' => ['::setDemoAccountSubmitForm'],
        '#value' => ($isSetUp ? $buttonExistText : $buttonSetText) . ': ' . $demoAccountData['name'],
        '#button_type' => 'primary',
        '#suffix' => $demoAccountData['description'] . '<br>',
      ];
      if ($isSetUp) {
        $button['#attributes']['disabled'] = 'disabled';
      }
      $this->addSectionAction($button, $section);
    }

    $this->addSectionAction([
      '#type' => 'link',
      '#title' => $this->t('Set custom credentials'),
      '#url' => Url::fromRoute('commercetools.settings'),
      '#attributes' => [
        'class' => ['button'],
      ],
    ], $section);

    if ($this->ctConfig->isConnectionConfigured()) {
      $clearCredentialsButton = [
        '#type' => 'submit',
        '#name' => 'clear_credentials',
        '#submit' => ['::clearCredentialsSubmitForm'],
        '#button_type' => 'danger',
        '#value' => $this->t('Clear credentials'),
      ];
      $this->addSectionAction($clearCredentialsButton, $section);
      if ($isDemoCredentialsSetUp) {
        $configStatus = $this->t('demo credentials');
      }
      else {
        $configStatus = $this->t('custom credentials');
      }
      try {
        $projectInfo = $this->ctApi->getProjectInfo();
        $section->status = 'positive';
        $section->statusText = $configStatus . ', ' . $this->t('project') . ' - ' . $projectInfo['name'];
      }
      catch (UnauthorizedException | ConnectException | NotFoundException | CommercetoolsOperationFailedException) {
        $section->status = 'negative';
        $connectionConfig = $this->ctConfig->getConnectionConfig();
        $section->statusText = $configStatus . ', ' . $this->t('no access to the @project_key project', [
          '@project_key' => $connectionConfig[CommercetoolsApiServiceInterface::CONFIG_PROJECT_KEY],
        ]);
      }
    }
    else {
      $section->status = 'waring';
      $section->statusText = $this->t('not configured');
    }
    return $section;
  }

  /**
   * Gets the status of the Commercetools Content module.
   *
   * @return \Drupal\commercetools_demo\Form\FormSectionDto
   *   The Commercetools Content module status.
   */
  private function getContentModuleStatus(): FormSectionDto {
    $section = new FormSectionDto(
      title: $this->t('commercetools Content'),
      description: $this->t('The commercetools Content module provides rendering of the commercetools content by the Drupal backend, with local caching.'),
    );
    $this->addDeployStatus($section, 'commercetools_content');
    return $section;
  }

  /**
   * Gets the status of the Commercetools Decoupled module.
   *
   * @return \Drupal\commercetools_demo\Form\FormSectionDto
   *   The Commercetools Decoupled module status.
   */
  private function getDecoupledModuleStatus(): FormSectionDto {
    $section = new FormSectionDto(
      title: $this->t('commercetools Decoupled'),
      description: $this->t('The commercetools Decoupled module provides rendering of the commercetools content on the frontend in the browser using decoupled Web Components.'),
    );
    $this->addDeployStatus($section, 'commercetools_decoupled');
    return $section;
  }

  /**
   * Gets the status of the Commercetools Decoupled module.
   *
   * @return \Drupal\commercetools_demo\Form\FormSectionDto
   *   The Commercetools Decoupled module status.
   */
  private function getLocalizationStatus(): FormSectionDto {
    $section = new FormSectionDto(
      title: $this->t('Multi-country and multi-currency Demo'),
      status: 'negative',
      statusText: $this->t('Not configured'),
    );
    $module = 'commercetools_demo';
    $isConnectionConfigured = $this->ctConfig->isConnectionConfigured();
    $isLanguageInstalled = $this->moduleHandler->moduleExists('language');
    $isConfigured = $this->ctLocalization->isConfigured();
    $isUiDeployed = $this->demoConfigDeployer->isDemoComponentsDeployedFor($module);
    $languagesNumber = count($this->ctLocalization->languages);
    $items = [
      '#theme' => 'item_list',
    ];
    $items['#items'][] = $this->t(
      'Drupal Language module: <span class="@class">@status</span>',
      [
        '@class' => $isLanguageInstalled ? 'color-success' : 'color-error',
        '@status' => $isLanguageInstalled ? $this->t('Installed') : $this->t(
          '<a href="@link">Not installed</a>',
          ['@link' => '/admin/modules#module-language'],
        ),
      ],
    );
    $items['#items'][] = $this->t(
      'Drupal Languages configured: <span class="@class">@status</span>',
      [
        '@class' => $languagesNumber > 1 ? 'color-success' : 'color-warning',
        '@status' => $this->formatPlural(
          $languagesNumber,
          'Single language: @list',
          '@count languages: @list',
          [
            '@list' => implode(', ', array_map(function ($language) {
              return "{$language->getId()} - {$language->getName()}";
            }, $this->ctLocalization->languages)),
          ],
        ),
      ],
    );
    $items['#items'][] = $this->t(
      'commercetools connection: <span class="@class">@status</span>',
      [
        '@class' => $isConnectionConfigured ? 'color-success' : 'color-error',
        '@status' => $isConnectionConfigured ? $this->t('Configured') : $this->t('Not configured'),
      ],
    );
    $items['#items'][] = $this->t(
      'Localization settings: <span class="@class">@status</span>',
      [
        '@class' => $isConfigured ? 'color-success' : 'color-warning',
        '@status' => $isConfigured ? $this->t('Configured') : $this->t(
          '<a href="@link">Incomplete</a>',
          ['@link' => '/admin/config/system/commercetools/store#edit-locale-settings'],
        ),
      ],
    );
    $items['#items'][] = $this->t(
      'Demo Locale switcher: <span class="@class">@status</span>',
      [
        '@class' => $isUiDeployed ? 'color-success' : 'color-warning',
        '@status' => $isUiDeployed ? $this->t('Deployed') : $this->t('Not deployed'),
      ],
    );

    if ($isLanguageInstalled && $isUiDeployed && $languagesNumber > 1) {
      $section->description = $this->t(
        'Demonstrates the multi-country, multi-currency and multi-language feature. @list Warning: Removal will delete the Drupal Languages with the codes "en", "de", "en-gb" but keeping the default language with the updated name. You can restore the previous name manually.',
        ['@list' => $this->renderer->renderRoot($items)],
      );

      $section->status = 'positive';
      $section->statusText = $this->t('Configured');
      $this->addSectionAction([
        '#type' => 'submit',
        '#submit' => ['::uninstallDemoLocalizationSubmitForm'],
        '#value' => $this->t('Remove Demo Localization'),
        '#name' => 'remove_demo_localization',
        '#button_type' => 'danger',
        '#module' => $module,
      ], $section);
    }
    else {
      $section->description = $this->t(
        'Demonstrates the multi-country, multi-currency and multi-language feature.<br/>Warning: it will create or rename the Drupal Languages with codes "en", "de", "en-gb". @list',
        ['@list' => $this->renderer->renderRoot($items)],
      );
      $action = [
        '#type' => 'submit',
        '#submit' => ['::deployDemoLocalizationSubmitForm'],
        '#value' => $this->t('Deploy Demo Localization'),
        '#name' => 'deploy_demo_localization',
        '#button_type' => 'primary',
        '#module' => $module,
      ];
      if (!$isConnectionConfigured) {
        $action['#attributes']['#disabled'] = 'disabled';
      }
      $this->addSectionAction($action, $section);
    }
    return $section;
  }

  /**
   * Adds the deployment status to a section.
   *
   * @param \Drupal\commercetools_demo\Form\FormSectionDto $section
   *   The section to add the status to.
   * @param string $module
   *   The module name.
   */
  private function addDeployStatus(FormSectionDto $section, string $module): void {
    if ($this->moduleHandler->moduleExists($module)) {
      $section->statusText = $this->t('Installed');
      $config = $this->configFactory->get("{$module}.settings");
      $catalogPath = $config->get('catalog_path');

      if ($catalogPath) {
        $this->addSectionAction([
          '#type' => 'link',
          '#title' => $this->t('Open Catalog'),
          '#url' => Url::fromUserInput($catalogPath),
          '#attributes' => [
            'class' => ['button', 'button--primary'],
          ],
        ], $section);
      }

      $configDemo = $this->demoConfigDeployer->getDemoConfig($module);
      if (
        $this->ctConfig->isEqual($configDemo, $config)
        && $this->demoConfigDeployer->isDemoComponentsDeployedFor($module)
      ) {
        $demoPage = $this->demoConfigDeployer->getDemoPage($module);
        if ($demoPage) {
          $this->addSectionAction([
            '#type' => 'link',
            '#name' => 'demo_page_' . $module,
            '#title' => $this->t('View demo article'),
            '#url' => Url::fromUserInput($demoPage->toUrl()->toString()),
            '#attributes' => [
              'class' => ['button', 'button--primary'],
            ],
          ], $section);
        }
        $section->status = 'positive';
        $section->statusText .= ' ' . $this->t('with demo configuration');
      }
      else {
        $section->statusText .= ' ' . $this->t('with custom configuration');
        $this->addSectionAction([
          '#type' => 'submit',
          '#name' => 'deploy_demo_configuration_' . $module,
          '#submit' => ['::deployDemoConfigurationSubmitForm'],
          '#value' => $this->t('Deploy Demo configuration'),
          '#module' => $module,
        ], $section);
      }

      $this->addSectionAction([
        '#type' => 'submit',
        '#name' => 'uninstall_' . $module,
        '#value' => $this->t('Uninstall the module'),
        '#submit' => ['::uninstallModuleSubmitForm'],
        '#button_type' => 'danger',
        '#module' => $module,
      ], $section);

    }
    else {
      $section->status = 'negative';
      $section->statusText = $this->t('Not installed');
      $this->addSectionAction([
        '#type' => 'submit',
        '#name' => 'install_' . $module,
        '#submit' => ['::installModuleSubmitForm'],
        '#value' => $this->t('Deploy module and UI components'),
        '#button_type' => 'primary',
        '#module' => $module,
      ], $section);
    }
  }

  /**
   * Adds an action to a section.
   *
   * @param array $action
   *   The action to add.
   * @param \Drupal\commercetools_demo\Form\FormSectionDto $section
   *   The section to add the action to.
   */
  private function addSectionAction(array $action, FormSectionDto $section) {
    $section->actions[] = $action;
    $action['#printed'] = TRUE;
    $this->formSectionsActions[] = $action;
  }

  /**
   * Sets the theme by default and installs if necessary.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   */
  public function setThemeSubmitForm(array &$form, FormStateInterface $form_state) {
    $buttonClicked = $form_state->getTriggeringElement();
    $theme = $buttonClicked['#theme'];
    if (!$this->themeHandler->themeExists($theme)) {
      $this->themeInstaller->install([$theme]);
    }
    $this->configFactory->getEditable('system.theme')->set('default', $theme)->save();
    // To prevent an error on installing Bootstrap theme:
    // Template "bootstrap_barrio:menu_columns" is not defined
    // Seems the SDC cache is not cleared properly.
    // @todo Investigate this and fill an issue on Drupal.org.
    $this->pluginCacheClearer->clearCachedDefinitions();
    $form_state->setRebuild(FALSE);
  }

  /**
   * Sets up demo connection configuration.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   */
  public function setDemoAccountSubmitForm(array &$form, FormStateInterface $form_state) {
    $account = $form_state->getTriggeringElement()['#demo_account'];
    $this->demoConfigDeployer->deployDemoAccount($account);
    $accounts = $this->demoConfigDeployer->getDemoAccounts();
    $values = $accounts[$account]['config'][CommercetoolsConfiguration::CONFIGURATION_API];
    $config = $this->ctConfig->getConnectionConfig();
    $updated = array_intersect_key($values, $config);
    $event = new CommercetoolsConfigurationEvent($updated);
    $this->dispatcher->dispatch($event);
    $form_state->setRebuild(FALSE);
  }

  /**
   * Clears the configured credentials.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   */
  public function clearCredentialsSubmitForm(array &$form, FormStateInterface $form_state) {
    $this->demoConfigDeployer->unsetConnectionConfig();
    $form_state->setRebuild(FALSE);
  }

  /**
   * Installs a module and deploys the demo configuration.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   */
  public function installModuleSubmitForm(array &$form, FormStateInterface $form_state): void {
    $module = $form_state->getTriggeringElement()['#module'];
    $this->installModule($module);
    $this->deployDemoConfigurationSubmitForm($form, $form_state);
    $form_state->setRebuild(FALSE);
  }

  /**
   * Uninstalls a module and deletes the demo configuration.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   */
  public function uninstallModuleSubmitForm(array &$form, FormStateInterface $form_state): void {
    $module = $form_state->getTriggeringElement()['#module'];
    $this->demoConfigDeployer->removeDemoComponents($module);
    $this->moduleInstaller->uninstall([$module]);
    $form_state->setRebuild(FALSE);
  }

  /**
   * Deploys all demo presets for a module.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   */
  public function deployDemoConfigurationSubmitForm(array &$form, FormStateInterface $form_state): void {
    $module = $form_state->getTriggeringElement()['#module'];
    $this->demoConfigDeployer->setDemoConfig($module);
    $this->demoConfigDeployer->deployDemoComponents($module);
    $this->demoConfigDeployer->deployDemoPages($module);

    $form_state->setRebuild(FALSE);
  }

  /**
   * Deploys a Localization demo presets.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   */
  public function deployDemoLocalizationSubmitForm(array &$form, FormStateInterface $form_state): void {
    $module = $form_state->getTriggeringElement()['#module'];
    $this->installModule('language');
    // Rename default English to "USA (English)".
    if ($lang = ConfigurableLanguage::load('en')) {
      $lang->set('label', 'USA (English)');
      $lang->save();
    }
    $this->demoConfigDeployer->deployDemoComponents($module);
    $form_state->setRebuild(FALSE);
  }

  /**
   * Removes a Localization demo presets.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   */
  public function uninstallDemoLocalizationSubmitForm(array &$form, FormStateInterface $form_state): void {
    $module = $form_state->getTriggeringElement()['#module'];
    $this->demoConfigDeployer->removeDemoComponents($module);
    $form_state->setRebuild(FALSE);
  }

  /**
   * Covers module installation.
   *
   * @param string $module
   *   A module name.
   */
  private function installModule(string $module): void {
    $this->moduleInstaller->install([$module]);
    // A workaround for the issue
    // https://www.drupal.org/project/drupal/issues/3495977
    // @todo Remove this when the proper fix is available.
    if ($this->container->has('testing.config_schema_checker')) {
      $configCheckerService = $this->container->get('testing.config_schema_checker');
      $reflection = new \ReflectionClass($configCheckerService);
      /** @var \Drupal\Core\Config\TypedConfigManagerInterface $configCheckerServiceConfigTyped */
      $configCheckerServiceConfigTyped = $reflection->getProperty('typedManager')->getValue($configCheckerService);
      $configCheckerServiceConfigTyped->clearCachedDefinitions();
    }
  }

}

/**
 * Provides a DTO for a form section.
 */
class FormSectionDto {

  public function __construct(
    public TranslatableMarkup $title,
    public string $status = 'warning',
    public TranslatableMarkup|string|null $statusText = NULL,
    public ?TranslatableMarkup $description = NULL,
    public array $actions = [],
  ) {
  }

}

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

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