Skip to content

Commit

Permalink
Refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
mamazu committed Jan 2, 2025
1 parent 32c9a0a commit cb1088a
Show file tree
Hide file tree
Showing 10 changed files with 201 additions and 119 deletions.
10 changes: 9 additions & 1 deletion src/Maker/AdminConfigurationMaker/AdminGeneratorSettings.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

class AdminGeneratorSettings
{
public bool $shouldAddMenuItem = false;
public bool $shouldAddMenuItem = true;

public bool $shouldHaveEditForm = true;

Expand All @@ -18,6 +18,14 @@ class AdminGeneratorSettings

public string $listKey;

public function __construct(
public string $resourceKey
) {
$this->slug = '/' . $resourceKey;
$this->formKey = $resourceKey;
$this->listKey = $resourceKey;
}

/** @var array<string> */
public array $listToolbarActions = [
'add', 'delete', 'export',
Expand Down
90 changes: 56 additions & 34 deletions src/Maker/AdminConfigurationMaker/MakeAdminConfigurationCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

use FriendsOfSulu\MakerBundle\Utils\ConsoleHelperTrait;
use FriendsOfSulu\MakerBundle\Utils\NameGenerators\ResourceKeyExtractor;
use FriendsOfSulu\MakerBundle\Utils\NameGenerators\UniqueNameGenerator;
use Symfony\Bundle\MakerBundle\ConsoleStyle;
use Symfony\Bundle\MakerBundle\DependencyBuilder;
use Symfony\Bundle\MakerBundle\Doctrine\DoctrineHelper;
use Symfony\Bundle\MakerBundle\Generator;
use Symfony\Bundle\MakerBundle\InputConfiguration;
use Symfony\Bundle\MakerBundle\Maker\AbstractMaker;
Expand All @@ -17,7 +17,6 @@
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Question\ChoiceQuestion;
use Webmozart\Assert\Assert;

class MakeAdminConfigurationCommand extends AbstractMaker
{
Expand All @@ -26,7 +25,9 @@ class MakeAdminConfigurationCommand extends AbstractMaker
public const ARG_RESOURCE_CLASS = 'resourceClass';
public const OPT_FORCE = 'force';
public const OPT_PERMISSIONS = 'permissions';
public const OPT_ADVANCED = 'advanced';
public const OPT_ASSUME_DEFAULTS = 'assume-defaults';

private AdminGeneratorSettings $settings;

public const ADMIN_DEPENDENCIES = [
"Sulu\Bundle\AdminBundle\Admin\Admin",
Expand All @@ -39,7 +40,7 @@ class MakeAdminConfigurationCommand extends AbstractMaker

public function __construct(
private ResourceKeyExtractor $resourceKeyExtractor,
private UniqueNameGenerator $nameGenerator
private DoctrineHelper $doctrineHelper,
) {
}

Expand All @@ -64,17 +65,35 @@ public function configureCommand(Command $command, InputConfiguration $inputConf
->addArgument(self::ARG_RESOURCE_CLASS, InputArgument::OPTIONAL, \sprintf('Class that you want to generate the list view for (eg. <fg=yellow>%s</>)', Str::asClassName(Str::getRandomTerm())))
->addOption(self::OPT_PERMISSIONS, null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'List of permissions that should be configurable')
->addOption(self::OPT_FORCE, '-f', InputOption::VALUE_NONE, 'Force the creation of a new file even if the old one is already there')
->addOption(self::OPT_ADVANCED, '-a', InputOption::VALUE_NONE, 'Show all the options. This only works for interactive prompts though')
->addOption(self::OPT_ASSUME_DEFAULTS, null, InputOption::VALUE_NONE, 'Assume default values and ask less questions')
;
}

public function interact(InputInterface $input, ConsoleStyle $io, Command $command): void
{
$this->interactiveEntityArgument($input, self::ARG_RESOURCE_CLASS, $this->doctrineHelper);

/** @var class-string $resourceClassName */
$resourceClassName = $input->getArgument(self::ARG_RESOURCE_CLASS);
$resourceKey = $this->resourceKeyExtractor->getUniqueName($resourceClassName);

$this->settings = $this->askMethodsToBeGenerated(
$io,
assumeDefaults: true === $input->getOption(self::OPT_ASSUME_DEFAULTS),
resourceKey: $resourceKey
);
}

public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator): void
{
/** @var string $className */
$className = $input->getArgument(self::ARG_RESOURCE_CLASS);
Assert::classExists($className);
$resourceKey = $this->resourceKeyExtractor->getUniqueName($className);
$generatedClassName = 'App\\Admin\\' . $this->nameGenerator->getUniqueName($className) . 'Admin';
/** @var class-string $resourceClassName */
$resourceClassName = $input->getArgument(self::ARG_RESOURCE_CLASS);

$className = $generator->createClassNameDetails(
Str::getShortClassName($resourceClassName),
namespacePrefix: 'Admin\\',
suffix: 'Admin'
);

$useStatements = new UseStatementGenerator(
\array_merge(
Expand All @@ -86,20 +105,11 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen
)
);

$settings = new AdminGeneratorSettings();

$settings->shouldAddMenuItem = $io->confirm('Do you want to have a menu entry?');
$settings->shouldHaveEditForm = $io->confirm('Do you want to have an edit form?');
$settings->shouldHaveReferences = $io->confirm('Do you want to have an a references tab?');

if ($settings->shouldHaveReferences) {
if ($this->settings->shouldHaveReferences) {
$useStatements->addUseStatement('Sulu\Bundle\ReferenceBundle\Infrastructure\Sulu\Admin\View\ReferenceViewBuilderFactoryInterface');
}

$slug = $this->askString($io, 'Enter the API slug', '/' . $resourceKey);
$settings->slug = '/' . \ltrim($slug, '/');

if (\str_contains($settings->slug, '_')) {
if (\str_contains($this->settings->slug, '_')) {
$io->warning('Your slug contains an _ this could cause problems when generating a controller for this class. It is recommended to not use underscores in the slug.');
}

Expand All @@ -122,26 +132,18 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen
/** @var array<string> $answer */
$answer = $io->askQuestion($choiceQuestion);

$settings->permissionTypes = $answer;
$this->settings->permissionTypes = $answer;
} else {
$settings->permissionTypes = $currentOptionvalue ?: $availablePermissions;
}

if ($input->hasOption(self::OPT_ADVANCED) && $input->isInteractive()) {
$settings->formKey = $this->askString($io, 'Form Key', $resourceKey);
$settings->listKey = $this->askString($io, 'List Key', $resourceKey);
} else {
$settings->formKey = $resourceKey;
$settings->listKey = $resourceKey;
$this->settings->permissionTypes = $currentOptionvalue ?: $availablePermissions;
}

$generator->generateClass(
$generatedClassName,
$className->getFullName(),
__DIR__ . '/configurationTemplate.tpl.php',
[
'use_statements' => $useStatements,
'resourceKey' => $resourceKey,
'settings' => $settings,
'resourceKey' => $this->settings->resourceKey,
'settings' => $this->settings,
]
);

Expand All @@ -154,4 +156,24 @@ public function configureDependencies(DependencyBuilder $dependencies): void
$dependencies->addClassDependency($class, 'sulu/sulu-admin');
}
}

private function askMethodsToBeGenerated(ConsoleStyle $io, bool $assumeDefaults, string $resourceKey): AdminGeneratorSettings
{
$settings = new AdminGeneratorSettings($resourceKey);
if ($assumeDefaults) {
return $settings;
}

$settings->shouldAddMenuItem = $io->confirm('Do you want to have a menu entry?');
$settings->shouldHaveEditForm = $io->confirm('Do you want to have an edit form?');
$settings->shouldHaveReferences = $io->confirm('Do you want to have an a references tab?');

$slug = $this->askString($io, 'Enter the API slug', '/' . $settings->resourceKey);
$this->settings->slug = '/' . \ltrim($slug, '/');

$settings->formKey = $this->askString($io, 'Form Key', $resourceKey);
$settings->listKey = $this->askString($io, 'List Key', $resourceKey);

return $settings;
}
}
93 changes: 61 additions & 32 deletions src/Maker/ControllerMaker/MakeControllerCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

use FriendsOfSulu\MakerBundle\Utils\ConsoleHelperTrait;
use FriendsOfSulu\MakerBundle\Utils\NameGenerators\ResourceKeyExtractor;
use FriendsOfSulu\MakerBundle\Utils\NameGenerators\UniqueNameGenerator;
use Symfony\Bundle\MakerBundle\ConsoleStyle;
use Symfony\Bundle\MakerBundle\DependencyBuilder;
use Symfony\Bundle\MakerBundle\Doctrine\DoctrineHelper;
use Symfony\Bundle\MakerBundle\Generator;
use Symfony\Bundle\MakerBundle\InputConfiguration;
use Symfony\Bundle\MakerBundle\Maker\AbstractMaker;
Expand All @@ -22,11 +22,12 @@ class MakeControllerCommand extends AbstractMaker
{
use ConsoleHelperTrait;

public const ARG_RESOURCE_CLASS = 'resourceClass';
public const ARG_CONTROLLER_NAMESPACE = 'controller_namespace';
public const OPT_FORCE = 'force';
public const ESCAPE_ROUTEKEY = 'escape_routekey';
public const OPT_ADD_TRASHING = 'add-trashing';
private const ARG_RESOURCE_CLASS = 'resourceClass';
private const OPT_ESCAPE_ROUTEKEY = 'escape-routekey';
private const OPT_ADD_TRASHING = 'add-trashing';
private const OPT_ASSUME_DEFAULTS = 'assume-defaults';

private ControllerGeneratorSettings $settings;

public const CONTROLLER_DEPENDENCIES = [
'FOS\RestBundle\Routing\ClassResourceInterface',
Expand All @@ -37,7 +38,7 @@ class MakeControllerCommand extends AbstractMaker

public function __construct(
private ResourceKeyExtractor $resourceKeyExtractor,
private UniqueNameGenerator $nameGenerator
private DoctrineHelper $doctrineHelper,
) {
}

Expand All @@ -53,47 +54,70 @@ public function getDescription(): string

public static function getCommandDescription(): string
{
return 'Create a controller that fetches data from the api';
return 'Create a controller that provides the API the admin interface uses';
}

public function configureCommand(Command $command, InputConfiguration $inputConfig): void
{
$command
->addArgument(self::ARG_RESOURCE_CLASS, InputArgument::OPTIONAL, \sprintf('Class that you want to generate the list view for (eg. <fg=yellow>%s</>)', Str::asClassName(Str::getRandomTerm())))
->addArgument(self::ARG_CONTROLLER_NAMESPACE, InputArgument::OPTIONAL, 'Namespace where the controller should be generated to', 'App\\Controller\\Admin')
->addOption(self::ESCAPE_ROUTEKEY, null, InputOption::VALUE_NONE, 'If your resource key contains underscores they will be removed')
->addOption(self::OPT_ADD_TRASHING, null, InputOption::VALUE_NONE, 'Adding trashing functionality to the controller (see sulu:make:trash)')
->addArgument(
self::ARG_RESOURCE_CLASS,
InputArgument::OPTIONAL,
\sprintf('Class that you want to generate the list view for (eg. <fg=yellow>%s</>)', Str::asClassName(Str::getRandomTerm())),
)
->addOption(
self::OPT_ESCAPE_ROUTEKEY,
null,
InputOption::VALUE_NONE,
'If your resource key contains underscores they will be removed',
)
->addOption(
self::OPT_ADD_TRASHING,
null,
InputOption::VALUE_NONE,
'Adding trashing functionality to the controller (see sulu:make:trash)',
)
->addOption(
self::OPT_ASSUME_DEFAULTS,
null,
InputOption::VALUE_NONE,
'Assume default values',
)
;
}

public function interact(InputInterface $input, ConsoleStyle $io, Command $command): void
{
$this->interactiveEntityArgument($input, self::ARG_RESOURCE_CLASS, $this->doctrineHelper);

$this->settings = $this->askMethodsToBeGenerated($io, true === $input->getOption(self::OPT_ASSUME_DEFAULTS));
$this->settings->shouldHaveTrashing = true === $input->getOption(self::OPT_ADD_TRASHING);
}

public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator): void
{
$resourceClass = self::getStringArgument($input, self::ARG_RESOURCE_CLASS);
Assert::classExists($resourceClass);

$resourceKey = $this->resourceKeyExtractor->getUniqueName($resourceClass);
$generatedClassName = \sprintf(
'%s\\%sController',
self::getStringArgument($input, self::ARG_CONTROLLER_NAMESPACE),
$this->nameGenerator->getUniqueName($resourceClass)

$generatedClassName = $generator->createClassNameDetails(
Str::getShortClassName($resourceClass),
namespacePrefix: 'Controller\\Admin\\',
suffix: 'Controller'
);

$routeResource = $resourceKey;
if (\str_contains($resourceKey, '_')) {
if (!$input->getOption(self::ESCAPE_ROUTEKEY)) {
$io->warning('Your resource key "' . $resourceKey . '" contains an underscore. If this is used as a route key this will generate routes like this: "' . \str_replace('_', '/', $resourceClass) . '". This is normally unwanted behaviour. ');
}

if ($input->getOption(self::ESCAPE_ROUTEKEY) || $io->confirm('Should the underscores (_) be removed?')) {
$io->warning('Your resource key "' . $resourceKey . '" contains an underscore. If this is used as a route key this will generate routes like this: "' . \str_replace('_', '/', $resourceClass) . '". This is normally unwanted behaviour. ');
if ($io->confirm('Should the underscores (_) be removed?', false)) {
$routeResource = \str_replace('_', '', $resourceKey);
$io->info('Removed underscore in route key');
}
}

$settings = $this->askMethodsToBeGenerated($io);
$settings->shouldHaveTrashing = true === $input->getOption(self::OPT_ADD_TRASHING);
$useStatements = self::CONTROLLER_DEPENDENCIES;
if ($settings->shouldHaveGetListAction) {
if ($this->settings->shouldHaveGetListAction) {
$useStatements =
\array_merge(
$useStatements,
Expand All @@ -107,40 +131,41 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen
);
}

if ($settings->shouldHaveTrashing) {
if ($this->settings->shouldHaveTrashing) {
$useStatements[] = 'Sulu\Bundle\TrashBundle\Application\TrashItemHandler\StoreTrashItemHandlerInterface';
}
if ($settings->needsEntityManager()) {
if ($this->settings->needsEntityManager()) {
$useStatements[] = 'Doctrine\ORM\EntityManagerInterface';
}

if ($settings->hasUpdateActions()) {
if ($this->settings->hasUpdateActions()) {
$useStatements[] = 'Symfony\Component\HttpFoundation\Request';

$io->info('Please note that if you have update actions like putAction or postAction that you need to implement the mapDataFromRequest on the generated class.');
$io->note('You need to implement the "mapDataFromRequest" on the generated class.');
}

$generator->generateClass(
$generatedClassName,
$generatedClassName->getFullName(),
__DIR__ . '/controllerTemplate.tpl.php',
[
'use_statements' => new UseStatementGenerator($useStatements),
'resourceKey' => $resourceKey,
'route_resource_key' => $resourceKey,
'resourceClass' => $resourceClass,
'settings' => $settings,
'settings' => $this->settings,
]
);

$generator->writeChanges();

$controllerClassName = $generatedClassName->getFullName();
$io->info([
'Next steps: Add the controller to the route routes in the `config/routes_admin.yaml`',
<<<YAML
app_{$resourceKey}_api:
type: rest
prefix: /admin/api
resource: $generatedClassName
resource: $controllerClassName
name_prefix: app.
YAML,
'Registering the controller in the admin panel under `config/sulu_admin.yaml`:',
Expand All @@ -162,9 +187,13 @@ public function configureDependencies(DependencyBuilder $dependencies): void
}
}

private function askMethodsToBeGenerated(ConsoleStyle $io): ControllerGeneratorSettings
private function askMethodsToBeGenerated(ConsoleStyle $io, bool $assumeDefaults): ControllerGeneratorSettings
{
$settings = new ControllerGeneratorSettings();
if ($assumeDefaults) {
return $settings;
}

$settings->shouldHaveGetListAction = $io->confirm('Should the cgetAction be generated (list view)');
$settings->shouldHaveGetAction = $io->confirm('Should the getAction be generated (single item)');
$settings->shouldHaveDeleteAction = $io->confirm('Should a deleteAction be generated');
Expand Down
Loading

0 comments on commit cb1088a

Please sign in to comment.