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 = [],
) {
}
}
