devel_wizard-2.x-dev/src/Plugin/DevelWizard/Spell/ThemeClaroSpell.php
src/Plugin/DevelWizard/Spell/ThemeClaroSpell.php
<?php
declare(strict_types=1);
namespace Drupal\devel_wizard\Plugin\DevelWizard\Spell;
use Drupal\Component\Plugin\ConfigurableInterface;
use Drupal\Component\Serialization\Yaml;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Extension\ModuleExtensionList;
use Drupal\Core\Extension\ProfileExtensionList;
use Drupal\Core\Extension\ThemeExtensionList;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Plugin\PluginFormInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\Core\Template\TwigEnvironment;
use Drupal\devel_wizard\Attribute\DevelWizardSpell;
use Drupal\devel_wizard\Utils;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Filesystem\Path;
use Symfony\Component\String\UnicodeString;
#[DevelWizardSpell(
id: 'devel_wizard_theme_claro',
category: new TranslatableMarkup('Code'),
label: new TranslatableMarkup('Theme based on Claro'),
description: new TranslatableMarkup('Generates a new Theme based on Claro.'),
tags: [
'code' => new TranslatableMarkup('Code'),
'theme' => new TranslatableMarkup('Theme'),
],
)]
class ThemeClaroSpell extends SpellBase implements
PluginFormInterface,
ConfigurableInterface,
ContainerFactoryPluginInterface {
public static function create(
ContainerInterface $container,
array $configuration,
$plugin_id,
$plugin_definition,
) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('messenger'),
$container->get('logger.channel.devel_wizard_spell'),
$container->get('string_translation'),
$container->get('devel_wizard.utils'),
$container->get('config.factory'),
$container->get('extension.list.module'),
$container->get('extension.list.theme'),
$container->get('extension.list.profile'),
$container->get('twig'),
new Filesystem(),
);
}
public function __construct(
array $configuration,
$plugin_id,
$plugin_definition,
MessengerInterface $messenger,
LoggerInterface $logger,
TranslationInterface $stringTranslation,
Utils $utils,
ConfigFactoryInterface $configFactory,
protected ModuleExtensionList $moduleList,
protected ThemeExtensionList $themeList,
protected ProfileExtensionList $profileList,
protected TwigEnvironment $twig,
protected Filesystem $fs,
) {
parent::__construct(
$configuration,
$plugin_id,
$plugin_definition,
$messenger,
$logger,
$stringTranslation,
$utils,
$configFactory,
);
}
/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
// @todo Is standalone?
return [
'machineNameLowerUnderscore' => '',
];
}
protected function populateCalculatedConfigurationValues(): static {
parent::populateCalculatedConfigurationValues();
if (empty($this->configuration['machineNameLowerUnderscore'])) {
throw new \InvalidArgumentException(sprintf(
'%s can not be empty',
'machineNameLowerUnderscore',
));
}
$machineName = $this->configuration['machineNameLowerUnderscore'];
$this->configuration['baseDir'] = "themes/custom/$machineName";
$this->configuration['machineNameLowerDash'] = str_replace('_', '-', $machineName);
$this->configuration['machineNameLowerCamel'] = (new UnicodeString($machineName))
->camel()
->toString();
$this->configuration['machineNameUpperCamel'] = (new UnicodeString("a_{$machineName}"))
->camel()
->trimPrefix('a')
->toString();
return $this;
}
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$conf = $this->getConfiguration();
$form['machineNameLowerUnderscore'] = [
'#type' => 'machine_name',
'#default_value' => $conf['machineNameLowerUnderscore'],
'#maxlength' => 64,
'#description' => $this->t('A unique name for the new theme. It must only contain lowercase letters, numbers, and underscores.'),
'#machine_name' => [
'exists' => [$this, 'exists'],
'source' => [],
'standalone' => TRUE,
],
'#autocomplete_route_name' => 'devel_wizard.autocomplete.extension_all',
];
return $form;
}
/**
* {@inheritdoc}
*/
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
// @todo Implement validateConfigurationForm() method.
}
/**
* {@inheritdoc}
*/
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
$values = $form_state->getValue($form['#parents'], []);
$this->setConfiguration($values);
}
public function exists(string $machine_name): bool {
return array_key_exists($machine_name, $this->moduleList->getList())
|| array_key_exists($machine_name, $this->themeList->getList())
|| array_key_exists($machine_name, $this->profileList->getList());
}
/**
* @throws \Twig\Error\Error
*/
protected function doIt(): static {
$this->doItCode();
drupal_flush_all_caches();
$this->batchContext['finished'] = 1.0;
return $this;
}
/**
* @throws \Twig\Error\Error
*/
protected function doItCode(): static {
foreach ($this->getYamlFiles() as $filePath => $fileContent) {
$this->fs->mkdir(Path::getDirectory($filePath));
$this->fs->dumpFile($filePath, Yaml::encode($fileContent));
$this->messageFilesystemEntryCreate($filePath);
}
foreach ($this->getTwigFiles() as $dstFilePath => $template) {
$dstFileContent = $this->twig->render(
$template,
$this->configuration,
);
$this->fs->mkdir(Path::getDirectory($dstFilePath));
$this->fs->dumpFile($dstFilePath, $dstFileContent);
$this->messageFilesystemEntryCreate($dstFilePath);
}
foreach ($this->getFilesToCopy() as $src => $dst) {
$this->fs->copy($src, $dst);
}
return $this;
}
protected function getYamlFiles(): array {
return $this->getYamlFilesInfo()
+ $this->getYamlFilesConfig()
+ $this->getYamlFilesOther();
}
protected function getYamlFilesInfo(): array {
$machineName = $this->configuration['machineNameLowerUnderscore'];
$versionParts = explode('.', \Drupal::VERSION);
$baseDir = $this->configuration['baseDir'];
return [
"$baseDir/$machineName.info.yml" => [
'type' => 'theme',
'core_version_requirement' => sprintf(
'^%d.%d',
$versionParts[0],
$versionParts[1],
),
'name' => $this->configuration['machineNameLowerUnderscore'],
'description' => 'Useless description.',
'base theme' => 'claro',
'screenshot' => 'screenshot.png',
'regions' => [
'header' => 'Header',
'pre_content' => 'Pre-content',
'breadcrumb' => 'Breadcrumb',
'highlighted' => 'Highlighted',
'help' => 'Help',
'content' => 'Content',
'sidebar_first' => 'First sidebar',
'footer_top' => 'Footer Top',
'footer_bottom' => 'Footer Bottom',
'page_top' => 'Page top',
'page_bottom' => 'Page bottom',
],
'regions_hidden' => [
'sidebar_first',
],
'libraries' => [
"$machineName/global-styling",
],
'libraries-extend' => [
'module_filter/modules.tabs' => [
"$machineName/module_filter.tabs",
],
'toolbar/toolbar' => [
"$machineName/toolbar.toolbar",
],
'views_ui/admin.styling' => [
"$machineName/views_ui.admin.styling",
],
'type_tray/type_tray' => [
"$machineName/type_tray.type_tray",
],
],
],
];
}
protected function getYamlFilesConfig(): array {
$machineName = $this->configuration['machineNameLowerUnderscore'];
$baseDir = $this->configuration['baseDir'];
return [
"$baseDir/config/schema/$machineName.settings.yml" => [
"$machineName.settings" => [
'type' => 'theme_settings',
'label' => "{$this->configuration['machineNameLowerUnderscore']} - Backend theme settings",
],
],
"$baseDir/config/install/$machineName.settings.yml" => [
'features' => [
'comment_user_picture' => TRUE,
'comment_user_verification' => TRUE,
'favicon' => TRUE,
'node_user_picture' => TRUE,
],
'favicon' => [
'mimetype' => 'image/svg+xml',
'path' => "themes/custom/$machineName/favicon.svg",
'url' => "/themes/custom/$machineName/favicon.svg",
'use_default' => FALSE,
],
'logo' => [
'path' => '',
'url' => '',
'use_default' => TRUE,
],
],
];
}
protected function getYamlFilesOther(): array {
$machineName = $this->configuration['machineNameLowerUnderscore'];
$baseDir = $this->configuration['baseDir'];
return [
"$baseDir/$machineName.libraries.yml" => [
'global-styling' => [
'css' => [
'component' => [
"library/$machineName.global-styling/fieldset.css" => [],
],
],
],
'table-sort' => [
'js' => [
"library/$machineName.table-sort/lib.js" => [],
"library/$machineName.table-sort/db.js" => [],
],
'css' => [
'base' => [
"library/$machineName.table-sort/base.css" => [],
],
],
'dependencies' => [
'core/jquery.once',
],
],
'module_filter.tabs' => [
'js' => [
'library/module_filter.tabs/index.js' => [],
],
'css' => [
'theme' => [
'library/module_filter.tabs/theme.css' => [],
],
],
],
'toolbar.toolbar' => [
'css' => [
'theme' => [
'/modules/contrib/devel_wizard/css/toolbar.icon.theme.css' => [],
],
],
],
'type_tray.type_tray' => [
'css' => [
'theme' => [
'library/type_tray.type_tray/theme.css' => [],
],
],
],
'views_ui.admin.styling' => [
'css' => [
'theme' => [
'library/views_ui.admin.styling/theme.css' => [],
],
],
],
],
"$baseDir/$machineName.breakpoints.yml" => [
"$machineName.sm" => [
'label' => 'Small',
'mediaQuery' => 'all and (min-width: 500px)',
'weight' => 0,
'multipliers' => ['1x'],
],
"$machineName.md" => [
'label' => 'Medium',
'mediaQuery' => 'all and (min-width: 700px)',
'weight' => 1,
'multipliers' => ['1x'],
],
"$machineName.lg" => [
'label' => 'Large',
'mediaQuery' => 'all and (min-width: 1000px)',
'weight' => 2,
'multipliers' => ['1x'],
],
"$machineName.xl" => [
'label' => 'X-Large',
'mediaQuery' => 'all and (min-width: 1300px)',
'weight' => 3,
'multipliers' => ['1x'],
],
"$machineName.nav-md" => [
'label' => 'Nav Medium',
'mediaQuery' => 'all and (min-width: 500px)',
'weight' => 4,
'multipliers' => ['1x'],
],
"$machineName.nav" => [
'label' => 'Nav',
'mediaQuery' => 'all and (min-width: 1200px)',
'weight' => 5,
'multipliers' => ['1x'],
],
"$machineName.grid-md" => [
'label' => 'Grid Medium',
'mediaQuery' => 'all and (min-width: 700px)',
'weight' => 6,
'multipliers' => ['1x'],
],
"$machineName.grid-max" => [
'label' => 'Grid Max',
'mediaQuery' => 'all and (min-width: 1440px)',
'weight' => 7,
'multipliers' => ['1x'],
],
],
];
}
protected function getTwigFiles(): array {
$machineName = $this->configuration['machineNameLowerUnderscore'];
$baseDir = $this->configuration['baseDir'];
return [
"$baseDir/library/$machineName.global-styling/fieldset.scss" => '@devel_wizard/spell/theme_claro/library/global-styling/fieldset.css.twig',
"$baseDir/library/module_filter.tabs/index.js" => '@devel_wizard/spell/theme_claro/library/module_filter.tabs/index.js.twig',
"$baseDir/library/module_filter.tabs/theme.scss" => '@devel_wizard/spell/theme_claro/library/module_filter.tabs/theme.css.twig',
"$baseDir/library/table-sort/base.scss" => '@devel_wizard/spell/theme_claro/library/table-sort/base.css.twig',
"$baseDir/library/table-sort/db.js" => '@devel_wizard/spell/theme_claro/library/table-sort/db.js.twig',
"$baseDir/library/table-sort/lib.js" => '@devel_wizard/spell/theme_claro/library/table-sort/lib.js.twig',
"$baseDir/library/type_tray.type_tray/theme.scss" => '@devel_wizard/spell/theme_claro/library/type_tray.type_tray/theme.css.twig',
"$baseDir/library/views_ui.admin.styling/theme.scss" => '@devel_wizard/spell/theme_claro/library/views_ui.admin.styling/theme.css.twig',
];
}
protected function getFilesToCopy(): array {
$baseDir = $this->configuration['baseDir'];
return [
'core/themes/claro/screenshot.png' => "$baseDir/screenshot.png",
'core/themes/claro/logo.svg' => "$baseDir/logo.svg",
"$baseDir/logo.svg" => "$baseDir/favicon.svg",
];
}
}
