InitBundleCommand.php 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  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 Symfony\Bundle\FrameworkBundle\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\Bundle\FrameworkBundle\Util\Mustache;
  17. /**
  18. * Initializes a new bundle.
  19. *
  20. * @author Fabien Potencier <fabien@symfony.com>
  21. */
  22. class InitBundleCommand extends Command
  23. {
  24. /**
  25. * @see Command
  26. */
  27. protected function configure()
  28. {
  29. $this
  30. ->setDefinition(array(
  31. new InputArgument('namespace', InputArgument::REQUIRED, 'The namespace of the bundle to create'),
  32. new InputArgument('dir', InputArgument::REQUIRED, 'The directory where to create the bundle'),
  33. new InputArgument('bundleName', InputArgument::OPTIONAL, 'The optional bundle name'),
  34. new InputOption('format', '', InputOption::VALUE_REQUIRED, 'Use the format for configuration files (php, xml, or yml)', 'yml')
  35. ))
  36. ->setHelp(<<<EOT
  37. The <info>init:bundle</info> command generates a new bundle with a basic skeleton.
  38. <info>./app/console init:bundle "Vendor\HelloBundle" src [bundleName]</info>
  39. The bundle namespace must end with "Bundle" (e.g. <comment>Vendor\HelloBundle</comment>)
  40. and can be placed in any directory (e.g. <comment>src</comment>).
  41. If you don't specify a bundle name (e.g. <comment>HelloBundle</comment>), the bundle name will
  42. be the concatenation of the namespace segments (e.g. <comment>VendorHelloBundle</comment>).
  43. EOT
  44. )
  45. ->setName('init:bundle')
  46. ;
  47. }
  48. /**
  49. * @see Command
  50. *
  51. * @throws \InvalidArgumentException When namespace doesn't end with Bundle
  52. * @throws \RuntimeException When bundle can't be executed
  53. */
  54. protected function execute(InputInterface $input, OutputInterface $output)
  55. {
  56. if (!preg_match('/Bundle$/', $namespace = $input->getArgument('namespace'))) {
  57. throw new \InvalidArgumentException('The namespace must end with Bundle.');
  58. }
  59. // validate namespace
  60. if (preg_match('/[^A-Za-z0-9_\\\-]/', $namespace)) {
  61. throw new \InvalidArgumentException('The namespace contains invalid characters.');
  62. }
  63. // user specified bundle name?
  64. $bundle = $input->getArgument('bundleName');
  65. if (!$bundle) {
  66. $bundle = strtr($namespace, array('\\' => ''));
  67. }
  68. if (!preg_match('/Bundle$/', $bundle)) {
  69. throw new \InvalidArgumentException('The bundle name must end with Bundle.');
  70. }
  71. // validate that the namespace is at least one level deep
  72. if (false === strpos($namespace, '\\')) {
  73. $msg = array();
  74. $msg[] = sprintf('The namespace must contain a vendor namespace (e.g. "VendorName\%s" instead of simply "%s").', $namespace, $namespace);
  75. $msg[] = 'If you\'ve specified a vendor namespace, did you forget to surround it with quotes (init:bundle "Acme\BlogBundle")?';
  76. throw new \InvalidArgumentException(implode("\n\n", $msg));
  77. }
  78. $dir = $input->getArgument('dir');
  79. // add trailing / if necessary
  80. $dir = '/' === substr($dir, -1, 1) ? $dir : $dir.'/';
  81. $targetDir = $dir.strtr($namespace, '\\', '/');
  82. if (file_exists($targetDir)) {
  83. throw new \RuntimeException(sprintf('Bundle "%s" already exists.', $bundle));
  84. }
  85. $filesystem = $this->container->get('filesystem');
  86. $filesystem->mirror(__DIR__.'/../Resources/skeleton/bundle/generic', $targetDir);
  87. $filesystem->mirror(__DIR__.'/../Resources/skeleton/bundle/'.$input->getOption('format'), $targetDir);
  88. Mustache::renderDir($targetDir, array(
  89. 'namespace' => $namespace,
  90. 'bundle' => $bundle,
  91. ));
  92. rename($targetDir.'/Bundle.php', $targetDir.'/'.$bundle.'.php');
  93. $output->writeln('<comment>Summary of actions</comment>');
  94. $output->writeln(sprintf('- The bundle "<info>%s</info>" was created at "<info>%s</info>" and is using the namespace "<info>%s</info>".', $bundle, $targetDir, $namespace));
  95. $output->writeln(sprintf('- The bundle contains a sample controller, a sample template and a sample routing file.'));
  96. $output->writeln('');
  97. $output->writeln('<comment>Follow-up actions</comment>');
  98. $output->writeln('- Enable the bundle inside the AppKernel::registerBundles() method.');
  99. $output->writeln(' Resource: <info>http://symfony.com/doc/2.0/book/page_creation.html#create-the-bundle</info>');
  100. $output->writeln('- Ensure that the namespace is registered with the autoloader.');
  101. $output->writeln(' Resource: <info>http://symfony.com/doc/2.0/book/page_creation.html#autoloading-introduction-sidebar</info>');
  102. $output->writeln('- If using routing, import the bundle\'s routing resource.');
  103. $output->writeln(' Resource: <info>http://symfony.com/doc/2.0/book/routing.html#including-external-routing-resources</info>');
  104. $output->writeln('- Starting building your bundle!');
  105. $output->writeln(' Resource: <info>http://symfony.com/doc/2.0/book/page_creation.html#the-hello-symfony-page</info>');
  106. }
  107. }