From 6ea6684a94fc641e3d634e1096a201de9a046ff3 Mon Sep 17 00:00:00 2001 From: Jesse Rushlow Date: Sun, 5 May 2024 23:50:10 -0400 Subject: [PATCH 1/4] [make:voter|crud] generate all classes with final keyword --- src/DependencyInjection/Configuration.php | 2 + src/DependencyInjection/MakerExtension.php | 6 ++ src/Generator.php | 5 ++ src/Maker/MakeCrud.php | 21 +++--- src/Maker/MakeVoter.php | 8 ++- src/Resources/config/services.xml | 2 + .../crud/controller/Controller.tpl.php | 2 +- .../crud/test/Test.EntityManager.tpl.php | 2 +- src/Resources/skeleton/security/Voter.tpl.php | 2 +- src/Util/ClassSource/Model/ClassData.php | 65 +++++++++++++++++++ src/Util/TemplateComponentGenerator.php | 17 +++++ tests/Doctrine/EntityRegeneratorTest.php | 4 +- tests/Maker/MakeVoterTest.php | 27 ++++++++ tests/Util/ClassSource/ClassDataTest.php | 58 +++++++++++++++++ tests/Util/TemplateComponentGeneratorTest.php | 32 +++++++-- .../expected/WithCustomRepository.php | 2 +- .../make-voter/expected/FooBarVoter.php | 46 +++++++++++++ .../expected/not_final_FooBarVoter.php | 46 +++++++++++++ 18 files changed, 328 insertions(+), 19 deletions(-) create mode 100644 src/Util/ClassSource/Model/ClassData.php create mode 100644 tests/Util/ClassSource/ClassDataTest.php create mode 100644 tests/fixtures/make-voter/expected/FooBarVoter.php create mode 100644 tests/fixtures/make-voter/expected/not_final_FooBarVoter.php diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index c9d94d086..15c718318 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -24,6 +24,8 @@ public function getConfigTreeBuilder(): TreeBuilder $rootNode ->children() ->scalarNode('root_namespace')->defaultValue('App')->end() + ->booleanNode('generate_final_classes')->defaultTrue()->end() + ->booleanNode('generate_final_entities')->defaultFalse()->end() ->end() ; diff --git a/src/DependencyInjection/MakerExtension.php b/src/DependencyInjection/MakerExtension.php index 51069bcf4..7eb250ee2 100644 --- a/src/DependencyInjection/MakerExtension.php +++ b/src/DependencyInjection/MakerExtension.php @@ -45,6 +45,12 @@ public function load(array $configs, ContainerBuilder $container): void $doctrineHelperDefinition = $container->getDefinition('maker.doctrine_helper'); $doctrineHelperDefinition->replaceArgument(0, $rootNamespace.'\\Entity'); + $componentGeneratorDefinition = $container->getDefinition('maker.template_component_generator'); + $componentGeneratorDefinition + ->replaceArgument(0, $config['generate_final_classes']) + ->replaceArgument(1, $config['generate_final_entities']) + ; + $container->registerForAutoconfiguration(MakerInterface::class) ->addTag(MakeCommandRegistrationPass::MAKER_TAG); } diff --git a/src/Generator.php b/src/Generator.php index 03f7984d6..59e369db8 100644 --- a/src/Generator.php +++ b/src/Generator.php @@ -14,6 +14,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\MakerBundle\Exception\RuntimeCommandException; use Symfony\Bundle\MakerBundle\Util\ClassNameDetails; +use Symfony\Bundle\MakerBundle\Util\ClassSource\Model\ClassData; use Symfony\Bundle\MakerBundle\Util\PhpCompatUtil; use Symfony\Bundle\MakerBundle\Util\TemplateComponentGenerator; @@ -60,6 +61,10 @@ public function generateClass(string $className, string $templateName, array $va throw new \LogicException(\sprintf('Could not determine where to locate the new class "%s", maybe try with a full namespace like "\\My\\Full\\Namespace\\%s"', $className, Str::getShortClassName($className))); } + if (\array_key_exists('class_data', $variables) && $variables['class_data'] instanceof ClassData) { + $this->templateComponentGenerator->configureClass($variables['class_data']); + } + $variables = array_merge($variables, [ 'class_name' => Str::getShortClassName($className), 'namespace' => Str::getNamespace($className), diff --git a/src/Maker/MakeCrud.php b/src/Maker/MakeCrud.php index 46facba78..04ade40e3 100644 --- a/src/Maker/MakeCrud.php +++ b/src/Maker/MakeCrud.php @@ -27,6 +27,7 @@ use Symfony\Bundle\MakerBundle\Maker\Common\CanGenerateTestsTrait; use Symfony\Bundle\MakerBundle\Renderer\FormTypeRenderer; use Symfony\Bundle\MakerBundle\Str; +use Symfony\Bundle\MakerBundle\Util\ClassSource\Model\ClassData; use Symfony\Bundle\MakerBundle\Util\UseStatementGenerator; use Symfony\Bundle\MakerBundle\Validator; use Symfony\Bundle\TwigBundle\TwigBundle; @@ -131,6 +132,11 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen ]; } + $controllerClassData = ClassData::create( + class: sprintf('App\Controller\%sController', $this->controllerClassName), + extendsClass: AbstractController::class, + ); + $controllerClassDetails = $generator->createClassNameDetails( $this->controllerClassName, 'Controller\\', @@ -174,6 +180,7 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen $controllerClassDetails->getFullName(), 'crud/controller/Controller.tpl.php', array_merge([ + 'class_data' => $controllerClassData, 'use_statements' => $useStatements, 'entity_class_name' => $entityClassDetails->getShortName(), 'form_class_name' => $formClassDetails->getShortName(), @@ -242,10 +249,9 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen } if ($this->shouldGenerateTests()) { - $testClassDetails = $generator->createClassNameDetails( - $entityClassDetails->getRelativeNameWithoutSuffix(), - 'Test\\Controller\\', - 'ControllerTest' + $testClassData = ClassData::create( + class: sprintf('App\Tests\Controller\%sControllerTest', $entityClassDetails->getRelativeNameWithoutSuffix()), + extendsClass: WebTestCase::class, ); $useStatements = new UseStatementGenerator([ @@ -261,18 +267,17 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen $useStatements->addUseStatement(EntityManagerInterface::class); } - $generator->generateFile( - 'tests/Controller/'.$testClassDetails->getShortName().'.php', + $generator->generateClass( + $testClassData->fullClassName, 'crud/test/Test.EntityManager.tpl.php', [ + 'class_data' => $testClassData, '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' => EntityManagerInterface::class, 'form_field_prefix' => strtolower(Str::asSnakeCase($entityTwigVarSingular)), diff --git a/src/Maker/MakeVoter.php b/src/Maker/MakeVoter.php index b807bc36e..5063b1e0b 100644 --- a/src/Maker/MakeVoter.php +++ b/src/Maker/MakeVoter.php @@ -15,6 +15,7 @@ use Symfony\Bundle\MakerBundle\DependencyBuilder; use Symfony\Bundle\MakerBundle\Generator; use Symfony\Bundle\MakerBundle\InputConfiguration; +use Symfony\Bundle\MakerBundle\Util\ClassSource\Model\ClassData; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -46,6 +47,11 @@ public function configureCommand(Command $command, InputConfiguration $inputConf public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator): void { + $classMetaData = ClassData::create( + class: sprintf('App\Security\Voter\%sVoter', $input->getArgument('name')), + extendsClass: Voter::class, + ); + $voterClassNameDetails = $generator->createClassNameDetails( $input->getArgument('name'), 'Security\\Voter\\', @@ -55,7 +61,7 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen $generator->generateClass( $voterClassNameDetails->getFullName(), 'security/Voter.tpl.php', - [] + ['class_data' => $classMetaData] ); $generator->writeChanges(); diff --git a/src/Resources/config/services.xml b/src/Resources/config/services.xml index ae08be6cb..55d26d7a4 100644 --- a/src/Resources/config/services.xml +++ b/src/Resources/config/services.xml @@ -80,6 +80,8 @@ + + diff --git a/src/Resources/skeleton/crud/controller/Controller.tpl.php b/src/Resources/skeleton/crud/controller/Controller.tpl.php index 012ce710f..268a66cac 100644 --- a/src/Resources/skeleton/crud/controller/Controller.tpl.php +++ b/src/Resources/skeleton/crud/controller/Controller.tpl.php @@ -5,7 +5,7 @@ #[Route('')] -class extends AbstractController +getClassDeclaration() ?> { generateRouteForControllerMethod('/', sprintf('%s_index', $route_name), ['GET']) ?> diff --git a/src/Resources/skeleton/crud/test/Test.EntityManager.tpl.php b/src/Resources/skeleton/crud/test/Test.EntityManager.tpl.php index d5aaf90a8..2f9cf0214 100644 --- a/src/Resources/skeleton/crud/test/Test.EntityManager.tpl.php +++ b/src/Resources/skeleton/crud/test/Test.EntityManager.tpl.php @@ -5,7 +5,7 @@ -class extends WebTestCase +getClassDeclaration() ?> { private KernelBrowser $client; private EntityManagerInterface $manager; diff --git a/src/Resources/skeleton/security/Voter.tpl.php b/src/Resources/skeleton/security/Voter.tpl.php index 17d3ae5cb..0b5ff0eb1 100644 --- a/src/Resources/skeleton/security/Voter.tpl.php +++ b/src/Resources/skeleton/security/Voter.tpl.php @@ -6,7 +6,7 @@ use Symfony\Component\Security\Core\Authorization\Voter\Voter; use Symfony\Component\Security\Core\User\UserInterface; -class extends Voter +getClassDeclaration() ?> { public const EDIT = 'POST_EDIT'; public const VIEW = 'POST_VIEW'; diff --git a/src/Util/ClassSource/Model/ClassData.php b/src/Util/ClassSource/Model/ClassData.php new file mode 100644 index 000000000..aef96ef1a --- /dev/null +++ b/src/Util/ClassSource/Model/ClassData.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\MakerBundle\Util\ClassSource\Model; + +use Symfony\Bundle\MakerBundle\Str; + +/** + * @author Jesse Rushlow + * + * @internal + */ +final class ClassData +{ + private function __construct( + public readonly string $className, + public readonly string $namespace, + public readonly string $fullClassName, + public readonly ?string $extends, + public readonly bool $isEntity, + private bool $isFinal = true, + ) { + } + + public static function create(string $class, ?string $extendsClass = null, bool $isEntity = false): self + { + return new self( + className: Str::getShortClassName($class), + namespace: Str::getNamespace($class), + fullClassName: $class, + extends: null === $extendsClass ? null : Str::getShortClassName($extendsClass), + isEntity: $isEntity, + ); + } + + public function getClassDeclaration(): string + { + $extendsDeclaration = ''; + + if (null !== $this->extends) { + $extendsDeclaration = sprintf(' extends %s', $this->extends); + } + + return sprintf('%sclass %s%s', + $this->isFinal ? 'final ' : '', + $this->className, + $extendsDeclaration, + ); + } + + public function setIsFinal(bool $isFinal): self + { + $this->isFinal = $isFinal; + + return $this; + } +} diff --git a/src/Util/TemplateComponentGenerator.php b/src/Util/TemplateComponentGenerator.php index 03af60648..7a88a030a 100644 --- a/src/Util/TemplateComponentGenerator.php +++ b/src/Util/TemplateComponentGenerator.php @@ -11,6 +11,8 @@ namespace Symfony\Bundle\MakerBundle\Util; +use Symfony\Bundle\MakerBundle\Util\ClassSource\Model\ClassData; + /** * @author Jesse Rushlow * @@ -18,6 +20,12 @@ */ final class TemplateComponentGenerator { + public function __construct( + private bool $generateFinalClasses, + private bool $generateFinalEntities, + ) { + } + public function generateRouteForControllerMethod(string $routePath, string $routeName, array $methods = [], bool $indent = true, bool $trailingNewLine = true): string { $attribute = \sprintf('%s#[Route(\'%s\', name: \'%s\'', $indent ? ' ' : null, $routePath, $routeName); @@ -43,4 +51,13 @@ public function getPropertyType(ClassNameDetails $classNameDetails): ?string { return \sprintf('%s ', $classNameDetails->getShortName()); } + + public function configureClass(ClassData $classMetadata): ClassData + { + if ($classMetadata->isEntity) { + return $classMetadata->setIsFinal($this->generateFinalEntities); + } + + return $classMetadata->setIsFinal($this->generateFinalClasses); + } } diff --git a/tests/Doctrine/EntityRegeneratorTest.php b/tests/Doctrine/EntityRegeneratorTest.php index 8a095a413..bf198c988 100644 --- a/tests/Doctrine/EntityRegeneratorTest.php +++ b/tests/Doctrine/EntityRegeneratorTest.php @@ -23,6 +23,7 @@ use Symfony\Bundle\MakerBundle\Generator; use Symfony\Bundle\MakerBundle\Util\AutoloaderUtil; use Symfony\Bundle\MakerBundle\Util\MakerFileLinkFormatter; +use Symfony\Bundle\MakerBundle\Util\TemplateComponentGenerator; use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\Filesystem\Filesystem; @@ -99,7 +100,8 @@ private function doTestRegeneration(string $sourceDir, Kernel $kernel, string $n $fileManager = new FileManager($fs, $autoloaderUtil, new MakerFileLinkFormatter(null), $tmpDir); $doctrineHelper = new DoctrineHelper('App\\Entity', $container->get('doctrine')); - $generator = new Generator($fileManager, 'App\\'); + $templateComponentGenerator = new TemplateComponentGenerator(false, false); + $generator = new Generator(fileManager: $fileManager, namespacePrefix: 'App\\', templateComponentGenerator: $templateComponentGenerator); $entityClassGenerator = new EntityClassGenerator($generator, $doctrineHelper); $regenerator = new EntityRegenerator( $doctrineHelper, diff --git a/tests/Maker/MakeVoterTest.php b/tests/Maker/MakeVoterTest.php index c10af66d7..e6494aae2 100644 --- a/tests/Maker/MakeVoterTest.php +++ b/tests/Maker/MakeVoterTest.php @@ -14,6 +14,7 @@ use Symfony\Bundle\MakerBundle\Maker\MakeVoter; use Symfony\Bundle\MakerBundle\Test\MakerTestCase; use Symfony\Bundle\MakerBundle\Test\MakerTestRunner; +use Symfony\Component\Yaml\Yaml; class MakeVoterTest extends MakerTestCase { @@ -32,6 +33,32 @@ public function getTestDetails(): \Generator 'FooBar', ] ); + + $expectedVoterPath = \dirname(__DIR__).'/fixtures/make-voter/expected/FooBarVoter.php'; + $generatedVoter = $runner->getPath('src/Security/Voter/FooBarVoter.php'); + + self::assertSame(file_get_contents($expectedVoterPath), file_get_contents($generatedVoter)); + }), + ]; + + yield 'it_makes_voter_not_final' => [$this->createMakerTest() + ->run(function (MakerTestRunner $runner) { + $runner->writeFile( + 'config/packages/dev/maker.yaml', + Yaml::dump(['when@dev' => ['maker' => ['generate_final_classes' => false]]]) + ); + + $runner->runMaker( + [ + // voter class name + 'FooBar', + ] + ); + + $expectedVoterPath = \dirname(__DIR__).'/fixtures/make-voter/expected/not_final_FooBarVoter.php'; + $generatedVoter = $runner->getPath('src/Security/Voter/FooBarVoter.php'); + + self::assertSame(file_get_contents($expectedVoterPath), file_get_contents($generatedVoter)); }), ]; } diff --git a/tests/Util/ClassSource/ClassDataTest.php b/tests/Util/ClassSource/ClassDataTest.php new file mode 100644 index 000000000..c82817e3e --- /dev/null +++ b/tests/Util/ClassSource/ClassDataTest.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\MakerBundle\Tests\Util\ClassSource; + +use PHPUnit\Framework\TestCase; +use Symfony\Bundle\MakerBundle\MakerBundle; +use Symfony\Bundle\MakerBundle\Test\MakerTestKernel; +use Symfony\Bundle\MakerBundle\Util\ClassSource\Model\ClassData; + +class ClassDataTest extends TestCase +{ + public function testStaticConstructor(): void + { + $meta = ClassData::create(MakerBundle::class); + + // Sanity check in case Maker's NS changes + self::assertSame('Symfony\Bundle\MakerBundle\MakerBundle', MakerBundle::class); + + self::assertSame('MakerBundle', $meta->className); + self::assertSame('Symfony\Bundle\MakerBundle', $meta->namespace); + self::assertSame('Symfony\Bundle\MakerBundle\MakerBundle', $meta->fullClassName); + } + + public function testGetClassDeclaration(): void + { + $meta = ClassData::create(MakerBundle::class); + + self::assertSame('final class MakerBundle', $meta->getClassDeclaration()); + } + + public function testIsFinal(): void + { + $meta = ClassData::create(MakerBundle::class); + + // Default - isFinal - true + self::assertSame('final class MakerBundle', $meta->getClassDeclaration()); + + // Not Final - isFinal - false + $meta->setIsFinal(false); + self::assertSame('class MakerBundle', $meta->getClassDeclaration()); + } + + public function testGetClassDeclarationWithExtends(): void + { + $meta = ClassData::create(class: MakerBundle::class, extendsClass: MakerTestKernel::class); + + self::assertSame('final class MakerBundle extends MakerTestKernel', $meta->getClassDeclaration()); + } +} diff --git a/tests/Util/TemplateComponentGeneratorTest.php b/tests/Util/TemplateComponentGeneratorTest.php index 4c756e104..f3e4a8f01 100644 --- a/tests/Util/TemplateComponentGeneratorTest.php +++ b/tests/Util/TemplateComponentGeneratorTest.php @@ -12,7 +12,6 @@ namespace Symfony\Bundle\MakerBundle\Tests\Util; use PHPUnit\Framework\TestCase; -use Symfony\Bundle\MakerBundle\Util\PhpCompatUtil; use Symfony\Bundle\MakerBundle\Util\TemplateComponentGenerator; /** @@ -22,7 +21,7 @@ class TemplateComponentGeneratorTest extends TestCase { public function testRouteAttributes(): void { - $generator = new TemplateComponentGenerator($this->createMock(PhpCompatUtil::class)); + $generator = new TemplateComponentGenerator(false, false); $expected = " #[Route('/', name: 'app_home')]\n"; @@ -34,7 +33,7 @@ public function testRouteAttributes(): void */ public function testRouteMethods(string $expected, array $methods): void { - $generator = new TemplateComponentGenerator($this->createMock(PhpCompatUtil::class)); + $generator = new TemplateComponentGenerator(false, false); self::assertSame($expected, $generator->generateRouteForControllerMethod( '/', @@ -54,7 +53,7 @@ public function routeMethodDataProvider(): \Generator */ public function testRouteIndentation(string $expected): void { - $generator = new TemplateComponentGenerator($this->createMock(PhpCompatUtil::class)); + $generator = new TemplateComponentGenerator(false, false); self::assertSame($expected, $generator->generateRouteForControllerMethod( '/', @@ -74,7 +73,7 @@ public function routeIndentationDataProvider(): \Generator */ public function testRouteTrailingNewLine(string $expected): void { - $generator = new TemplateComponentGenerator($this->createMock(PhpCompatUtil::class)); + $generator = new TemplateComponentGenerator(false, false); self::assertSame($expected, $generator->generateRouteForControllerMethod( '/', @@ -89,4 +88,27 @@ public function routeTrailingNewLineDataProvider(): \Generator { yield ["#[Route('/', name: 'app_home')]", true]; } + + /** + * @dataProvider finalClassDataProvider + */ + public function testGetFinalClassDeclaration(bool $finalClass, bool $finalEntity, bool $isEntity, string $expectedResult): void + { + $this->markTestIncomplete('We wont need this...'); + $generator = new TemplateComponentGenerator($finalClass, $finalEntity); + + self::assertSame($expectedResult, $generator->getFinalDeclaration($isEntity)); + } + + public function finalClassDataProvider(): \Generator + { + yield 'Not Final Class' => [false, false, false, '']; + yield 'Not Final Class w/ Entity' => [false, true, false, '']; + yield 'Final Class' => [true, false, false, 'final ']; + yield 'Final Class w/ Entity' => [true, true, false, 'final ']; + yield 'Not Final Entity' => [false, false, true, '']; + yield 'Not Final Entity w/ Class' => [true, false, true, '']; + yield 'Final Entity' => [false, true, true, 'final ']; + yield 'Final Entity w/ Class' => [true, true, true, 'final ']; + } } diff --git a/tests/fixtures/make-crud/expected/WithCustomRepository.php b/tests/fixtures/make-crud/expected/WithCustomRepository.php index 390c94bf8..b1c77ffd5 100644 --- a/tests/fixtures/make-crud/expected/WithCustomRepository.php +++ b/tests/fixtures/make-crud/expected/WithCustomRepository.php @@ -12,7 +12,7 @@ use Symfony\Component\Routing\Attribute\Route; #[Route('/sweet/food')] -class SweetFoodController extends AbstractController +final class SweetFoodController extends AbstractController { #[Route('/', name: 'app_sweet_food_index', methods: ['GET'])] public function index(SweetFoodRepository $sweetFoodRepository): Response diff --git a/tests/fixtures/make-voter/expected/FooBarVoter.php b/tests/fixtures/make-voter/expected/FooBarVoter.php new file mode 100644 index 000000000..2cfc1ee22 --- /dev/null +++ b/tests/fixtures/make-voter/expected/FooBarVoter.php @@ -0,0 +1,46 @@ +getUser(); + + // if the user is anonymous, do not grant access + if (!$user instanceof UserInterface) { + return false; + } + + // ... (check conditions and return true to grant permission) ... + switch ($attribute) { + case self::EDIT: + // logic to determine if the user can EDIT + // return true or false + break; + + case self::VIEW: + // logic to determine if the user can VIEW + // return true or false + break; + } + + return false; + } +} diff --git a/tests/fixtures/make-voter/expected/not_final_FooBarVoter.php b/tests/fixtures/make-voter/expected/not_final_FooBarVoter.php new file mode 100644 index 000000000..e38fb4ad2 --- /dev/null +++ b/tests/fixtures/make-voter/expected/not_final_FooBarVoter.php @@ -0,0 +1,46 @@ +getUser(); + + // if the user is anonymous, do not grant access + if (!$user instanceof UserInterface) { + return false; + } + + // ... (check conditions and return true to grant permission) ... + switch ($attribute) { + case self::EDIT: + // logic to determine if the user can EDIT + // return true or false + break; + + case self::VIEW: + // logic to determine if the user can VIEW + // return true or false + break; + } + + return false; + } +} From 66d209851000b5d2d06dd5110d28293da3ebfcc6 Mon Sep 17 00:00:00 2001 From: Jesse Rushlow Date: Thu, 16 May 2024 07:04:03 -0400 Subject: [PATCH 2/4] use statements from data object --- src/Maker/MakeCrud.php | 52 ++++++++----------- .../crud/controller/Controller.tpl.php | 2 +- .../crud/test/Test.EntityManager.tpl.php | 2 +- src/Util/ClassSource/Model/ClassData.php | 23 +++++++- tests/Util/TemplateComponentGeneratorTest.php | 9 +++- 5 files changed, 54 insertions(+), 34 deletions(-) diff --git a/src/Maker/MakeCrud.php b/src/Maker/MakeCrud.php index 04ade40e3..7a906ff2d 100644 --- a/src/Maker/MakeCrud.php +++ b/src/Maker/MakeCrud.php @@ -28,7 +28,6 @@ use Symfony\Bundle\MakerBundle\Renderer\FormTypeRenderer; use Symfony\Bundle\MakerBundle\Str; use Symfony\Bundle\MakerBundle\Util\ClassSource\Model\ClassData; -use Symfony\Bundle\MakerBundle\Util\UseStatementGenerator; use Symfony\Bundle\MakerBundle\Validator; use Symfony\Bundle\TwigBundle\TwigBundle; use Symfony\Component\Console\Command\Command; @@ -132,11 +131,6 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen ]; } - $controllerClassData = ClassData::create( - class: sprintf('App\Controller\%sController', $this->controllerClassName), - extendsClass: AbstractController::class, - ); - $controllerClassDetails = $generator->createClassNameDetails( $this->controllerClassName, 'Controller\\', @@ -153,6 +147,20 @@ class: sprintf('App\Controller\%sController', $this->controllerClassName), ++$iter; } while (class_exists($formClassDetails->getFullName())); + $controllerClassData = ClassData::create( + class: sprintf('App\Controller\%sController', $this->controllerClassName), + extendsClass: AbstractController::class, + useStatements: [ + $entityClassDetails->getFullName(), + $formClassDetails->getFullName(), + $repositoryClassName, + AbstractController::class, + Request::class, + Response::class, + Route::class, + ], + ); + $entityVarPlural = lcfirst($this->inflector->pluralize($entityClassDetails->getShortName())); $entityVarSingular = lcfirst($this->inflector->singularize($entityClassDetails->getShortName())); @@ -162,18 +170,8 @@ class: sprintf('App\Controller\%sController', $this->controllerClassName), $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, - ]); - if (EntityManagerInterface::class !== $repositoryClassName) { - $useStatements->addUseStatement(EntityManagerInterface::class); + $controllerClassData->addUseStatement(EntityManagerInterface::class); } $generator->generateController( @@ -181,7 +179,6 @@ class: sprintf('App\Controller\%sController', $this->controllerClassName), 'crud/controller/Controller.tpl.php', array_merge([ 'class_data' => $controllerClassData, - 'use_statements' => $useStatements, 'entity_class_name' => $entityClassDetails->getShortName(), 'form_class_name' => $formClassDetails->getShortName(), 'route_path' => Str::asRoutePath($controllerClassDetails->getRelativeNameWithoutSuffix()), @@ -252,19 +249,17 @@ class: sprintf('App\Controller\%sController', $this->controllerClassName), $testClassData = ClassData::create( class: sprintf('App\Tests\Controller\%sControllerTest', $entityClassDetails->getRelativeNameWithoutSuffix()), extendsClass: WebTestCase::class, + useStatements: [ + $entityClassDetails->getFullName(), + WebTestCase::class, + KernelBrowser::class, + $repositoryClassName, + EntityRepository::class, + ], ); - $useStatements = new UseStatementGenerator([ - $entityClassDetails->getFullName(), - WebTestCase::class, - KernelBrowser::class, - $repositoryClassName, - ]); - - $useStatements->addUseStatement(EntityRepository::class); - if (EntityManagerInterface::class !== $repositoryClassName) { - $useStatements->addUseStatement(EntityManagerInterface::class); + $testClassData->addUseStatement(EntityManagerInterface::class); } $generator->generateClass( @@ -272,7 +267,6 @@ class: sprintf('App\Tests\Controller\%sControllerTest', $entityClassDetails->get 'crud/test/Test.EntityManager.tpl.php', [ 'class_data' => $testClassData, - 'use_statements' => $useStatements, 'entity_full_class_name' => $entityClassDetails->getFullName(), 'entity_class_name' => $entityClassDetails->getShortName(), 'entity_var_singular' => $entityVarSingular, diff --git a/src/Resources/skeleton/crud/controller/Controller.tpl.php b/src/Resources/skeleton/crud/controller/Controller.tpl.php index 268a66cac..e50c62e0d 100644 --- a/src/Resources/skeleton/crud/controller/Controller.tpl.php +++ b/src/Resources/skeleton/crud/controller/Controller.tpl.php @@ -2,7 +2,7 @@ namespace ; - +getUseStatements(); ?> #[Route('')] getClassDeclaration() ?> diff --git a/src/Resources/skeleton/crud/test/Test.EntityManager.tpl.php b/src/Resources/skeleton/crud/test/Test.EntityManager.tpl.php index 2f9cf0214..825737383 100644 --- a/src/Resources/skeleton/crud/test/Test.EntityManager.tpl.php +++ b/src/Resources/skeleton/crud/test/Test.EntityManager.tpl.php @@ -3,7 +3,7 @@ namespace ; - +getUseStatements(); ?> getClassDeclaration() ?> { diff --git a/src/Util/ClassSource/Model/ClassData.php b/src/Util/ClassSource/Model/ClassData.php index aef96ef1a..f967a69af 100644 --- a/src/Util/ClassSource/Model/ClassData.php +++ b/src/Util/ClassSource/Model/ClassData.php @@ -12,6 +12,7 @@ namespace Symfony\Bundle\MakerBundle\Util\ClassSource\Model; use Symfony\Bundle\MakerBundle\Str; +use Symfony\Bundle\MakerBundle\Util\UseStatementGenerator; /** * @author Jesse Rushlow @@ -26,18 +27,26 @@ private function __construct( public readonly string $fullClassName, public readonly ?string $extends, public readonly bool $isEntity, + private UseStatementGenerator $useStatementGenerator, private bool $isFinal = true, ) { } - public static function create(string $class, ?string $extendsClass = null, bool $isEntity = false): self + public static function create(string $class, ?string $extendsClass = null, bool $isEntity = false, array $useStatements = []): self { + $useStatements = new UseStatementGenerator($useStatements); + + if ($extendsClass) { + $useStatements->addUseStatement($extendsClass); + } + return new self( className: Str::getShortClassName($class), namespace: Str::getNamespace($class), fullClassName: $class, extends: null === $extendsClass ? null : Str::getShortClassName($extendsClass), isEntity: $isEntity, + useStatementGenerator: $useStatements, ); } @@ -62,4 +71,16 @@ public function setIsFinal(bool $isFinal): self return $this; } + + public function addUseStatement(array|string $useStatement): self + { + $this->useStatementGenerator->addUseStatement($useStatement); + + return $this; + } + + public function getUseStatements(): string + { + return (string) $this->useStatementGenerator; + } } diff --git a/tests/Util/TemplateComponentGeneratorTest.php b/tests/Util/TemplateComponentGeneratorTest.php index f3e4a8f01..ac7931b24 100644 --- a/tests/Util/TemplateComponentGeneratorTest.php +++ b/tests/Util/TemplateComponentGeneratorTest.php @@ -12,6 +12,8 @@ namespace Symfony\Bundle\MakerBundle\Tests\Util; use PHPUnit\Framework\TestCase; +use Symfony\Bundle\MakerBundle\MakerBundle; +use Symfony\Bundle\MakerBundle\Util\ClassSource\Model\ClassData; use Symfony\Bundle\MakerBundle\Util\TemplateComponentGenerator; /** @@ -94,10 +96,13 @@ public function routeTrailingNewLineDataProvider(): \Generator */ public function testGetFinalClassDeclaration(bool $finalClass, bool $finalEntity, bool $isEntity, string $expectedResult): void { - $this->markTestIncomplete('We wont need this...'); $generator = new TemplateComponentGenerator($finalClass, $finalEntity); - self::assertSame($expectedResult, $generator->getFinalDeclaration($isEntity)); + $classData = ClassData::create(MakerBundle::class, isEntity: $isEntity); + + $generator->configureClass($classData); + + self::assertSame(sprintf('%sclass MakerBundle', $expectedResult), $classData->getClassDeclaration()); } public function finalClassDataProvider(): \Generator From b7fd3e3060ec1bafad85695bea1acdc3c2f9b277 Mon Sep 17 00:00:00 2001 From: Jesse Rushlow Date: Sun, 19 May 2024 00:11:01 -0400 Subject: [PATCH 3/4] support for root namespaces and suffix's --- src/DependencyInjection/MakerExtension.php | 1 + src/Generator.php | 9 ++-- src/Maker/MakeCrud.php | 10 +++-- src/Maker/MakeVoter.php | 22 +++++----- src/Resources/config/services.xml | 5 ++- .../crud/controller/Controller.tpl.php | 2 +- src/Resources/skeleton/security/Voter.tpl.php | 8 ++-- src/Util/ClassSource/Model/ClassData.php | 43 ++++++++++++++++--- src/Util/TemplateComponentGenerator.php | 3 ++ tests/Doctrine/EntityRegeneratorTest.php | 2 +- tests/Util/ClassSource/ClassDataTest.php | 42 ++++++++++++++++-- tests/Util/TemplateComponentGeneratorTest.php | 21 ++++++--- 12 files changed, 127 insertions(+), 41 deletions(-) diff --git a/src/DependencyInjection/MakerExtension.php b/src/DependencyInjection/MakerExtension.php index 7eb250ee2..1de775bff 100644 --- a/src/DependencyInjection/MakerExtension.php +++ b/src/DependencyInjection/MakerExtension.php @@ -49,6 +49,7 @@ public function load(array $configs, ContainerBuilder $container): void $componentGeneratorDefinition ->replaceArgument(0, $config['generate_final_classes']) ->replaceArgument(1, $config['generate_final_entities']) + ->replaceArgument(2, $rootNamespace) ; $container->registerForAutoconfiguration(MakerInterface::class) diff --git a/src/Generator.php b/src/Generator.php index 59e369db8..315b33427 100644 --- a/src/Generator.php +++ b/src/Generator.php @@ -55,16 +55,17 @@ public function __construct( */ public function generateClass(string $className, string $templateName, array $variables = []): string { + if (\array_key_exists('class_data', $variables) && $variables['class_data'] instanceof ClassData) { + $classData = $this->templateComponentGenerator->configureClass($variables['class_data']); + $className = $classData->getFullClassName(); + } + $targetPath = $this->fileManager->getRelativePathForFutureClass($className); if (null === $targetPath) { throw new \LogicException(\sprintf('Could not determine where to locate the new class "%s", maybe try with a full namespace like "\\My\\Full\\Namespace\\%s"', $className, Str::getShortClassName($className))); } - if (\array_key_exists('class_data', $variables) && $variables['class_data'] instanceof ClassData) { - $this->templateComponentGenerator->configureClass($variables['class_data']); - } - $variables = array_merge($variables, [ 'class_name' => Str::getShortClassName($className), 'namespace' => Str::getNamespace($className), diff --git a/src/Maker/MakeCrud.php b/src/Maker/MakeCrud.php index 7a906ff2d..3ec476f46 100644 --- a/src/Maker/MakeCrud.php +++ b/src/Maker/MakeCrud.php @@ -148,7 +148,8 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen } while (class_exists($formClassDetails->getFullName())); $controllerClassData = ClassData::create( - class: sprintf('App\Controller\%sController', $this->controllerClassName), + class: sprintf('Controller\%s', $this->controllerClassName), + suffix: 'Controller', extendsClass: AbstractController::class, useStatements: [ $entityClassDetails->getFullName(), @@ -175,7 +176,7 @@ class: sprintf('App\Controller\%sController', $this->controllerClassName), } $generator->generateController( - $controllerClassDetails->getFullName(), + $controllerClassData->getFullClassName(), 'crud/controller/Controller.tpl.php', array_merge([ 'class_data' => $controllerClassData, @@ -247,7 +248,8 @@ class: sprintf('App\Controller\%sController', $this->controllerClassName), if ($this->shouldGenerateTests()) { $testClassData = ClassData::create( - class: sprintf('App\Tests\Controller\%sControllerTest', $entityClassDetails->getRelativeNameWithoutSuffix()), + class: sprintf('Tests\Controller\%s', $entityClassDetails->getRelativeNameWithoutSuffix()), + suffix: 'ControllerTest', extendsClass: WebTestCase::class, useStatements: [ $entityClassDetails->getFullName(), @@ -263,7 +265,7 @@ class: sprintf('App\Tests\Controller\%sControllerTest', $entityClassDetails->get } $generator->generateClass( - $testClassData->fullClassName, + $testClassData->getFullClassName(), 'crud/test/Test.EntityManager.tpl.php', [ 'class_data' => $testClassData, diff --git a/src/Maker/MakeVoter.php b/src/Maker/MakeVoter.php index 5063b1e0b..c489ca2ed 100644 --- a/src/Maker/MakeVoter.php +++ b/src/Maker/MakeVoter.php @@ -19,7 +19,9 @@ use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authorization\Voter\Voter; +use Symfony\Component\Security\Core\User\UserInterface; /** * @author Javier Eguiluz @@ -47,21 +49,21 @@ public function configureCommand(Command $command, InputConfiguration $inputConf public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator): void { - $classMetaData = ClassData::create( - class: sprintf('App\Security\Voter\%sVoter', $input->getArgument('name')), + $voterClassData = ClassData::create( + class: sprintf('Security\Voter\%s', $input->getArgument('name')), + suffix: 'Voter', extendsClass: Voter::class, - ); - - $voterClassNameDetails = $generator->createClassNameDetails( - $input->getArgument('name'), - 'Security\\Voter\\', - 'Voter' + useStatements: [ + TokenInterface::class, + Voter::class, + UserInterface::class, + ] ); $generator->generateClass( - $voterClassNameDetails->getFullName(), + $voterClassData->getFullClassName(), 'security/Voter.tpl.php', - ['class_data' => $classMetaData] + ['class_data' => $voterClassData] ); $generator->writeChanges(); diff --git a/src/Resources/config/services.xml b/src/Resources/config/services.xml index 55d26d7a4..5fbc0439b 100644 --- a/src/Resources/config/services.xml +++ b/src/Resources/config/services.xml @@ -80,8 +80,9 @@ - - + + + diff --git a/src/Resources/skeleton/crud/controller/Controller.tpl.php b/src/Resources/skeleton/crud/controller/Controller.tpl.php index e50c62e0d..135d0c10a 100644 --- a/src/Resources/skeleton/crud/controller/Controller.tpl.php +++ b/src/Resources/skeleton/crud/controller/Controller.tpl.php @@ -1,6 +1,6 @@ -namespace ; +namespace getNamespace() ?>; getUseStatements(); ?> diff --git a/src/Resources/skeleton/security/Voter.tpl.php b/src/Resources/skeleton/security/Voter.tpl.php index 0b5ff0eb1..431b3c585 100644 --- a/src/Resources/skeleton/security/Voter.tpl.php +++ b/src/Resources/skeleton/security/Voter.tpl.php @@ -1,10 +1,8 @@ -namespace ; +namespace getNamespace(); ?>; -use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -use Symfony\Component\Security\Core\Authorization\Voter\Voter; -use Symfony\Component\Security\Core\User\UserInterface; +getUseStatements(); ?> getClassDeclaration() ?> { @@ -16,7 +14,7 @@ protected function supports(string $attribute, mixed $subject): bool // replace with your own logic // https://symfony.com/doc/current/security/voters.html return in_array($attribute, [self::EDIT, self::VIEW]) - && $subject instanceof \App\Entity\; + && $subject instanceof \App\Entity\getClassName()) ?>; } protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool diff --git a/src/Util/ClassSource/Model/ClassData.php b/src/Util/ClassSource/Model/ClassData.php index f967a69af..9ef9faaba 100644 --- a/src/Util/ClassSource/Model/ClassData.php +++ b/src/Util/ClassSource/Model/ClassData.php @@ -22,18 +22,24 @@ final class ClassData { private function __construct( - public readonly string $className, - public readonly string $namespace, - public readonly string $fullClassName, + private string $className, + private string $namespace, public readonly ?string $extends, public readonly bool $isEntity, private UseStatementGenerator $useStatementGenerator, private bool $isFinal = true, + private string $rootNamespace = 'App', ) { } - public static function create(string $class, ?string $extendsClass = null, bool $isEntity = false, array $useStatements = []): self + public static function create(string $class, ?string $suffix = null, ?string $extendsClass = null, bool $isEntity = false, array $useStatements = []): self { + $className = Str::getShortClassName($class); + + if (null !== $suffix && !str_ends_with($className, $suffix)) { + $className = Str::asClassName(sprintf('%s%s', $className, $suffix)); + } + $useStatements = new UseStatementGenerator($useStatements); if ($extendsClass) { @@ -41,15 +47,40 @@ public static function create(string $class, ?string $extendsClass = null, bool } return new self( - className: Str::getShortClassName($class), + className: Str::asClassName($className), namespace: Str::getNamespace($class), - fullClassName: $class, extends: null === $extendsClass ? null : Str::getShortClassName($extendsClass), isEntity: $isEntity, useStatementGenerator: $useStatements, ); } + public function getClassName(): string + { + return $this->className; + } + + public function getNamespace(): string + { + if (empty($this->namespace)) { + return $this->rootNamespace; + } + + return sprintf('%s\%s', $this->rootNamespace, $this->namespace); + } + + public function getFullClassName(): string + { + return sprintf('%s\%s', $this->getNamespace(), $this->className); + } + + public function setRootNamespace(string $rootNamespace): self + { + $this->rootNamespace = $rootNamespace; + + return $this; + } + public function getClassDeclaration(): string { $extendsDeclaration = ''; diff --git a/src/Util/TemplateComponentGenerator.php b/src/Util/TemplateComponentGenerator.php index 7a88a030a..24271fc35 100644 --- a/src/Util/TemplateComponentGenerator.php +++ b/src/Util/TemplateComponentGenerator.php @@ -23,6 +23,7 @@ final class TemplateComponentGenerator public function __construct( private bool $generateFinalClasses, private bool $generateFinalEntities, + private string $rootNamespace, ) { } @@ -54,6 +55,8 @@ public function getPropertyType(ClassNameDetails $classNameDetails): ?string public function configureClass(ClassData $classMetadata): ClassData { + $classMetadata->setRootNamespace($this->rootNamespace); + if ($classMetadata->isEntity) { return $classMetadata->setIsFinal($this->generateFinalEntities); } diff --git a/tests/Doctrine/EntityRegeneratorTest.php b/tests/Doctrine/EntityRegeneratorTest.php index bf198c988..4d2b251cb 100644 --- a/tests/Doctrine/EntityRegeneratorTest.php +++ b/tests/Doctrine/EntityRegeneratorTest.php @@ -100,7 +100,7 @@ private function doTestRegeneration(string $sourceDir, Kernel $kernel, string $n $fileManager = new FileManager($fs, $autoloaderUtil, new MakerFileLinkFormatter(null), $tmpDir); $doctrineHelper = new DoctrineHelper('App\\Entity', $container->get('doctrine')); - $templateComponentGenerator = new TemplateComponentGenerator(false, false); + $templateComponentGenerator = new TemplateComponentGenerator(false, false, 'App'); $generator = new Generator(fileManager: $fileManager, namespacePrefix: 'App\\', templateComponentGenerator: $templateComponentGenerator); $entityClassGenerator = new EntityClassGenerator($generator, $doctrineHelper); $regenerator = new EntityRegenerator( diff --git a/tests/Util/ClassSource/ClassDataTest.php b/tests/Util/ClassSource/ClassDataTest.php index c82817e3e..cbad75dec 100644 --- a/tests/Util/ClassSource/ClassDataTest.php +++ b/tests/Util/ClassSource/ClassDataTest.php @@ -25,9 +25,9 @@ public function testStaticConstructor(): void // Sanity check in case Maker's NS changes self::assertSame('Symfony\Bundle\MakerBundle\MakerBundle', MakerBundle::class); - self::assertSame('MakerBundle', $meta->className); - self::assertSame('Symfony\Bundle\MakerBundle', $meta->namespace); - self::assertSame('Symfony\Bundle\MakerBundle\MakerBundle', $meta->fullClassName); + self::assertSame('MakerBundle', $meta->getClassName()); + self::assertSame('App\Symfony\Bundle\MakerBundle', $meta->getNamespace()); + self::assertSame('App\Symfony\Bundle\MakerBundle\MakerBundle', $meta->getFullClassName()); } public function testGetClassDeclaration(): void @@ -55,4 +55,40 @@ public function testGetClassDeclarationWithExtends(): void self::assertSame('final class MakerBundle extends MakerTestKernel', $meta->getClassDeclaration()); } + + /** @dataProvider suffixDataProvider */ + public function testSuffix(?string $suffix, string $expectedResult): void + { + $data = ClassData::create(class: MakerBundle::class, suffix: $suffix); + + self::assertSame($expectedResult, $data->getClassName()); + } + + public function suffixDataProvider(): \Generator + { + yield [null, 'MakerBundle']; + yield ['Testing', 'MakerBundleTesting']; + yield ['Bundle', 'MakerBundle']; + } + + /** @dataProvider namespaceDataProvider */ + public function testNamespace(string $class, ?string $rootNamespace, string $expectedNamespace, string $expectedFullClassName): void + { + $class = ClassData::create($class); + + if (null !== $rootNamespace) { + $class->setRootNamespace($rootNamespace); + } + + self::assertSame($expectedNamespace, $class->getNamespace()); + self::assertSame($expectedFullClassName, $class->getFullClassName()); + } + + public function namespaceDataProvider(): \Generator + { + yield ['MyController', null, 'App', 'App\MyController']; + yield ['Controller\MyController', null, 'App\Controller', 'App\Controller\MyController']; + yield ['MyController', 'Maker', 'Maker', 'Maker\MyController']; + yield ['Controller\MyController', 'Maker', 'Maker\Controller', 'Maker\Controller\MyController']; + } } diff --git a/tests/Util/TemplateComponentGeneratorTest.php b/tests/Util/TemplateComponentGeneratorTest.php index ac7931b24..06d69ed31 100644 --- a/tests/Util/TemplateComponentGeneratorTest.php +++ b/tests/Util/TemplateComponentGeneratorTest.php @@ -23,7 +23,7 @@ class TemplateComponentGeneratorTest extends TestCase { public function testRouteAttributes(): void { - $generator = new TemplateComponentGenerator(false, false); + $generator = new TemplateComponentGenerator(false, false, 'App'); $expected = " #[Route('/', name: 'app_home')]\n"; @@ -35,7 +35,7 @@ public function testRouteAttributes(): void */ public function testRouteMethods(string $expected, array $methods): void { - $generator = new TemplateComponentGenerator(false, false); + $generator = new TemplateComponentGenerator(false, false, 'App'); self::assertSame($expected, $generator->generateRouteForControllerMethod( '/', @@ -55,7 +55,7 @@ public function routeMethodDataProvider(): \Generator */ public function testRouteIndentation(string $expected): void { - $generator = new TemplateComponentGenerator(false, false); + $generator = new TemplateComponentGenerator(false, false, 'App'); self::assertSame($expected, $generator->generateRouteForControllerMethod( '/', @@ -75,7 +75,7 @@ public function routeIndentationDataProvider(): \Generator */ public function testRouteTrailingNewLine(string $expected): void { - $generator = new TemplateComponentGenerator(false, false); + $generator = new TemplateComponentGenerator(false, false, 'App'); self::assertSame($expected, $generator->generateRouteForControllerMethod( '/', @@ -96,7 +96,7 @@ public function routeTrailingNewLineDataProvider(): \Generator */ public function testGetFinalClassDeclaration(bool $finalClass, bool $finalEntity, bool $isEntity, string $expectedResult): void { - $generator = new TemplateComponentGenerator($finalClass, $finalEntity); + $generator = new TemplateComponentGenerator($finalClass, $finalEntity, 'App'); $classData = ClassData::create(MakerBundle::class, isEntity: $isEntity); @@ -116,4 +116,15 @@ public function finalClassDataProvider(): \Generator yield 'Final Entity' => [false, true, true, 'final ']; yield 'Final Entity w/ Class' => [true, true, true, 'final ']; } + + public function testConfiguresClassDataWithRootNamespace(): void + { + $generator = new TemplateComponentGenerator(false, false, 'MakerTest'); + + $classData = ClassData::create(MakerBundle::class); + + $generator->configureClass($classData); + + self::assertSame('MakerTest\Symfony\Bundle\MakerBundle', $classData->getNamespace()); + } } From 988f765cc4e9bae75ed823f7331811ee6c48bbff Mon Sep 17 00:00:00 2001 From: Jesse Rushlow Date: Thu, 29 Aug 2024 11:54:00 -0400 Subject: [PATCH 4/4] php-cs-fixer it up --- src/Maker/MakeCrud.php | 4 ++-- src/Maker/MakeVoter.php | 2 +- src/Util/ClassSource/Model/ClassData.php | 10 +++++----- tests/Util/TemplateComponentGeneratorTest.php | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Maker/MakeCrud.php b/src/Maker/MakeCrud.php index 3ec476f46..0a37b2ba4 100644 --- a/src/Maker/MakeCrud.php +++ b/src/Maker/MakeCrud.php @@ -148,7 +148,7 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen } while (class_exists($formClassDetails->getFullName())); $controllerClassData = ClassData::create( - class: sprintf('Controller\%s', $this->controllerClassName), + class: \sprintf('Controller\%s', $this->controllerClassName), suffix: 'Controller', extendsClass: AbstractController::class, useStatements: [ @@ -248,7 +248,7 @@ class: sprintf('Controller\%s', $this->controllerClassName), if ($this->shouldGenerateTests()) { $testClassData = ClassData::create( - class: sprintf('Tests\Controller\%s', $entityClassDetails->getRelativeNameWithoutSuffix()), + class: \sprintf('Tests\Controller\%s', $entityClassDetails->getRelativeNameWithoutSuffix()), suffix: 'ControllerTest', extendsClass: WebTestCase::class, useStatements: [ diff --git a/src/Maker/MakeVoter.php b/src/Maker/MakeVoter.php index c489ca2ed..faabc993e 100644 --- a/src/Maker/MakeVoter.php +++ b/src/Maker/MakeVoter.php @@ -50,7 +50,7 @@ public function configureCommand(Command $command, InputConfiguration $inputConf public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator): void { $voterClassData = ClassData::create( - class: sprintf('Security\Voter\%s', $input->getArgument('name')), + class: \sprintf('Security\Voter\%s', $input->getArgument('name')), suffix: 'Voter', extendsClass: Voter::class, useStatements: [ diff --git a/src/Util/ClassSource/Model/ClassData.php b/src/Util/ClassSource/Model/ClassData.php index 9ef9faaba..988404f2a 100644 --- a/src/Util/ClassSource/Model/ClassData.php +++ b/src/Util/ClassSource/Model/ClassData.php @@ -37,7 +37,7 @@ public static function create(string $class, ?string $suffix = null, ?string $ex $className = Str::getShortClassName($class); if (null !== $suffix && !str_ends_with($className, $suffix)) { - $className = Str::asClassName(sprintf('%s%s', $className, $suffix)); + $className = Str::asClassName(\sprintf('%s%s', $className, $suffix)); } $useStatements = new UseStatementGenerator($useStatements); @@ -66,12 +66,12 @@ public function getNamespace(): string return $this->rootNamespace; } - return sprintf('%s\%s', $this->rootNamespace, $this->namespace); + return \sprintf('%s\%s', $this->rootNamespace, $this->namespace); } public function getFullClassName(): string { - return sprintf('%s\%s', $this->getNamespace(), $this->className); + return \sprintf('%s\%s', $this->getNamespace(), $this->className); } public function setRootNamespace(string $rootNamespace): self @@ -86,10 +86,10 @@ public function getClassDeclaration(): string $extendsDeclaration = ''; if (null !== $this->extends) { - $extendsDeclaration = sprintf(' extends %s', $this->extends); + $extendsDeclaration = \sprintf(' extends %s', $this->extends); } - return sprintf('%sclass %s%s', + return \sprintf('%sclass %s%s', $this->isFinal ? 'final ' : '', $this->className, $extendsDeclaration, diff --git a/tests/Util/TemplateComponentGeneratorTest.php b/tests/Util/TemplateComponentGeneratorTest.php index 06d69ed31..a61bb6bd2 100644 --- a/tests/Util/TemplateComponentGeneratorTest.php +++ b/tests/Util/TemplateComponentGeneratorTest.php @@ -102,7 +102,7 @@ public function testGetFinalClassDeclaration(bool $finalClass, bool $finalEntity $generator->configureClass($classData); - self::assertSame(sprintf('%sclass MakerBundle', $expectedResult), $classData->getClassDeclaration()); + self::assertSame(\sprintf('%sclass MakerBundle', $expectedResult), $classData->getClassDeclaration()); } public function finalClassDataProvider(): \Generator