PageRenderTime 41ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/sensio/generator-bundle/Sensio/Bundle/GeneratorBundle/Command/GenerateDoctrineEntityCommand.php

https://gitlab.com/TouirMohamedMarwen/Symfony2
PHP | 302 lines | 253 code | 31 blank | 18 comment | 7 complexity | 4eca7bfcf086bbcc8ed61ad9a950717b MD5 | raw file
  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 Sensio\Bundle\GeneratorBundle\Generator\DoctrineEntityGenerator;
  12. use Sensio\Bundle\GeneratorBundle\Command\Helper\DialogHelper;
  13. use Symfony\Component\Console\Input\InputOption;
  14. use Symfony\Component\Console\Input\InputInterface;
  15. use Symfony\Component\Console\Output\OutputInterface;
  16. use Symfony\Component\DependencyInjection\Container;
  17. use Doctrine\DBAL\Types\Type;
  18. /**
  19. * Initializes a Doctrine entity inside a bundle.
  20. *
  21. * @author Fabien Potencier <fabien@symfony.com>
  22. */
  23. class GenerateDoctrineEntityCommand extends GenerateDoctrineCommand
  24. {
  25. protected function configure()
  26. {
  27. $this
  28. ->setName('doctrine:generate:entity')
  29. ->setAliases(array('generate:doctrine:entity'))
  30. ->setDescription('Generates a new Doctrine entity inside a bundle')
  31. ->addOption('entity', null, InputOption::VALUE_REQUIRED, 'The entity class name to initialize (shortcut notation)')
  32. ->addOption('fields', null, InputOption::VALUE_REQUIRED, 'The fields to create with the new entity')
  33. ->addOption('format', null, InputOption::VALUE_REQUIRED, 'Use the format for configuration files (php, xml, yml, or annotation)', 'annotation')
  34. ->addOption('with-repository', null, InputOption::VALUE_NONE, 'Whether to generate the entity repository or not')
  35. ->setHelp(<<<EOT
  36. The <info>doctrine:generate:entity</info> task generates a new Doctrine
  37. entity inside a bundle:
  38. <info>php app/console doctrine:generate:entity --entity=AcmeBlogBundle:Blog/Post</info>
  39. The above command would initialize a new entity in the following entity
  40. namespace <info>Acme\BlogBundle\Entity\Blog\Post</info>.
  41. You can also optionally specify the fields you want to generate in the new
  42. entity:
  43. <info>php app/console doctrine:generate:entity --entity=AcmeBlogBundle:Blog/Post --fields="title:string(255) body:text"</info>
  44. The command can also generate the corresponding entity repository class with the
  45. <comment>--with-repository</comment> option:
  46. <info>php app/console doctrine:generate:entity --entity=AcmeBlogBundle:Blog/Post --with-repository</info>
  47. By default, the command uses annotations for the mapping information; change it
  48. with <comment>--format</comment>:
  49. <info>php app/console doctrine:generate:entity --entity=AcmeBlogBundle:Blog/Post --format=yml</info>
  50. To deactivate the interaction mode, simply use the `--no-interaction` option
  51. without forgetting to pass all needed options:
  52. <info>php app/console doctrine:generate:entity --entity=AcmeBlogBundle:Blog/Post --format=annotation --fields="title:string(255) body:text" --with-repository --no-interaction</info>
  53. EOT
  54. );
  55. }
  56. /**
  57. * @throws \InvalidArgumentException When the bundle doesn't end with Bundle (Example: "Bundle/MySampleBundle")
  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. $fields = $this->parseFields($input->getOption('fields'));
  72. $dialog->writeSection($output, 'Entity generation');
  73. $bundle = $this->getContainer()->get('kernel')->getBundle($bundle);
  74. $generator = $this->getGenerator();
  75. $generator->generate($bundle, $entity, $format, array_values($fields), $input->getOption('with-repository'));
  76. $output->writeln('Generating the entity code: <info>OK</info>');
  77. $dialog->writeGeneratorSummary($output, array());
  78. }
  79. protected function interact(InputInterface $input, OutputInterface $output)
  80. {
  81. $dialog = $this->getDialogHelper();
  82. $dialog->writeSection($output, 'Welcome to the Doctrine2 entity generator');
  83. // namespace
  84. $output->writeln(array(
  85. '',
  86. 'This command helps you generate Doctrine2 entities.',
  87. '',
  88. 'First, you need to give the entity name you want to generate.',
  89. 'You must use the shortcut notation like <comment>AcmeBlogBundle:Post</comment>.',
  90. '',
  91. ));
  92. $bundleNames = array_keys($this->getContainer()->get('kernel')->getBundles());
  93. while (true) {
  94. $entity = $dialog->askAndValidate($output, $dialog->getQuestion('The Entity shortcut name', $input->getOption('entity')), array('Sensio\Bundle\GeneratorBundle\Command\Validators', 'validateEntityName'), false, $input->getOption('entity'), $bundleNames);
  95. list($bundle, $entity) = $this->parseShortcutNotation($entity);
  96. // check reserved words
  97. if ($this->getGenerator()->isReservedKeyword($entity)) {
  98. $output->writeln(sprintf('<bg=red> "%s" is a reserved word</>.', $entity));
  99. continue;
  100. }
  101. try {
  102. $b = $this->getContainer()->get('kernel')->getBundle($bundle);
  103. if (!file_exists($b->getPath().'/Entity/'.str_replace('\\', '/', $entity).'.php')) {
  104. break;
  105. }
  106. $output->writeln(sprintf('<bg=red>Entity "%s:%s" already exists</>.', $bundle, $entity));
  107. } catch (\Exception $e) {
  108. $output->writeln(sprintf('<bg=red>Bundle "%s" does not exist.</>', $bundle));
  109. }
  110. }
  111. $input->setOption('entity', $bundle.':'.$entity);
  112. // format
  113. $output->writeln(array(
  114. '',
  115. 'Determine the format to use for the mapping information.',
  116. '',
  117. ));
  118. $formats = array('yml', 'xml', 'php', 'annotation');
  119. $format = $dialog->askAndValidate($output, $dialog->getQuestion('Configuration format (yml, xml, php, or annotation)', $input->getOption('format')), array('Sensio\Bundle\GeneratorBundle\Command\Validators', 'validateFormat'), false, $input->getOption('format'), $formats);
  120. $input->setOption('format', $format);
  121. // fields
  122. $input->setOption('fields', $this->addFields($input, $output, $dialog));
  123. // repository?
  124. $output->writeln('');
  125. $withRepository = $dialog->askConfirmation($output, $dialog->getQuestion('Do you want to generate an empty repository class', $input->getOption('with-repository') ? 'yes' : 'no', '?'), $input->getOption('with-repository'));
  126. $input->setOption('with-repository', $withRepository);
  127. // summary
  128. $output->writeln(array(
  129. '',
  130. $this->getHelper('formatter')->formatBlock('Summary before generation', 'bg=blue;fg=white', true),
  131. '',
  132. sprintf("You are going to generate a \"<info>%s:%s</info>\" Doctrine2 entity", $bundle, $entity),
  133. sprintf("using the \"<info>%s</info>\" format.", $format),
  134. '',
  135. ));
  136. }
  137. private function parseFields($input)
  138. {
  139. if (is_array($input)) {
  140. return $input;
  141. }
  142. $fields = array();
  143. foreach (explode(' ', $input) as $value) {
  144. $elements = explode(':', $value);
  145. $name = $elements[0];
  146. if (strlen($name)) {
  147. $type = isset($elements[1]) ? $elements[1] : 'string';
  148. preg_match_all('/(.*)\((.*)\)/', $type, $matches);
  149. $type = isset($matches[1][0]) ? $matches[1][0] : $type;
  150. $length = isset($matches[2][0]) ? $matches[2][0] : null;
  151. $fields[$name] = array('fieldName' => $name, 'type' => $type, 'length' => $length);
  152. }
  153. }
  154. return $fields;
  155. }
  156. private function addFields(InputInterface $input, OutputInterface $output, DialogHelper $dialog)
  157. {
  158. $fields = $this->parseFields($input->getOption('fields'));
  159. $output->writeln(array(
  160. '',
  161. 'Instead of starting with a blank entity, you can add some fields now.',
  162. 'Note that the primary key will be added automatically (named <comment>id</comment>).',
  163. '',
  164. ));
  165. $output->write('<info>Available types:</info> ');
  166. $types = array_keys(Type::getTypesMap());
  167. $count = 20;
  168. foreach ($types as $i => $type) {
  169. if ($count > 50) {
  170. $count = 0;
  171. $output->writeln('');
  172. }
  173. $count += strlen($type);
  174. $output->write(sprintf('<comment>%s</comment>', $type));
  175. if (count($types) != $i + 1) {
  176. $output->write(', ');
  177. } else {
  178. $output->write('.');
  179. }
  180. }
  181. $output->writeln('');
  182. $fieldValidator = function ($type) use ($types) {
  183. // FIXME: take into account user-defined field types
  184. if (!in_array($type, $types)) {
  185. throw new \InvalidArgumentException(sprintf('Invalid type "%s".', $type));
  186. }
  187. return $type;
  188. };
  189. $lengthValidator = function ($length) {
  190. if (!$length) {
  191. return $length;
  192. }
  193. $result = filter_var($length, FILTER_VALIDATE_INT, array(
  194. 'options' => array('min_range' => 1),
  195. ));
  196. if (false === $result) {
  197. throw new \InvalidArgumentException(sprintf('Invalid length "%s".', $length));
  198. }
  199. return $length;
  200. };
  201. while (true) {
  202. $output->writeln('');
  203. $generator = $this->getGenerator();
  204. $columnName = $dialog->askAndValidate($output, $dialog->getQuestion('New field name (press <return> to stop adding fields)', null), function ($name) use ($fields, $generator) {
  205. if (isset($fields[$name]) || 'id' == $name) {
  206. throw new \InvalidArgumentException(sprintf('Field "%s" is already defined.', $name));
  207. }
  208. // check reserved words
  209. if ($generator->isReservedKeyword($name)) {
  210. throw new \InvalidArgumentException(sprintf('Name "%s" is a reserved word.', $name));
  211. }
  212. return $name;
  213. });
  214. if (!$columnName) {
  215. break;
  216. }
  217. $defaultType = 'string';
  218. // try to guess the type by the column name prefix/suffix
  219. if (substr($columnName, -3) == '_at') {
  220. $defaultType = 'datetime';
  221. } elseif (substr($columnName, -3) == '_id') {
  222. $defaultType = 'integer';
  223. } elseif (substr($columnName, 0, 3) == 'is_') {
  224. $defaultType = 'boolean';
  225. } elseif (substr($columnName, 0, 4) == 'has_') {
  226. $defaultType = 'boolean';
  227. }
  228. $type = $dialog->askAndValidate($output, $dialog->getQuestion('Field type', $defaultType), $fieldValidator, false, $defaultType, $types);
  229. $data = array('columnName' => $columnName, 'fieldName' => lcfirst(Container::camelize($columnName)), 'type' => $type);
  230. if ($type == 'string') {
  231. $data['length'] = $dialog->askAndValidate($output, $dialog->getQuestion('Field length', 255), $lengthValidator, false, 255);
  232. }
  233. $fields[$columnName] = $data;
  234. }
  235. return $fields;
  236. }
  237. protected function createGenerator()
  238. {
  239. return new DoctrineEntityGenerator($this->getContainer()->get('filesystem'), $this->getContainer()->get('doctrine'));
  240. }
  241. }