CreateDatabaseDoctrineCommand.php 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. <?php
  2. namespace Doctrine\Bundle\DoctrineBundle\Command;
  3. use Doctrine\DBAL\DriverManager;
  4. use Doctrine\DBAL\Sharding\PoolingShardConnection;
  5. use InvalidArgumentException;
  6. use Symfony\Component\Console\Input\InputInterface;
  7. use Symfony\Component\Console\Input\InputOption;
  8. use Symfony\Component\Console\Output\OutputInterface;
  9. use Throwable;
  10. use function array_merge;
  11. use function in_array;
  12. use function sprintf;
  13. /**
  14. * Database tool allows you to easily create your configured databases.
  15. *
  16. * @final
  17. */
  18. class CreateDatabaseDoctrineCommand extends DoctrineCommand
  19. {
  20. /**
  21. * {@inheritDoc}
  22. */
  23. protected function configure()
  24. {
  25. $this
  26. ->setName('doctrine:database:create')
  27. ->setDescription('Creates the configured database')
  28. ->addOption('shard', 's', InputOption::VALUE_REQUIRED, 'The shard connection to use for this command')
  29. ->addOption('connection', 'c', InputOption::VALUE_OPTIONAL, 'The connection to use for this command')
  30. ->addOption('if-not-exists', null, InputOption::VALUE_NONE, 'Don\'t trigger an error, when the database already exists')
  31. ->setHelp(<<<EOT
  32. The <info>%command.name%</info> command creates the default connections database:
  33. <info>php %command.full_name%</info>
  34. You can also optionally specify the name of a connection to create the database for:
  35. <info>php %command.full_name% --connection=default</info>
  36. EOT
  37. );
  38. }
  39. /**
  40. * {@inheritDoc}
  41. */
  42. protected function execute(InputInterface $input, OutputInterface $output)
  43. {
  44. $connectionName = $input->getOption('connection');
  45. if (empty($connectionName)) {
  46. $connectionName = $this->getDoctrine()->getDefaultConnectionName();
  47. }
  48. $connection = $this->getDoctrineConnection($connectionName);
  49. $ifNotExists = $input->getOption('if-not-exists');
  50. $driverOptions = [];
  51. $params = $connection->getParams();
  52. if (isset($params['driverOptions'])) {
  53. $driverOptions = $params['driverOptions'];
  54. }
  55. // Since doctrine/dbal 2.11 master has been replaced by primary
  56. if (isset($params['primary'])) {
  57. $params = $params['primary'];
  58. $params['driverOptions'] = $driverOptions;
  59. }
  60. if (isset($params['master'])) {
  61. $params = $params['master'];
  62. $params['driverOptions'] = $driverOptions;
  63. }
  64. // Cannot inject `shard` option in parent::getDoctrineConnection
  65. // cause it will try to connect to a non-existing database
  66. if (isset($params['shards'])) {
  67. $shards = $params['shards'];
  68. // Default select global
  69. $params = array_merge($params, $params['global'] ?? []);
  70. unset($params['global']['dbname'], $params['global']['path'], $params['global']['url']);
  71. if ($input->getOption('shard')) {
  72. foreach ($shards as $i => $shard) {
  73. if ($shard['id'] === (int) $input->getOption('shard')) {
  74. // Select sharded database
  75. $params = array_merge($params, $shard);
  76. unset($params['shards'][$i]['dbname'], $params['shards'][$i]['path'], $params['shards'][$i]['url'], $params['id']);
  77. break;
  78. }
  79. }
  80. }
  81. }
  82. $hasPath = isset($params['path']);
  83. $name = $hasPath ? $params['path'] : ($params['dbname'] ?? false);
  84. if (! $name) {
  85. throw new InvalidArgumentException("Connection does not contain a 'path' or 'dbname' parameter and cannot be created.");
  86. }
  87. // Need to get rid of _every_ occurrence of dbname from connection configuration and we have already extracted all relevant info from url
  88. unset($params['dbname'], $params['path'], $params['url']);
  89. $tmpConnection = DriverManager::getConnection($params);
  90. if ($tmpConnection instanceof PoolingShardConnection) {
  91. $tmpConnection->connect($input->getOption('shard'));
  92. } else {
  93. $tmpConnection->connect();
  94. }
  95. $shouldNotCreateDatabase = $ifNotExists && in_array($name, $tmpConnection->getSchemaManager()->listDatabases());
  96. // Only quote if we don't have a path
  97. if (! $hasPath) {
  98. $name = $tmpConnection->getDatabasePlatform()->quoteSingleIdentifier($name);
  99. }
  100. $error = false;
  101. try {
  102. if ($shouldNotCreateDatabase) {
  103. $output->writeln(sprintf('<info>Database <comment>%s</comment> for connection named <comment>%s</comment> already exists. Skipped.</info>', $name, $connectionName));
  104. } else {
  105. $tmpConnection->getSchemaManager()->createDatabase($name);
  106. $output->writeln(sprintf('<info>Created database <comment>%s</comment> for connection named <comment>%s</comment></info>', $name, $connectionName));
  107. }
  108. } catch (Throwable $e) {
  109. $output->writeln(sprintf('<error>Could not create database <comment>%s</comment> for connection named <comment>%s</comment></error>', $name, $connectionName));
  110. $output->writeln(sprintf('<error>%s</error>', $e->getMessage()));
  111. $error = true;
  112. }
  113. $tmpConnection->close();
  114. return $error ? 1 : 0;
  115. }
  116. }