CreateDatabaseCommand.php 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. <?php
  2. declare(strict_types=1);
  3. namespace Shlinkio\Shlink\CLI\Command\Db;
  4. use Doctrine\DBAL\Connection;
  5. use Shlinkio\Shlink\CLI\Util\ExitCodes;
  6. use Shlinkio\Shlink\CLI\Util\ProcessRunnerInterface;
  7. use Symfony\Component\Console\Input\InputInterface;
  8. use Symfony\Component\Console\Output\OutputInterface;
  9. use Symfony\Component\Console\Style\SymfonyStyle;
  10. use Symfony\Component\Lock\LockFactory;
  11. use Symfony\Component\Process\PhpExecutableFinder;
  12. use function Functional\contains;
  13. class CreateDatabaseCommand extends AbstractDatabaseCommand
  14. {
  15. public const NAME = 'db:create';
  16. public const DOCTRINE_SCRIPT = 'vendor/doctrine/orm/bin/doctrine.php';
  17. public const DOCTRINE_CREATE_SCHEMA_COMMAND = 'orm:schema-tool:create';
  18. private Connection $regularConn;
  19. private Connection $noDbNameConn;
  20. public function __construct(
  21. LockFactory $locker,
  22. ProcessRunnerInterface $processRunner,
  23. PhpExecutableFinder $phpFinder,
  24. Connection $conn,
  25. Connection $noDbNameConn
  26. ) {
  27. parent::__construct($locker, $processRunner, $phpFinder);
  28. $this->regularConn = $conn;
  29. $this->noDbNameConn = $noDbNameConn;
  30. }
  31. protected function configure(): void
  32. {
  33. $this
  34. ->setName(self::NAME)
  35. ->setDescription(
  36. 'Creates the database needed for shlink to work. It will do nothing if the database already exists',
  37. );
  38. }
  39. protected function lockedExecute(InputInterface $input, OutputInterface $output): int
  40. {
  41. $io = new SymfonyStyle($input, $output);
  42. $this->checkDbExists();
  43. if ($this->schemaExists()) {
  44. $io->success('Database already exists. Run "db:migrate" command to make sure it is up to date.');
  45. return ExitCodes::EXIT_SUCCESS;
  46. }
  47. // Create database
  48. $io->writeln('<fg=blue>Creating database tables...</>');
  49. $this->runPhpCommand($output, [self::DOCTRINE_SCRIPT, self::DOCTRINE_CREATE_SCHEMA_COMMAND]);
  50. $io->success('Database properly created!');
  51. return ExitCodes::EXIT_SUCCESS;
  52. }
  53. private function checkDbExists(): void
  54. {
  55. if ($this->regularConn->getDatabasePlatform()->getName() === 'sqlite') {
  56. return;
  57. }
  58. // In order to create the new database, we have to use a connection where the dbname was not set.
  59. // Otherwise, it will fail to connect and will not be able to create the new database
  60. $schemaManager = $this->noDbNameConn->getSchemaManager();
  61. $databases = $schemaManager->listDatabases();
  62. $shlinkDatabase = $this->regularConn->getDatabase();
  63. if (! contains($databases, $shlinkDatabase)) {
  64. $schemaManager->createDatabase($shlinkDatabase);
  65. }
  66. }
  67. private function schemaExists(): bool
  68. {
  69. // If at least one of the shlink tables exist, we will consider the database exists somehow.
  70. // Any inconsistency should be taken care by the migrations
  71. $schemaManager = $this->regularConn->getSchemaManager();
  72. return ! empty($schemaManager->listTableNames());
  73. }
  74. }