|
13 | 13 |
|
14 | 14 | use Doctrine\Common\Annotations\Annotation;
|
15 | 15 | use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
| 16 | +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; |
16 | 17 | use Symfony\Bundle\MakerBundle\ConsoleStyle;
|
17 | 18 | use Symfony\Bundle\MakerBundle\DependencyBuilder;
|
18 | 19 | use Symfony\Bundle\MakerBundle\FileManager;
|
19 | 20 | use Symfony\Bundle\MakerBundle\Generator;
|
20 | 21 | use Symfony\Bundle\MakerBundle\InputConfiguration;
|
21 | 22 | use Symfony\Bundle\MakerBundle\Maker\AbstractMaker;
|
| 23 | +use Symfony\Bundle\MakerBundle\Maker\Common\CanGenerateTestsTrait; |
22 | 24 | use Symfony\Bundle\MakerBundle\Str;
|
| 25 | +use Symfony\Bundle\MakerBundle\Util\ClassSource\Model\ClassData; |
23 | 26 | use Symfony\Bundle\MakerBundle\Util\PhpCompatUtil;
|
24 | 27 | use Symfony\Bundle\MakerBundle\Util\UseStatementGenerator;
|
25 | 28 | use Symfony\Bundle\TwigBundle\TwigBundle;
|
|
36 | 39 | final class MakeTwcController extends AbstractMaker
|
37 | 40 | {
|
38 | 41 |
|
| 42 | + use CanGenerateTestsTrait; |
| 43 | + |
| 44 | + private bool $isInvokable; |
| 45 | + private ClassData $controllerClassData; |
| 46 | + private bool $usesTwigTemplate; |
| 47 | + private string $twigTemplatePath; |
39 | 48 |
|
40 | 49 | public function __construct(
|
41 | 50 | private ContextGenerator $contextGenerator,
|
42 |
| - private FileManager $fileManager, |
43 | 51 | private ?PhpCompatUtil $phpCompatUtil = null,
|
44 | 52 |
|
45 | 53 | ) {
|
@@ -71,9 +79,99 @@ public function configureCommand(Command $command, InputConfiguration $inputConf
|
71 | 79 | ->addOption('invokable', 'i', InputOption::VALUE_NONE, 'Use this option to create an invokable controller')
|
72 | 80 | ->addOption('context', 'c', InputOption::VALUE_OPTIONAL, 'your context config to generate on your target')
|
73 | 81 | ;
|
| 82 | + $this->configureCommandWithTestsOption($command); |
| 83 | + } |
| 84 | + |
| 85 | + public function interact(InputInterface $input, ConsoleStyle $io, Command $command): void |
| 86 | + { |
| 87 | + $this->usesTwigTemplate = $this->isTwigInstalled() && !$input->getOption('no-template'); |
| 88 | + $this->isInvokable = (bool) $input->getOption('invokable'); |
| 89 | + |
| 90 | + $controllerClass = $input->getArgument('controller-class'); |
| 91 | + $controllerClassName = \sprintf('Controller\%s', $controllerClass); |
| 92 | + |
| 93 | + $context = $input->getOption('context'); |
| 94 | + |
| 95 | + $namespaceContext = $this->contextGenerator->classNameByContext( |
| 96 | + Support::CONTROLLER, |
| 97 | + Str::addSuffix($controllerClass, 'Controller'), |
| 98 | + $context |
| 99 | + ); |
| 100 | + |
| 101 | + // If the class name provided is absolute, we do not assume it will live in src/Controller |
| 102 | + // e.g. src/Custom/Location/For/MyController instead of src/Controller/MyController |
| 103 | + if ($isAbsoluteNamespace = '\\' === $controllerClass[0]) { |
| 104 | + $controllerClassName = substr($controllerClass, 1); |
| 105 | + } |
| 106 | + |
| 107 | + $this->controllerClassData = ClassData::create( |
| 108 | + class: $namespaceContext, |
| 109 | + suffix: 'Controller', |
| 110 | + extendsClass: AbstractController::class, |
| 111 | + useStatements: [ |
| 112 | + $this->usesTwigTemplate ? Response::class : JsonResponse::class, |
| 113 | + \Symfony\Component\Routing\Attribute\Route::class, |
| 114 | + ] |
| 115 | + ); |
| 116 | + |
| 117 | + // Again if the class name is absolute, lets not make assumptions about where the twig template |
| 118 | + // should live. E.g. templates/custom/location/for/my_controller.html.twig instead of |
| 119 | + // templates/my/controller.html.twig. We do however remove the root_namespace prefix in either case |
| 120 | + // so we don't end up with templates/app/my/controller.html.twig |
| 121 | + $templateName = $this->controllerClassData->getFullClassName(withoutRootNamespace: true, withoutSuffix: true); |
| 122 | + |
| 123 | + $dir = $this->contextGenerator->getDirTemplateByContext('template', $context); |
| 124 | + // Convert the twig template name into a file path where it will be generated. |
| 125 | + $this->twigTemplatePath = \sprintf('%s%s', $dir, $this->isInvokable ? '.html.twig' : '/index.html.twig'); |
| 126 | + |
| 127 | + $this->interactSetGenerateTests($input, $io); |
74 | 128 | }
|
75 | 129 |
|
76 | 130 | public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator): void
|
| 131 | + { |
| 132 | + $controllerPath = $generator->generateClassFromClassData($this->controllerClassData, 'controller/Controller.tpl.php', [ |
| 133 | + 'route_path' => Str::asRoutePath($this->controllerClassData->getClassName(relative: true, withoutSuffix: true)), |
| 134 | + 'route_name' => Str::AsRouteName($this->controllerClassData->getClassName(relative: true, withoutSuffix: true)), |
| 135 | + 'method_name' => $this->isInvokable ? '__invoke' : 'index', |
| 136 | + 'with_template' => $this->usesTwigTemplate, |
| 137 | + 'template_name' => $this->twigTemplatePath, |
| 138 | + ], true); |
| 139 | + |
| 140 | + if ($this->usesTwigTemplate) { |
| 141 | + $generator->generateTemplate( |
| 142 | + $this->twigTemplatePath, |
| 143 | + 'controller/twig_template.tpl.php', |
| 144 | + [ |
| 145 | + 'controller_path' => $controllerPath, |
| 146 | + 'root_directory' => $generator->getRootDirectory(), |
| 147 | + 'class_name' => $this->controllerClassData->getClassName(), |
| 148 | + ] |
| 149 | + ); |
| 150 | + } |
| 151 | + |
| 152 | + if ($this->shouldGenerateTests()) { |
| 153 | + $testClassData = ClassData::create( |
| 154 | + class: \sprintf('Tests\Controller\%s', $this->controllerClassData->getClassName(relative: true, withoutSuffix: true)), |
| 155 | + suffix: 'ControllerTest', |
| 156 | + extendsClass: WebTestCase::class, |
| 157 | + ); |
| 158 | + |
| 159 | + $generator->generateClassFromClassData($testClassData, 'controller/test/Test.tpl.php', [ |
| 160 | + 'route_path' => Str::asRoutePath($this->controllerClassData->getClassName(relative: true, withoutSuffix: true)), |
| 161 | + ]); |
| 162 | + |
| 163 | + if (!class_exists(WebTestCase::class)) { |
| 164 | + $io->caution('You\'ll need to install the `symfony/test-pack` to execute the tests for your new controller.'); |
| 165 | + } |
| 166 | + } |
| 167 | + |
| 168 | + $generator->writeChanges(); |
| 169 | + |
| 170 | + $this->writeSuccessMessage($io); |
| 171 | + $io->text('Next: Open your new controller class and add some pages!'); |
| 172 | + } |
| 173 | + |
| 174 | + public function generate1(InputInterface $input, ConsoleStyle $io, Generator $generator): void |
77 | 175 | {
|
78 | 176 | $controllerClass = $input->getArgument('controller-class');
|
79 | 177 | $context = $input->getOption('context');
|
|
0 commit comments