Skip to content

Commit 2d0e7d0

Browse files
committed
support for root namespaces and suffix's
1 parent 1923589 commit 2d0e7d0

File tree

12 files changed

+127
-41
lines changed

12 files changed

+127
-41
lines changed

src/DependencyInjection/MakerExtension.php

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public function load(array $configs, ContainerBuilder $container): void
4949
$componentGeneratorDefinition
5050
->replaceArgument(0, $config['generate_final_classes'])
5151
->replaceArgument(1, $config['generate_final_entities'])
52+
->replaceArgument(2, $rootNamespace)
5253
;
5354

5455
$container->registerForAutoconfiguration(MakerInterface::class)

src/Generator.php

+5-4
Original file line numberDiff line numberDiff line change
@@ -55,16 +55,17 @@ public function __construct(
5555
*/
5656
public function generateClass(string $className, string $templateName, array $variables = []): string
5757
{
58+
if (\array_key_exists('class_data', $variables) && $variables['class_data'] instanceof ClassData) {
59+
$classData = $this->templateComponentGenerator->configureClass($variables['class_data']);
60+
$className = $classData->getFullClassName();
61+
}
62+
5863
$targetPath = $this->fileManager->getRelativePathForFutureClass($className);
5964

6065
if (null === $targetPath) {
6166
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)));
6267
}
6368

