GenerateDoctrineCrudCommand.php 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Sensio\Bundle\GeneratorBundle\Command;
  11. use Symfony\Component\Console\Input\InputArgument;
  12. use Symfony\Component\Console\Input\InputOption;
  13. use Symfony\Component\Console\Input\InputInterface;
  14. use Symfony\Component\Console\Output\OutputInterface;
  15. use Symfony\Component\Console\Output\Output;
  16. use Symfony\Component\Console\Command\Command;
  17. use Sensio\Bundle\GeneratorBundle\Generator\DoctrineCrudGenerator;
  18. use Sensio\Bundle\GeneratorBundle\Generator\DoctrineFormGenerator;
  19. use Sensio\Bundle\GeneratorBundle\Command\Helper\DialogHelper;
  20. use Sensio\Bundle\GeneratorBundle\Manipulator\RoutingManipulator;
  21. use Doctrine\ORM\Mapping\MappingException;
  22. /**
  23. * Generates a CRUD for a Doctrine entity.
  24. *
  25. * @author Fabien Potencier <fabien@symfony.com>
  26. */
  27. class GenerateDoctrineCrudCommand extends GenerateDoctrineCommand
  28. {
  29. private $generator;
  30. private $formGenerator;
  31. /**
  32. * @see Command
  33. */
  34. protected function configure()
  35. {
  36. $this
  37. ->setDefinition(array(
  38. new InputOption('entity', '', InputOption::VALUE_REQUIRED, 'The entity class name to initialize (shortcut notation)'),
  39. new InputOption('route-prefix', '', InputOption::VALUE_REQUIRED, 'The route prefix'),
  40. new InputOption('with-write', '', InputOption::VALUE_NONE, 'Whether or not to generate create, new and delete actions'),
  41. new InputOption('format', '', InputOption::VALUE_REQUIRED, 'Use the format for configuration files (php, xml, yml, or annotation)', 'annotation'),
  42. ))
  43. ->setDescription('Generates a CRUD based on a Doctrine entity')
  44. ->setHelp(<<<EOT
  45. The <info>doctrine:generate:crud</info> command generates a CRUD based on a Doctrine entity.
  46. The default command only generates the list and show actions.
  47. <info>php app/console doctrine:generate:crud --entity=AcmeBlogBundle:Post --route-prefix=post_admin</info>
  48. Using the --with-write option allows to generate the new, edit and delete actions.
  49. <info>php app/console doctrine:generate:crud --entity=AcmeBlogBundle:Post --route-prefix=post_admin --with-write</info>
  50. EOT
  51. )
  52. ->setName('doctrine:generate:crud')
  53. ->setAliases(array('generate:doctrine:crud'))
  54. ;
  55. }
  56. /**
  57. * @see Command
  58. */
  59. protected function execute(InputInterface $input, OutputInterface $output)
  60. {
  61. $dialog = $this->getDialogHelper();
  62. if ($input->isInteractive()) {
  63. if (!$dialog->askConfirmation($output, $dialog->getQuestion('Do you confirm generation', 'yes', '?'), true)) {
  64. $output->writeln('<error>Command aborted</error>');
  65. return 1;
  66. }
  67. }
  68. $entity = Validators::validateEntityName($input->getOption('entity'));
  69. list($bundle, $entity) = $this->parseShortcutNotation($entity);
  70. $format = Validators::validateFormat($input->getOption('format'));
  71. $prefix = $this->getRoutePrefix($input, $entity);
  72. $withWrite = $input->getOption('with-write');
  73. $dialog->writeSection($output, 'CRUD generation');
  74. $entityClass = $this->getContainer()->get('doctrine')->getEntityNamespace($bundle).'\\'.$entity;
  75. $metadata = $this->getEntityMetadata($entityClass);
  76. $bundle = $this->getContainer()->get('kernel')->getBundle($bundle);
  77. $generator = $this->getGenerator();
  78. $generator->generate($bundle, $entity, $metadata[0], $format, $prefix, $withWrite);
  79. $output->writeln('Generating the CRUD code: <info>OK</info>');
  80. $errors = array();
  81. $runner = $dialog->getRunner($output, $errors);
  82. // form
  83. if ($withWrite) {
  84. $this->generateForm($bundle, $entity, $metadata);
  85. $output->writeln('Generating the Form code: <info>OK</info>');
  86. }
  87. // routing
  88. if ('annotation' != $format) {
  89. $runner($this->updateRouting($dialog, $input, $output, $bundle, $format, $entity, $prefix));
  90. }
  91. $dialog->writeGeneratorSummary($output, $errors);
  92. }
  93. protected function interact(InputInterface $input, OutputInterface $output)
  94. {
  95. $dialog = $this->getDialogHelper();
  96. $dialog->writeSection($output, 'Welcome to the Doctrine2 CRUD generator');
  97. // namespace
  98. $output->writeln(array(
  99. '',
  100. 'This command helps you generate CRUD controllers and templates.',
  101. '',
  102. 'First, you need to give the entity for which you want to generate a CRUD.',
  103. 'You can give an entity that does not exist yet and the wizard will help',
  104. 'you defining it.',
  105. '',
  106. 'You must use the shortcut notation like <comment>AcmeBlogBundle:Post</comment>.',
  107. '',
  108. ));
  109. $entity = $dialog->askAndValidate($output, $dialog->getQuestion('The Entity shortcut name', $input->getOption('entity')), array('Sensio\Bundle\GeneratorBundle\Command\Validators', 'validateEntityName'), false, $input->getOption('entity'));
  110. $input->setOption('entity', $entity);
  111. list($bundle, $entity) = $this->parseShortcutNotation($entity);
  112. // Entity exists?
  113. $entityClass = $this->getContainer()->get('doctrine')->getEntityNamespace($bundle).'\\'.$entity;
  114. $metadata = $this->getEntityMetadata($entityClass);
  115. // write?
  116. $withWrite = $input->getOption('with-write') ?: false;
  117. $output->writeln(array(
  118. '',
  119. 'By default, the generator creates two actions: list and show.',
  120. 'You can also ask it to generate "write" actions: new, update, and delete.',
  121. '',
  122. ));
  123. $withWrite = $dialog->askConfirmation($output, $dialog->getQuestion('Do you want to generate the "write" actions', $withWrite ? 'yes' : 'no', '?'), $withWrite);
  124. $input->setOption('with-write', $withWrite);
  125. // format
  126. $format = $input->getOption('format');
  127. $output->writeln(array(
  128. '',
  129. 'Determine the format to use for the generated CRUD.',
  130. '',
  131. ));
  132. $format = $dialog->askAndValidate($output, $dialog->getQuestion('Configuration format (yml, xml, php, or annotation)', $format), array('Sensio\Bundle\GeneratorBundle\Command\Validators', 'validateFormat'), false, $format);
  133. $input->setOption('format', $format);
  134. // route prefix
  135. $prefix = $this->getRoutePrefix($input, $entity);
  136. $output->writeln(array(
  137. '',
  138. 'Determine the routes prefix (all the routes will be "mounted" under this',
  139. 'prefix: /prefix/, /prefix/new, ...).',
  140. '',
  141. ));
  142. $prefix = $dialog->ask($output, $dialog->getQuestion('Routes prefix', '/'.$prefix), '/'.$prefix);
  143. $input->setOption('route-prefix', $prefix);
  144. // summary
  145. $output->writeln(array(
  146. '',
  147. $this->getHelper('formatter')->formatBlock('Summary before generation', 'bg=blue;fg=white', true),
  148. '',
  149. sprintf("You are going to generate a CRUD controller for \"<info>%s:%s</info>\"", $bundle, $entity),
  150. sprintf("using the \"<info>%s</info>\" format.", $format),
  151. '',
  152. ));
  153. }
  154. /**
  155. * Tries to generate forms if they don't exist yet and if we need write operations on entities.
  156. */
  157. private function generateForm($bundle, $entity, $metadata)
  158. {
  159. try {
  160. $this->getFormGenerator()->generate($bundle, $entity, $metadata[0]);
  161. } catch (\RuntimeException $e ) {
  162. // form already exists
  163. }
  164. }
  165. private function updateRouting($dialog, InputInterface $input, OutputInterface $output, $bundle, $format, $entity, $prefix)
  166. {
  167. $auto = true;
  168. if ($input->isInteractive()) {
  169. $auto = $dialog->askConfirmation($output, $dialog->getQuestion('Confirm automatic update of the Routing', 'yes', '?'), true);
  170. }
  171. $output->write('Importing the CRUD routes: ');
  172. $this->getContainer()->get('filesystem')->mkdir($bundle->getPath().'/Resources/config/');
  173. $routing = new RoutingManipulator($bundle->getPath().'/Resources/config/routing.yml');
  174. $ret = $auto ? $routing->addResource($bundle->getName(), $format, '/'.$prefix, 'routing/'.strtolower(str_replace('\\', '_', $entity))) : false;
  175. if (!$ret) {
  176. $help = sprintf(" <comment>resource: \"@%s/Resources/config/routing/%s.%s\"</comment>\n", $bundle->getName(), strtolower(str_replace('\\', '_', $entity)), $format);
  177. $help .= sprintf(" <comment>prefix: /%s</comment>\n", $prefix);
  178. return array(
  179. '- Import the bundle\'s routing resource in the bundle routing file',
  180. sprintf(' (%s).', $bundle->getPath().'/Resources/config/routing.yml'),
  181. '',
  182. sprintf(' <comment>%s:</comment>', $bundle->getName().('' !== $prefix ? '_'.str_replace('/', '_', $prefix) : '')),
  183. $help,
  184. '',
  185. );
  186. }
  187. }
  188. protected function getRoutePrefix(InputInterface $input, $entity)
  189. {
  190. $prefix = $input->getOption('route-prefix') ?: strtolower(str_replace(array('\\', '/'), '_', $entity));
  191. if ($prefix && '/' === $prefix[0]) {
  192. $prefix = substr($prefix, 1);
  193. }
  194. return $prefix;
  195. }
  196. protected function getGenerator()
  197. {
  198. if (null === $this->generator) {
  199. $this->generator = new DoctrineCrudGenerator($this->getContainer()->get('filesystem'), __DIR__.'/../Resources/skeleton/crud');
  200. }
  201. return $this->generator;
  202. }
  203. public function setGenerator(DoctrineCrudGenerator $generator)
  204. {
  205. $this->generator = $generator;
  206. }
  207. protected function getFormGenerator()
  208. {
  209. if (null === $this->formGenerator) {
  210. $this->formGenerator = new DoctrineFormGenerator($this->getContainer()->get('filesystem'), __DIR__.'/../Resources/skeleton/form');;
  211. }
  212. return $this->formGenerator;
  213. }
  214. public function setFormGenerator(DoctrineFormGenerator $formGenerator)
  215. {
  216. $this->formGenerator = $formGenerator;
  217. }
  218. protected function getDialogHelper()
  219. {
  220. $dialog = $this->getHelperSet()->get('dialog');
  221. if (!$dialog || get_class($dialog) !== 'Sensio\Bundle\GeneratorBundle\Command\Helper\DialogHelper') {
  222. $this->getHelperSet()->set($dialog = new DialogHelper());
  223. }
  224. return $dialog;
  225. }
  226. }