CreateDatabaseCommand::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

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