64-
if (\array_key_exists('class_data', $variables) && $variables['class_data'] instanceof ClassData) {
65-
$this->templateComponentGenerator->configureClass($variables['class_data']);
66-
}
67-
6869
$variables = array_merge($variables, [
6970
'class_name' => Str::getShortClassName($className),
7071
'namespace' => Str::getNamespace($className),

src/Maker/MakeCrud.php

+6-4
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,8 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen
148148
} while (class_exists($formClassDetails->getFullName()));
149149

150150
$controllerClassData = ClassData::create(
151-
class: sprintf('App\Controller\%sController', $this->controllerClassName),
151+
class: sprintf('Controller\%s', $this->controllerClassName),
152+
suffix: 'Controller',
152153
extendsClass: AbstractController::class,
153154
useStatements: [
154155
$entityClassDetails->getFullName(),
@@ -175,7 +176,7 @@ class: sprintf('App\Controller\%sController', $this->controllerClassName),
175176
}
176177

177178
$generator->generateController(
178-
$controllerClassDetails->getFullName(),
179+
$controllerClassData->getFullClassName(),
179180
'crud/controller/Controller.tpl.php',
180181
array_merge([
181182
'class_data' => $controllerClassData,
@@ -247,7 +248,8 @@ class: sprintf('App\Controller\%sController', $this->controllerClassName),
247248

248249
if ($this->shouldGenerateTests()) {
249250
$testClassData = ClassData::create(
250-
class: sprintf('App\Tests\Controller\%sControllerTest', $entityClassDetails->getRelativeNameWithoutSuffix()),
251+
class: sprintf('Tests\Controller\%s', $entityClassDetails->getRelativeNameWithoutSuffix()),
252+
suffix: 'ControllerTest',
251253
extendsClass: WebTestCase::class,
252254
useStatements: [
253255
$entityClassDetails->getFullName(),
@@ -263,7 +265,7 @@ class: sprintf('App\Tests\Controller\%sControllerTest', $entityClassDetails->get
263265
}
264266

265267
$generator->generateClass(
266-
$testClassData->fullClassName,
268+
$testClassData->getFullClassName(),
267269
'crud/test/Test.EntityManager.tpl.php',
268270
[
269271
'class_data' => $testClassData,

src/Maker/MakeVoter.php

+12-10
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
use Symfony\Component\Console\Command\Command;
2020
use Symfony\Component\Console\Input\InputArgument;
2121
use Symfony\Component\Console\Input\InputInterface;
22+
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
2223
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
24+
use Symfony\Component\Security\Core\User\UserInterface;
2325

2426
/**
2527
* @author Javier Eguiluz <javier.eguiluz@gmail.com>
@@ -47,21 +49,21 @@ public function configureCommand(Command $command, InputConfiguration $inputConf
4749

4850
public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator): void
4951
{
50-
$classMetaData = ClassData::create(
51-
class: sprintf('App\Security\Voter\%sVoter', $input->getArgument('name')),
52+
$voterClassData = ClassData::create(
53+
class: sprintf('Security\Voter\%s', $input->getArgument('name')),
54+
suffix: 'Voter',
5255
extendsClass: Voter::class,
53-
);
54-
55-
$voterClassNameDetails = $generator->createClassNameDetails(
56-
$input->getArgument('name'),
57-
'Security\\Voter\\',
58-
'Voter'
56+
useStatements: [
57+
TokenInterface::class,
58+
Voter::class,
59+
UserInterface::class,
60+
]
5961
);
6062

6163
$generator->generateClass(
62-
$voterClassNameDetails->getFullName(),
64+
$voterClassData->getFullClassName(),
6365
'security/Voter.tpl.php',
64-
['class_data' => $classMetaData]
66+
['class_data' => $voterClassData]
6567
);
6668

6769
$generator->writeChanges();

src/Resources/config/services.xml

+3-2
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,9 @@
8080
</service>
8181

8282
<service id="maker.template_component_generator" class="Symfony\Bundle\MakerBundle\Util\TemplateComponentGenerator">
83-
<argument /> <!-- generate_final_classes -->
84-
<argument /> <!-- generate_final_entities -->
83+
<argument /> <!-- generate_final_classes -->
84+
<argument /> <!-- generate_final_entities -->
85+
<argument /> <!-- root_namespace -->
8586
</service>
8687
</services>
8788
</container>

src/Resources/skeleton/crud/controller/Controller.tpl.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?= "<?php\n" ?>
22

3-
namespace <?= $namespace ?>;
3+
namespace <?= $class_data->getNamespace() ?>;
44

55
<?= $class_data->getUseStatements(); ?>
66

src/Resources/skeleton/security/Voter.tpl.php

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
<?= "<?php\n" ?>
22

3-
namespace <?= $namespace; ?>;
3+
namespace <?= $class_data->getNamespace(); ?>;
44

5-
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
6-
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
7-
use Symfony\Component\Security\Core\User\UserInterface;
5+
<?= $class_data->getUseStatements(); ?>
86

97
<?= $class_data->getClassDeclaration() ?>
108
{
@@ -16,7 +14,7 @@ protected function supports(string $attribute, mixed $subject): bool
1614
// replace with your own logic
1715
// https://symfony.com/doc/current/security/voters.html
1816
return in_array($attribute, [self::EDIT, self::VIEW])
19-
&& $subject instanceof \App\Entity\<?= str_replace('Voter', null, $class_name) ?>;
17+
&& $subject instanceof \App\Entity\<?= str_replace('Voter', null, $class_data->getClassName()) ?>;
2018
}
2119

2220
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool

src/Util/ClassSource/Model/ClassData.php

+37-6
Original file line numberDiff line numberDiff line change
@@ -22,34 +22,65 @@
2222
final class ClassData
2323
{
2424
private function __construct(
25-
public readonly string $className,
26-
public readonly string $namespace,
27-
public readonly string $fullClassName,
25+
private string $className,
26+
private string $namespace,
2827
public readonly ?string $extends,
2928
public readonly bool $isEntity,
3029
private UseStatementGenerator $useStatementGenerator,
3130
private bool $isFinal = true,
31+
private string $rootNamespace = 'App',
3232
) {
3333
}
3434

35-
public static function create(string $class, ?string $extendsClass = null, bool $isEntity = false, array $useStatements = []): self
35+
public static function create(string $class, ?string $suffix = null, ?string $extendsClass = null, bool $isEntity = false, array $useStatements = []): self
3636
{
37+
$className = Str::getShortClassName($class);
38+
39+
if (null !== $suffix && !str_ends_with($className, $suffix)) {
40+
$className = Str::asClassName(sprintf('%s%s', $className, $suffix));
41+
}
42+
3743
$useStatements = new UseStatementGenerator($useStatements);
3844

3945
if ($extendsClass) {
4046
$useStatements->addUseStatement($extendsClass);
4147
}
4248

4349
return new self(
44-
className: Str::getShortClassName($class),
50+
className: Str::asClassName($className),
4551
namespace: Str::getNamespace($class),
46-
fullClassName: $class,
4752
extends: null === $extendsClass ? null : Str::getShortClassName($extendsClass),
4853
isEntity: $isEntity,
4954
useStatementGenerator: $useStatements,
5055
);
5156
}
5257

58+
public function getClassName(): string
59+
{
60+
return $this->className;
61+
}
62+
63+
public function getNamespace(): string
64+
{
65+
if (empty($this->namespace)) {
66+
return $this->rootNamespace;
67+
}
68+
69+
return sprintf('%s\%s', $this->rootNamespace, $this->namespace);
70+
}
71+
72+
public function getFullClassName(): string
73+
{
74+
return sprintf('%s\%s', $this->getNamespace(), $this->className);
75+
}
76+
77+
public function setRootNamespace(string $rootNamespace): self
78+
{
79+
$this->rootNamespace = $rootNamespace;
80+
81+
return $this;
82+
}
83+
5384
public function getClassDeclaration(): string
5485
{
5586
$extendsDeclaration = '';

src/Util/TemplateComponentGenerator.php

+3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ final class TemplateComponentGenerator
2323
public function __construct(
2424
private bool $generateFinalClasses,
2525
private bool $generateFinalEntities,
26+
private string $rootNamespace,
2627
) {
2728
}
2829

@@ -54,6 +55,8 @@ public function getPropertyType(ClassNameDetails $classNameDetails): ?string
5455

5556
public function configureClass(ClassData $classMetadata): ClassData
5657
{
58+
$classMetadata->setRootNamespace($this->rootNamespace);
59+
5760
if ($classMetadata->isEntity) {
5861
return $classMetadata->setIsFinal($this->generateFinalEntities);
5962
}

tests/Doctrine/EntityRegeneratorTest.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ private function doTestRegeneration(string $sourceDir, Kernel $kernel, string $n
100100

101101
$fileManager = new FileManager($fs, $autoloaderUtil, new MakerFileLinkFormatter(null), $tmpDir);
102102
$doctrineHelper = new DoctrineHelper('App\\Entity', $container->get('doctrine'));
103-
$templateComponentGenerator = new TemplateComponentGenerator(false, false);
103+
$templateComponentGenerator = new TemplateComponentGenerator(false, false, 'App');
104104
$generator = new Generator(fileManager: $fileManager, namespacePrefix: 'App\\', templateComponentGenerator: $templateComponentGenerator);
105105
$entityClassGenerator = new EntityClassGenerator($generator, $doctrineHelper);
106106
$regenerator = new EntityRegenerator(

tests/Util/ClassSource/ClassDataTest.php

+39-3
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ public function testStaticConstructor(): void
2525
// Sanity check in case Maker's NS changes
2626
self::assertSame('Symfony\Bundle\MakerBundle\MakerBundle', MakerBundle::class);
2727

28-
self::assertSame('MakerBundle', $meta->className);
29-
self::assertSame('Symfony\Bundle\MakerBundle', $meta->namespace);
30-
self::assertSame('Symfony\Bundle\MakerBundle\MakerBundle', $meta->fullClassName);
28+
self::assertSame('MakerBundle', $meta->getClassName());
29+
self::assertSame('App\Symfony\Bundle\MakerBundle', $meta->getNamespace());
30+
self::assertSame('App\Symfony\Bundle\MakerBundle\MakerBundle', $meta->getFullClassName());
3131
}
3232

3333
public function testGetClassDeclaration(): void
@@ -55,4 +55,40 @@ public function testGetClassDeclarationWithExtends(): void
5555

5656
self::assertSame('final class MakerBundle extends MakerTestKernel', $meta->getClassDeclaration());
5757
}
58+
59+
/** @dataProvider suffixDataProvider */
60+
public function testSuffix(?string $suffix, string $expectedResult): void
61+
{
62+
$data = ClassData::create(class: MakerBundle::class, suffix: $suffix);
63+
64+
self::assertSame($expectedResult, $data->getClassName());
65+
}
66+
67+
public function suffixDataProvider(): \Generator
68+
{
69+
yield [null, 'MakerBundle'];
70+
yield ['Testing', 'MakerBundleTesting'];
71+
yield ['Bundle', 'MakerBundle'];
72+
}
73+
74+
/** @dataProvider namespaceDataProvider */
75+
public function testNamespace(string $class, ?string $rootNamespace, string $expectedNamespace, string $expectedFullClassName): void
76+
{
77+
$class = ClassData::create($class);
78+
79+
if (null !== $rootNamespace) {
80+
$class->setRootNamespace($rootNamespace);
81+
}
82+
83+
self::assertSame($expectedNamespace, $class->getNamespace());
84+
self::assertSame($expectedFullClassName, $class->getFullClassName());
85+
}
86+
87+
public function namespaceDataProvider(): \Generator
88+
{
89+
yield ['MyController', null, 'App', 'App\MyController'];
90+
yield ['Controller\MyController', null, 'App\Controller', 'App\Controller\MyController'];
91+
yield ['MyController', 'Maker', 'Maker', 'Maker\MyController'];
92+
yield ['Controller\MyController', 'Maker', 'Maker\Controller', 'Maker\Controller\MyController'];
93+
}
5894
}

tests/Util/TemplateComponentGeneratorTest.php

+16-5
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class TemplateComponentGeneratorTest extends TestCase
2323
{
2424
public function testRouteAttributes(): void
2525
{
26-
$generator = new TemplateComponentGenerator(false, false);
26+
$generator = new TemplateComponentGenerator(false, false, 'App');
2727

2828
$expected = " #[Route('/', name: 'app_home')]\n";
2929

@@ -35,7 +35,7 @@ public function testRouteAttributes(): void
3535
*/
3636
public function testRouteMethods(string $expected, array $methods): void
3737
{
38-
$generator = new TemplateComponentGenerator(false, false);
38+
$generator = new TemplateComponentGenerator(false, false, 'App');
3939

4040
self::assertSame($expected, $generator->generateRouteForControllerMethod(
4141
'/',
@@ -55,7 +55,7 @@ public function routeMethodDataProvider(): \Generator
5555
*/
5656
public function testRouteIndentation(string $expected): void
5757
{
58-
$generator = new TemplateComponentGenerator(false, false);
58+
$generator = new TemplateComponentGenerator(false, false, 'App');
5959

6060
self::assertSame($expected, $generator->generateRouteForControllerMethod(
6161
'/',
@@ -75,7 +75,7 @@ public function routeIndentationDataProvider(): \Generator
7575
*/
7676
public function testRouteTrailingNewLine(string $expected): void
7777
{
78-
$generator = new TemplateComponentGenerator(false, false);
78+
$generator = new TemplateComponentGenerator(false, false, 'App');
7979

8080
self::assertSame($expected, $generator->generateRouteForControllerMethod(
8181
'/',
@@ -96,7 +96,7 @@ public function routeTrailingNewLineDataProvider(): \Generator
9696
*/
9797
public function testGetFinalClassDeclaration(bool $finalClass, bool $finalEntity, bool $isEntity, string $expectedResult): void
9898
{
99-
$generator = new TemplateComponentGenerator($finalClass, $finalEntity);
99+
$generator = new TemplateComponentGenerator($finalClass, $finalEntity, 'App');
100100

101101
$classData = ClassData::create(MakerBundle::class, isEntity: $isEntity);
102102

@@ -116,4 +116,15 @@ public function finalClassDataProvider(): \Generator
116116
yield 'Final Entity' => [false, true, true, 'final '];
117117
yield 'Final Entity w/ Class' => [true, true, true, 'final '];
118118
}
119+
120+
public function testConfiguresClassDataWithRootNamespace(): void
121+
{
122+
$generator = new TemplateComponentGenerator(false, false, 'MakerTest');
123+
124+
$classData = ClassData::create(MakerBundle::class);
125+
126+
$generator->configureClass($classData);
127+
128+
self::assertSame('MakerTest\Symfony\Bundle\MakerBundle', $classData->getNamespace());
129+
}
119130
}

0 commit comments

Comments
 (0)