Licitator 1.0
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

298 lines
10 KiB

<?php
declare(strict_types=1);
namespace Prometeo\CommandsBundle\Commands;
use Sonata\AdminBundle\Command\Validators;
use Sonata\AdminBundle\Manipulator\ServicesManipulator;
use Sonata\AdminBundle\Model\ModelManagerInterface;
use Symfony\Bundle\MakerBundle\ConsoleStyle;
use Symfony\Bundle\MakerBundle\DependencyBuilder;
use Symfony\Bundle\MakerBundle\Generator;
use Symfony\Bundle\MakerBundle\InputConfiguration;
use Symfony\Bundle\MakerBundle\Maker\AbstractMaker;
use Symfony\Bundle\MakerBundle\Util\ClassNameDetails;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\DependencyInjection\Container;
class MakeAdmin extends AbstractMaker
{
/**
* @var string
*/
private $projectDirectory;
/**
* @var string[]
*/
private $availableModelManagers;
/**
* @var string
*/
private $skeletonDirectory;
/**
* @var string
*/
private $modelClass;
/**
* @var string
*/
private $modelClassBasename;
/**
* @var string
*/
private $adminClassBasename;
/**
* @var string
*/
private $controllerClassBasename;
/**
* @var string
*/
private $managerType;
/**
* @var ModelManagerInterface
*/
private $modelManager;
public function __construct($projectDirectory, array $modelManagers = [])
{
$this->projectDirectory = $projectDirectory;
$this->availableModelManagers = $modelManagers;
$this->skeletonDirectory = __DIR__ . '/../Resources/skeleton';
}
public static function getCommandName(): string
{
return 'prometeo:make:admin';
}
public function configureCommand(Command $command, InputConfiguration $inputConfig): void
{
$command
->setDescription('Generates an admin class based on the given model class')
->addArgument('model', InputArgument::REQUIRED, 'The fully qualified model class')
->addOption('admin', 'a', InputOption::VALUE_OPTIONAL, 'The admin class basename')
->addOption('controller', 'c', InputOption::VALUE_OPTIONAL, 'The controller class basename')
->addOption('manager', 'm', InputOption::VALUE_OPTIONAL, 'The model manager type')
->addOption('services', 's', InputOption::VALUE_OPTIONAL, 'The services YAML file', 'services.yaml')
->addOption('id', 'i', InputOption::VALUE_OPTIONAL, 'The admin service ID');
$inputConfig->setArgumentAsNonInteractive('model');
}
public function interact(InputInterface $input, ConsoleStyle $io, Command $command): void
{
if ($input->getArgument('model')) {
return;
}
$io->section('Welcome to the Sonata Admin');
$this->modelClass = $io->ask(
'The fully qualified model class',
$input->getArgument('model'),
[Validators::class, 'validateClass']
);
$this->modelClassBasename = current(\array_slice(explode('\\', $this->modelClass), -1));
$this->adminClassBasename = $io->ask(
'The admin class basename',
$input->getOption('admin') ?: $this->modelClassBasename . 'Admin',
[Validators::class, 'validateAdminClassBasename']
);
if (\count($this->availableModelManagers) > 1) {
$managerTypes = array_keys($this->availableModelManagers);
$this->managerType = $io->choice('The manager type', $managerTypes, $managerTypes[0]);
$input->setOption('manager', $this->managerType);
}
if ($io->confirm('Do you want to generate a controller?', false)) {
$this->controllerClassBasename = $io->ask(
'The controller class basename',
$input->getOption('controller') ?: $this->modelClassBasename . 'AdminController',
[Validators::class, 'validateControllerClassBasename']
);
$input->setOption('controller', $this->controllerClassBasename);
}
$input->setOption('services', false);
if ($io->confirm('Do you want to update the services YAML configuration file?', true)) {
$path = $this->projectDirectory . '/config/';
$servicesFile = $io->ask(
'The services YAML configuration file',
is_file($path . 'admin.yaml') ? 'admin.yaml' : 'services.yaml',
[Validators::class, 'validateServicesFile']
);
$id = $io->ask(
'The admin service ID',
$this->getAdminServiceId($this->adminClassBasename),
[Validators::class, 'validateServiceId']
);
$input->setOption('services', $servicesFile);
$input->setOption('id', $id);
}
$input->setArgument('model', $this->modelClass);
$input->setOption('admin', $this->adminClassBasename);
}
/**
* Configure any library dependencies that your maker requires.
*/
public function configureDependencies(DependencyBuilder $dependencies): void
{
}
/**
* Called after normal code generation: allows you to do anything.
*/
public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator): void
{
$this->configure($input);
$adminClassNameDetails = $generator->createClassNameDetails(
$this->adminClassBasename,
'Admin\\',
'Admin'
);
$adminClassFullName = $adminClassNameDetails->getFullName();
$this->generateAdmin($io, $generator, $adminClassNameDetails);
$controllerClassFullName = '';
if ($this->controllerClassBasename) {
$controllerClassNameDetails = $generator->createClassNameDetails(
$this->controllerClassBasename,
'Controller\\',
'Controller'
);
$this->generateController($input, $io, $generator, $controllerClassNameDetails);
$controllerClassFullName = $controllerClassNameDetails->getFullName();
}
$this->generateService($input, $io, $adminClassFullName, $controllerClassFullName);
}
private function getAdminServiceId(string $adminClassBasename): string
{
return Container::underscore(sprintf(
'admin.%s',
str_replace('\\', '.', 'Admin' === substr($adminClassBasename, -5) ?
substr($adminClassBasename, 0, -5) : $adminClassBasename)
));
}
private function generateService(
InputInterface $input,
ConsoleStyle $io,
string $adminClassFullName,
string $controllerClassFullName
): void
{
if ($servicesFile = $input->getOption('services')) {
$file = sprintf('%s/config/%s', $this->projectDirectory, $servicesFile);
$servicesManipulator = new ServicesManipulator($file);
$controllerName = $this->controllerClassBasename ? $controllerClassFullName : '~';
$id = $input->getOption('id') ?:
$this->getAdminServiceId('App', $this->adminClassBasename);
$servicesManipulator->addResource(
$id,
$this->modelClass,
$adminClassFullName,
$controllerName,
substr($this->managerType, \strlen('sonata.admin.manager.'))
);
$io->writeln(sprintf(
'%sThe service "<info>%s</info>" has been appended to the file <info>"%s</info>".',
PHP_EOL,
$id,
realpath($file)
));
}
}
private function generateController(
InputInterface $input,
ConsoleStyle $io,
Generator $generator,
ClassNameDetails $controllerClassNameDetails
): void
{
$controllerClassFullName = null;
if ($controllerClassNameDetails) {
$controllerClassFullName = $controllerClassNameDetails->getFullName();
$generator->generateClass(
$controllerClassFullName,
__DIR__ . '/../Resources/skeleton/make/AdminController.tpl.php',
[]
);
$generator->writeChanges();
$io->writeln(sprintf(
'%sThe controller class "<info>%s</info>" has been generated under the file "<info>%s</info>".',
PHP_EOL,
$controllerClassNameDetails->getShortName(),
$controllerClassFullName
));
}
}
private function generateAdmin(
ConsoleStyle $io,
Generator $generator,
ClassNameDetails $adminClassNameDetails
): void
{
$adminClassFullName = $adminClassNameDetails->getFullName();
$fields = $this->modelManager->getExportFields($this->modelClass);
$fieldString = '';
foreach ($fields as $field) {
$fieldString = $fieldString . sprintf('%12s', '') . "->add('" . $field . "')" . PHP_EOL;
}
$fieldString .= sprintf('%12s', '');
$generator->generateClass(
$adminClassFullName,
__DIR__ . '/../Resources/skeleton/make/Admin.tpl.php',
['fields' => $fieldString]
);
$generator->writeChanges();
$io->writeln(sprintf(
'%sThe admin class "<info>%s</info>" has been generated under the file "<info>%s</info>".',
PHP_EOL,
$adminClassNameDetails->getShortName(),
$adminClassFullName
));
}
private function configure(InputInterface $input): void
{
$this->modelClass = Validators::validateClass($input->getArgument('model'));
$this->modelClassBasename = (new \ReflectionClass($this->modelClass))->getShortName();
$this->adminClassBasename = Validators::validateAdminClassBasename(
$input->getOption('admin') ?: $this->modelClassBasename . 'Admin'
);
if ($this->controllerClassBasename = $input->getOption('controller')) {
$this->controllerClassBasename = Validators::validateControllerClassBasename($this->controllerClassBasename);
}
if (0 === \count($this->availableModelManagers)) {
throw new \InvalidArgumentException('There are no model managers registered.');
}
$this->managerType = $input->getOption('manager') ?: array_keys($this->availableModelManagers)[0];
$this->modelManager = $this->availableModelManagers[$this->managerType] ?: current($this->availableModelManagers);
}
}