devel_wizard-2.x-dev/src/Plugin/DevelWizard/Spell/ControllerSpell.php
src/Plugin/DevelWizard/Spell/ControllerSpell.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_controller',
category: new TranslatableMarkup('Code'),
label: new TranslatableMarkup('Controller'),
description: new TranslatableMarkup('Generates a controller.'),
tags: [
'code' => new TranslatableMarkup('Code'),
'controller' => new TranslatableMarkup('Controller'),
],
)]
class ControllerSpell 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' => '',
],
'controller' => [
'id' => '',
],
];
}
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state): array {
$conf = $this->getConfiguration();
$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['controller'] = [
'#type' => 'details',
'#tree' => TRUE,
'#title' => $this->t('Controller'),
'#open' => TRUE,
'id' => [
'#type' => 'textfield',
'#required' => TRUE,
'#title' => $this->t('ID'),
'#default_value' => $conf['controller']['id'],
],
];
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'], []);
$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['controller']['id'])) {
throw new \InvalidArgumentException('controller.id is required');
}
$this->configuration['module'] += $this->utils->stringVariants(
$this->configuration['module']['machineName'],
'machineName',
);
$this->configuration['module']['dir'] = $this
->moduleList
->getPath($this->configuration['module']['machineName']);
$this->configuration['controller'] += $this->utils->stringVariants(
$this->configuration['controller']['id'],
'id',
);
$this->configuration['controller'] += [
'classNamespace' => sprintf(
'Drupal\\%s\\Controller',
$this->configuration['module']['machineName'],
),
'className' => $this->configuration['controller']['idUpperCamel'],
];
$this->configuration['controller'] += [
'classFqn' => sprintf(
'%s\\%s',
$this->configuration['controller']['classNamespace'],
$this->configuration['controller']['className'],
),
];
$this->configuration['controller'] += [
'filePath' => Path::join(
$this->configuration['module']['dir'],
$this->utils->classFqnToFilePath($this->configuration['controller']['classFqn']),
),
];
return $this;
}
/**
* @throws \Twig\Error\SyntaxError
* @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\LoaderError
*/
protected function doIt(): static {
$this
->doItClass()
->doItRouting()
->doItLinksMenu();
$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/controller/class.php.twig',
$conf,
);
$this->fs->dumpFile($conf['controller']['filePath'], $fileContent);
$this->messageFilesystemEntryCreate($conf['controller']['filePath']);
return $this;
}
protected function doItRouting(): static {
$filePath = Path::join(
$this->configuration['module']['dir'],
"{$this->configuration['module']['machineName']}.routing.yml",
);
$entries = [
"{$this->configuration['module']['machineName']}.{$this->configuration['controller']['id']}" => [
'path' => "{$this->configuration['module']['machineNameLowerDash']}/{$this->configuration['controller']['idLowerDash']}",
'defaults' => [
'_title_callback' => "\\{$this->configuration['controller']['classFqn']}::pageTitle",
'_controller' => "\\{$this->configuration['controller']['classFqn']}::pageBody",
],
'requirements' => [
'_access' => 'TRUE',
],
],
];
$this->utils->ymlFileReplace($filePath, $entries);
$this->messageFilesystemEntryUpdate($filePath);
return $this;
}
protected function doItLinksMenu(): static {
$filePath = Path::join(
$this->configuration['module']['dir'],
"{$this->configuration['module']['machineName']}.links.menu.yml",
);
$routeName = "{$this->configuration['module']['machineName']}.{$this->configuration['controller']['id']}";
$entries = [
$routeName => [
'parent' => 'system.admin',
'weight' => 10,
'route_name' => $routeName,
'title' => 'My page title 01',
'description' => 'My page description 01',
],
];
$this->utils->ymlFileReplace($filePath, $entries);
$this->messageFilesystemEntryUpdate($filePath);
return $this;
}
}
