322 lines
10 KiB
PHP
322 lines
10 KiB
PHP
<?php declare(strict_types=1);
|
|
|
|
/*
|
|
* This file is part of the Symfony MakerBundle package.
|
|
*
|
|
* (c) Fabien Potencier <fabien@symfony.com>
|
|
*
|
|
* For the full copyright and license information, please view the LICENSE
|
|
* file that was distributed with this source code.
|
|
*/
|
|
|
|
namespace App\Maker;
|
|
|
|
use Doctrine\Bundle\DoctrineBundle\DoctrineBundle;
|
|
use Doctrine\Inflector\{Inflector, InflectorFactory};
|
|
use Doctrine\ORM\{EntityManagerInterface, EntityRepository};
|
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
|
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
|
|
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
|
use Symfony\Bundle\MakerBundle\Doctrine\DoctrineHelper;
|
|
use Symfony\Bundle\MakerBundle\Maker\AbstractMaker;
|
|
use Symfony\Bundle\MakerBundle\Renderer\FormTypeRenderer;
|
|
use Symfony\Bundle\MakerBundle\Util\UseStatementGenerator;
|
|
use Symfony\Bundle\MakerBundle\{ConsoleStyle, DependencyBuilder, Generator, InputConfiguration, Str, Validator};
|
|
use Symfony\Bundle\TwigBundle\TwigBundle;
|
|
use Symfony\Component\Console\Command\Command;
|
|
use Symfony\Component\Console\Input\{InputArgument, InputInterface};
|
|
use Symfony\Component\Console\Question\Question;
|
|
use Symfony\Component\Form\AbstractType;
|
|
use Symfony\Component\HttpFoundation\{Request, Response};
|
|
use Symfony\Component\Routing\Annotation\Route;
|
|
use Symfony\Component\Security\Csrf\CsrfTokenManager;
|
|
use Symfony\Component\Validator\Validation;
|
|
|
|
/**
|
|
* @author Sadicov Vladimir <sadikoff@gmail.com>
|
|
*/
|
|
final class MakeCollectionCrud extends AbstractMaker {
|
|
private Inflector $inflector;
|
|
private string $controllerClassName;
|
|
private bool $generateTests = FALSE;
|
|
|
|
public function __construct(private DoctrineHelper $doctrineHelper, private FormTypeRenderer $formTypeRenderer)
|
|
{
|
|
$this->inflector = InflectorFactory::create()->build();
|
|
|
|
define('CRUD_TEMPLATE_PREFIX', __DIR__ . '/../Resources/crud');
|
|
}
|
|
|
|
public static function getCommandName(): string
|
|
{
|
|
return 'make:collection-crud';
|
|
}
|
|
|
|
public static function getCommandDescription(): string
|
|
{
|
|
return 'Creates custom CRUD for this App';
|
|
}
|
|
|
|
public function configureCommand(Command $command, InputConfiguration $inputConfig): void
|
|
{
|
|
$command
|
|
->addArgument('entity-class', InputArgument::OPTIONAL, sprintf('The class name of the entity to create CRUD (e.g. <fg=yellow>%s</>)', Str::asClassName(Str::getRandomTerm())))
|
|
->setHelp(file_get_contents(__DIR__ . '/../Resources/help/MakeCrud.txt'));
|
|
|
|
$inputConfig->setArgumentAsNonInteractive('entity-class');
|
|
}
|
|
|
|
public function interact(InputInterface $input, ConsoleStyle $io, Command $command): void
|
|
{
|
|
if (NULL === $input->getArgument('entity-class'))
|
|
{
|
|
$argument = $command->getDefinition()->getArgument('entity-class');
|
|
|
|
$entities = $this->doctrineHelper->getEntitiesForAutocomplete();
|
|
|
|
$question = new Question($argument->getDescription());
|
|
$question->setAutocompleterValues($entities);
|
|
|
|
$value = $io->askQuestion($question);
|
|
|
|
$input->setArgument('entity-class', $value);
|
|
}
|
|
|
|
$defaultControllerClass = Str::asClassName(sprintf('%s Controller', $input->getArgument('entity-class')));
|
|
|
|
$this->controllerClassName = $io->ask(
|
|
sprintf('Choose a name for your controller class (e.g. <fg=yellow>%s</>)', $defaultControllerClass),
|
|
$defaultControllerClass
|
|
);
|
|
|
|
$this->generateTests = $io->confirm('Do you want to generate tests for the controller?. [Experimental]', FALSE);
|
|
}
|
|
|
|
public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator): void
|
|
{
|
|
$entityClassDetails = $generator->createClassNameDetails(
|
|
Validator::entityExists($input->getArgument('entity-class'), $this->doctrineHelper->getEntitiesForAutocomplete()),
|
|
'Entity\\'
|
|
);
|
|
|
|
$entityDoctrineDetails = $this->doctrineHelper->createDoctrineDetails($entityClassDetails->getFullName());
|
|
|
|
$repositoryVars = [];
|
|
$repositoryClassName = EntityManagerInterface::class;
|
|
|
|
if (NULL !== $entityDoctrineDetails->getRepositoryClass())
|
|
{
|
|
$repositoryClassDetails = $generator->createClassNameDetails(
|
|
'\\' . $entityDoctrineDetails->getRepositoryClass(),
|
|
'Repository\\',
|
|
'Repository'
|
|
);
|
|
|
|
$repositoryClassName = $repositoryClassDetails->getFullName();
|
|
|
|
$repositoryVars = [
|
|
'repository_full_class_name' => $repositoryClassName,
|
|
'repository_class_name' => $repositoryClassDetails->getShortName(),
|
|
'repository_var' => lcfirst($this->inflector->singularize($repositoryClassDetails->getShortName())),
|
|
];
|
|
}
|
|
|
|
$controllerClassDetails = $generator->createClassNameDetails(
|
|
$this->controllerClassName,
|
|
'Controller\\',
|
|
'Controller'
|
|
);
|
|
|
|
$iter = 0;
|
|
|
|
do
|
|
{
|
|
$formClassDetails = $generator->createClassNameDetails(
|
|
$entityClassDetails->getRelativeNameWithoutSuffix() . ($iter ?: '') . 'Type',
|
|
'Form\\',
|
|
'Type'
|
|
);
|
|
$iter++;
|
|
}
|
|
while (class_exists($formClassDetails->getFullName()));
|
|
|
|
$entityVarPlural = lcfirst($this->inflector->pluralize($entityClassDetails->getShortName()));
|
|
$entityVarSingular = lcfirst($this->inflector->singularize($entityClassDetails->getShortName()));
|
|
|
|
$entityTwigVarPlural = Str::asTwigVariable($entityVarPlural);
|
|
$entityTwigVarSingular = Str::asTwigVariable($entityVarSingular);
|
|
|
|
$routeName = Str::asRouteName($controllerClassDetails->getRelativeNameWithoutSuffix());
|
|
$templatesPath = Str::asFilePath($controllerClassDetails->getRelativeNameWithoutSuffix());
|
|
|
|
$useStatements = new UseStatementGenerator([
|
|
$entityClassDetails->getFullName(),
|
|
$formClassDetails->getFullName(),
|
|
$repositoryClassName,
|
|
AbstractController::class,
|
|
Request::class,
|
|
Response::class,
|
|
Route::class,
|
|
]);
|
|
|
|
$generator->generateController(
|
|
$controllerClassDetails->getFullName(),
|
|
CRUD_TEMPLATE_PREFIX . '/controller/Controller.tpl.php',
|
|
array_merge(
|
|
[
|
|
'use_statements' => $useStatements,
|
|
'entity_class_name' => $entityClassDetails->getShortName(),
|
|
'form_class_name' => $formClassDetails->getShortName(),
|
|
'route_path' => Str::asRoutePath($controllerClassDetails->getRelativeNameWithoutSuffix()),
|
|
'route_name' => $routeName,
|
|
'templates_path' => $templatesPath,
|
|
'entity_var_plural' => $entityVarPlural,
|
|
'entity_twig_var_plural' => $entityTwigVarPlural,
|
|
'entity_var_singular' => $entityVarSingular,
|
|
'entity_twig_var_singular' => $entityTwigVarSingular,
|
|
'entity_identifier' => $entityDoctrineDetails->getIdentifier(),
|
|
'use_render_form' => method_exists(AbstractController::class, 'renderForm'),
|
|
],
|
|
$repositoryVars
|
|
)
|
|
);
|
|
|
|
$this->formTypeRenderer->render(
|
|
$formClassDetails,
|
|
$entityDoctrineDetails->getFormFields(),
|
|
$entityClassDetails
|
|
);
|
|
|
|
$templates = [
|
|
'edit' => [
|
|
'entity_class_name' => $entityClassDetails->getShortName(),
|
|
'entity_twig_var_singular' => $entityTwigVarSingular,
|
|
'entity_identifier' => $entityDoctrineDetails->getIdentifier(),
|
|
'route_name' => $routeName,
|
|
'templates_path' => $templatesPath,
|
|
],
|
|
'index' => [
|
|
'entity_class_name' => $entityClassDetails->getShortName(),
|
|
'entity_twig_var_plural' => $entityTwigVarPlural,
|
|
'entity_twig_var_singular' => $entityTwigVarSingular,
|
|
'entity_identifier' => $entityDoctrineDetails->getIdentifier(),
|
|
'entity_fields' => $entityDoctrineDetails->getDisplayFields(),
|
|
'route_name' => $routeName,
|
|
],
|
|
'new' => [
|
|
'entity_class_name' => $entityClassDetails->getShortName(),
|
|
'route_name' => $routeName,
|
|
'templates_path' => $templatesPath,
|
|
],
|
|
'show' => [
|
|
'entity_class_name' => $entityClassDetails->getShortName(),
|
|
'entity_twig_var_singular' => $entityTwigVarSingular,
|
|
'entity_identifier' => $entityDoctrineDetails->getIdentifier(),
|
|
'entity_fields' => $entityDoctrineDetails->getDisplayFields(),
|
|
'route_name' => $routeName,
|
|
'templates_path' => $templatesPath,
|
|
],
|
|
];
|
|
|
|
foreach ($templates as $template => $variables)
|
|
{
|
|
$generator->generateTemplate(
|
|
$templatesPath . '/' . $template . '.html.twig',
|
|
CRUD_TEMPLATE_PREFIX . '/templates/' . $template . '.tpl.php',
|
|
$variables
|
|
);
|
|
}
|
|
|
|
if ($this->generateTests)
|
|
{
|
|
$testClassDetails = $generator->createClassNameDetails(
|
|
$entityClassDetails->getRelativeNameWithoutSuffix(),
|
|
'Test\\Controller\\',
|
|
'ControllerTest'
|
|
);
|
|
|
|
$useStatements = new UseStatementGenerator([
|
|
$entityClassDetails->getFullName(),
|
|
WebTestCase::class,
|
|
KernelBrowser::class,
|
|
$repositoryClassName,
|
|
]);
|
|
|
|
$usesEntityManager = EntityManagerInterface::class === $repositoryClassName;
|
|
|
|
if ($usesEntityManager)
|
|
{
|
|
$useStatements->addUseStatement(EntityRepository::class);
|
|
}
|
|
|
|
$generator->generateFile(
|
|
'tests/Controller/' . $testClassDetails->getShortName() . '.php',
|
|
$usesEntityManager ? 'crud/test/Test.EntityManager.tpl.php' : 'crud/test/Test.tpl.php',
|
|
[
|
|
'use_statements' => $useStatements,
|
|
'entity_full_class_name' => $entityClassDetails->getFullName(),
|
|
'entity_class_name' => $entityClassDetails->getShortName(),
|
|
'entity_var_singular' => $entityVarSingular,
|
|
'route_path' => Str::asRoutePath($controllerClassDetails->getRelativeNameWithoutSuffix()),
|
|
'route_name' => $routeName,
|
|
'class_name' => Str::getShortClassName($testClassDetails->getFullName()),
|
|
'namespace' => Str::getNamespace($testClassDetails->getFullName()),
|
|
'form_fields' => $entityDoctrineDetails->getFormFields(),
|
|
'repository_class_name' => $usesEntityManager ? EntityManagerInterface::class : $repositoryVars['repository_class_name'],
|
|
'form_field_prefix' => strtolower(Str::asSnakeCase($entityTwigVarSingular)),
|
|
]
|
|
);
|
|
|
|
if ( ! class_exists(WebTestCase::class))
|
|
{
|
|
$io->caution('You\'ll need to install the `symfony/test-pack` to execute the tests for your new controller.');
|
|
}
|
|
}
|
|
|
|
$generator->writeChanges();
|
|
|
|
$this->writeSuccessMessage($io);
|
|
|
|
$io->text(sprintf('Next: Check your new CRUD by going to <fg=yellow>%s/</>', Str::asRoutePath($controllerClassDetails->getRelativeNameWithoutSuffix())));
|
|
}
|
|
|
|
public function configureDependencies(DependencyBuilder $dependencies): void
|
|
{
|
|
$dependencies->addClassDependency(
|
|
Route::class,
|
|
'router'
|
|
);
|
|
|
|
$dependencies->addClassDependency(
|
|
AbstractType::class,
|
|
'form'
|
|
);
|
|
|
|
$dependencies->addClassDependency(
|
|
Validation::class,
|
|
'validator'
|
|
);
|
|
|
|
$dependencies->addClassDependency(
|
|
TwigBundle::class,
|
|
'twig-bundle'
|
|
);
|
|
|
|
$dependencies->addClassDependency(
|
|
DoctrineBundle::class,
|
|
'orm'
|
|
);
|
|
|
|
$dependencies->addClassDependency(
|
|
CsrfTokenManager::class,
|
|
'security-csrf'
|
|
);
|
|
|
|
$dependencies->addClassDependency(
|
|
ParamConverter::class,
|
|
'annotations'
|
|
);
|
|
}
|
|
}
|