devel_wizard-2.x-dev/src/Plugin/DevelWizard/Spell/ImageEffectSpell.php
src/Plugin/DevelWizard/Spell/ImageEffectSpell.php
<?php
declare(strict_types=1);
namespace Drupal\devel_wizard\Plugin\DevelWizard\Spell;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Extension\ModuleExtensionList;
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;
#[DevelWizardSpell(
id: 'devel_wizard_image_effect',
category: new TranslatableMarkup('Code'),
label: new TranslatableMarkup('Image Effect'),
description: new TranslatableMarkup('Generates a minimal code for a new ImageEffect plugin.'),
tags: [
'code' => new TranslatableMarkup('Code'),
'media' => new TranslatableMarkup('Media'),
'image' => new TranslatableMarkup('Image'),
'imageEffect' => new TranslatableMarkup('Image Effect'),
],
)]
class ImageEffectSpell extends SpellBase implements
PluginFormInterface,
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('twig'),
new Filesystem(),
);
}
/**
* {@inheritdoc}
*/
public function __construct(
array $configuration,
$plugin_id,
$plugin_definition,
MessengerInterface $messenger,
LoggerInterface $logger,
TranslationInterface $stringTranslation,
Utils $utils,
ConfigFactoryInterface $configFactory,
protected ModuleExtensionList $moduleList,
protected TwigEnvironment $twig,
protected Filesystem $fs,
) {
parent::__construct(
$configuration,
$plugin_id,
$plugin_definition,
$messenger,
$logger,
$stringTranslation,
$utils,
$configFactory,
);
}
/**
* {@inheritdoc}
*/
public function defaultConfiguration(): array {
return [
'module' => [
'machineName' => '',
],
'imageEffect' => [
'id' => '',
],
];
}
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state): array {
$conf = $this->getConfiguration();
$form['#attributes']['class'][] = 'dws--image-effect';
$form['#attached']['library'][] = 'devel_wizard/spell.image_effect';
$form['module'] = [
'#type' => 'details',
'#tree' => TRUE,
'#title' => $this->t('Module'),
'#open' => TRUE,
'machineName' => [
'#type' => 'textfield',
'#required' => TRUE,
'#title' => $this->t('Machine-name'),
'#default_value' => $conf['module']['machineName'],
'#autocomplete_route_name' => 'devel_wizard.autocomplete.module',
],
];
$form['imageEffect'] = [
'#type' => 'details',
'#tree' => TRUE,
'#title' => $this->t('Image Effect'),
'#open' => TRUE,
'id' => [
'#type' => 'textfield',
'#required' => TRUE,
'#title' => $this->t('ID'),
'#default_value' => $conf['imageEffect']['id'],
'#field_prefix' => '<module.machineName>_',
],
];
return $form;
}
/**
* {@inheritdoc}
*/
public function validateConfigurationForm(array &$form, FormStateInterface $form_state): void {
// @todo Module exists.
}
/**
* {@inheritdoc}
*/
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
$configuration = $form_state->getValue($form['#parents'], []);
$configuration['imageEffect']['id'] = sprintf(
'%s_%s',
$configuration['module']['machineName'],
$configuration['imageEffect']['id'],
);
$this->setConfiguration($configuration);
}
protected function populateCalculatedConfigurationValues(): static {
parent::populateCalculatedConfigurationValues();
if (empty($this->configuration['module']['machineName'])) {
throw new \InvalidArgumentException('module.machineName is required');
}
if (empty($this->configuration['imageEffect']['id'])) {
throw new \InvalidArgumentException('imageEffect.id is required');
}
$this->configuration['module']['dir'] = $this
->moduleList
->getPath($this->configuration['module']['machineName']);
$this->configuration['imageEffect']['idShort'] = preg_replace(
'/^' . preg_quote($this->configuration['module']['machineName']) . '_/',
'',
$this->configuration['imageEffect']['id'],
);
$this->configuration['imageEffect'] += $this->utils->stringVariants($this->configuration['imageEffect']['idShort'], 'idShort');
$this->configuration['imageEffect'] += [
'label' => $this->configuration['imageEffect']['idShortUpperCamel'],
'description' => $this->configuration['imageEffect']['idShortUpperCamel'],
'classNamespace' => sprintf(
'Drupal\\%s\\Plugin\\ImageEffect',
$this->configuration['module']['machineName'],
),
'className' => $this->configuration['imageEffect']['idShortUpperCamel'],
];
$this->configuration['imageEffect'] += [
'classFqn' => sprintf(
'%s\\%s',
$this->configuration['imageEffect']['classNamespace'],
$this->configuration['imageEffect']['className'],
),
];
$this->configuration['imageEffect'] += [
'filePath' => Path::join(
$this->configuration['module']['dir'],
$this->utils->classFqnToFilePath($this->configuration['imageEffect']['classFqn']),
),
];
$this->configuration += [
'summary' => [],
];
$this->configuration['summary'] += [
'theme' => sprintf(
'%s_image_effect_%s_summary',
$this->configuration['module']['machineName'],
$this->configuration['imageEffect']['idShort'],
),
];
$this->configuration['summary'] += [
'templateFilePath' => Path::join(
$this->configuration['module']['dir'],
'templates',
str_replace('_', '-', $this->configuration['summary']['theme']) . '.html.twig',
),
];
return $this;
}
/**
* @throws \Twig\Error\SyntaxError
* @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\LoaderError
*/
protected function doIt(): static {
$this
->doItClass()
->doItConfigSchema()
->doItSummaryHookTheme()
->doItSummaryTwig();
$this->batchContext['sandbox']['finished'] = 1.0;
return $this;
}
/**
* @throws \Twig\Error\SyntaxError
* @throws \Twig\Error\LoaderError
* @throws \Twig\Error\RuntimeError
*/
protected function doItClass(): static {
$conf = $this->getConfiguration();
$fileContent = $this->twig->render(
'@devel_wizard/spell/image_effect/class.php.twig',
$conf,
);
$this->fs->dumpFile($conf['imageEffect']['filePath'], $fileContent);
$this->messageFilesystemEntryCreate($conf['imageEffect']['filePath']);
return $this;
}
protected function doItConfigSchema(): static {
$filePath = Path::join(
$this->configuration['module']['dir'],
'config',
'schema',
"{$this->configuration['module']['machineName']}.schema.yml",
);
$entries = [
"image.effect.{$this->configuration['imageEffect']['id']}" => [
'type' => 'mapping',
'mapping' => [
'foo' => [
'type' => 'integer',
'label' => 'Foo',
],
],
],
];
$this->utils->ymlFileReplace($filePath, $entries);
$this->messageFilesystemEntryUpdate($filePath);
return $this;
}
protected function doItSummaryHookTheme(): static {
$filePath = Path::join(
$this->configuration['module']['dir'],
"{$this->configuration['module']['machineName']}.module",
);
$addition = <<< PHP
/**
* Implements hook_theme()
*/
function {$this->configuration['module']['machineName']}_theme() {
\$hooks = [];
\$hooks['{$this->configuration['summary']['theme']}'] = [
'variables' => [
'effect' => [],
'data' => NULL,
],
];
return \$hooks;
}
PHP;
if ($this->fs->exists($filePath)) {
$fileContent = file_get_contents($filePath) ?: '';
}
else {
$fileContent = <<< 'PHP'
<?php
/**
* @file
* Custom functions.
*/
declare(strict_types=1);
PHP;
}
$this->fs->dumpFile($filePath, $fileContent . "\n" . $addition);
$this->messageFilesystemEntryUpdate($filePath);
return $this;
}
/**
* @throws \Twig\Error\SyntaxError
* @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\LoaderError
*/
protected function doItSummaryTwig(): static {
$filePath = $this->configuration['summary']['templateFilePath'];
$conf = $this->getConfiguration();
$fileContent = $this->twig->render(
'@devel_wizard/spell/image_effect/summary.twig.twig',
$conf,
);
$this->fs->dumpFile($filePath, $fileContent);
$this->messageFilesystemEntryCreate($filePath);
return $this;
}
}
