DropDatabaseDoctrineCommand::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 2
c 1
b 0
f 1
dl 0
loc 5
ccs 3
cts 3
cp 1
rs 10
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Chubbyphp\DoctrineDbServiceProvider\Command;
6
7
use Doctrine\Common\Persistence\ConnectionRegistry;
8
use Doctrine\DBAL\Connection;
9
use Doctrine\DBAL\DriverManager;
10
use Symfony\Component\Console\Command\Command;
11
use Symfony\Component\Console\Input\InputInterface;
12
use Symfony\Component\Console\Input\InputOption;
13
use Symfony\Component\Console\Output\OutputInterface;
14
15
/**
16
 * @see https://github.com/doctrine/DoctrineBundle/blob/master/Command/DropDatabaseDoctrineCommand.php
17
 */
18
final class DropDatabaseDoctrineCommand extends Command
19
{
20
    const RETURN_CODE_NOT_DROP = 1;
21
22
    const RETURN_CODE_NO_FORCE = 2;
23
24
    /**
25
     * @var ConnectionRegistry
26
     */
27
    private $connectionRegistry;
28
29 6
    public function __construct(ConnectionRegistry $connectionRegistry)
30
    {
31 6
        parent::__construct();
32
33 6
        $this->connectionRegistry = $connectionRegistry;
34 6
    }
35
36 6
    protected function configure(): void
37
    {
38
        $this
39 6
            ->setName('dbal:database:drop')
40 6
            ->setDescription('Drops the configured database')
41 6
            ->addOption('connection', null, InputOption::VALUE_OPTIONAL, 'The connection to use for this command')
42 6
            ->addOption(
43 6
                'if-exists',
44 6
                null,
45 6
                InputOption::VALUE_NONE,
46 6
                'Don\'t trigger an error, when the database doesn\'t exist'
47
            )
48 6
            ->addOption('force', null, InputOption::VALUE_NONE, 'Set this parameter to execute this action')
49 6
            ->setHelp(<<<'EOT'
50 6
The <info>%command.name%</info> command drops the default connections database:
51
52
    <info>php %command.full_name%</info>
53
54
The <info>--force</info> parameter has to be used to actually drop the database.
55
56
You can also optionally specify the name of a connection to drop the database for:
57
58
    <info>php %command.full_name% --connection=default</info>
59
60
<error>Be careful: All data in a given database will be lost when executing this command.</error>
61
EOT
62
            )
63
        ;
64 6
    }
65
66 6
    protected function execute(InputInterface $input, OutputInterface $output): int
67
    {
68 6
        $connectionName = $this->getConnectionName($input);
69
70
        /** @var Connection $connection */
71 6
        $connection = $this->connectionRegistry->getConnection($connectionName);
72
73 6
        $params = $this->getParams($connection);
74
75 6
        $dbName = $this->getDbName($params);
76
77 5
        if (!$input->getOption('force')) {
78 1
            $this->writeMissingForceOutput($output, $dbName, $connectionName);
79
80 1
            return self::RETURN_CODE_NO_FORCE;
81
        }
82
83 4
        $isPath = isset($params['path']);
84
85 4
        $ifExists = $input->getOption('if-exists');
86
87
        // Need to get rid of _every_ occurrence of dbname from connection configuration
88 4
        unset($params['dbname'], $params['path'], $params['url']);
89
90 4
        $connection->close();
91 4
        $connection = DriverManager::getConnection($params);
92 4
        $shouldDropDatabase = !$ifExists || in_array($dbName, $connection->getSchemaManager()->listDatabases());
93
94
        // Only quote if we don't have a path
95 4
        if (!$isPath) {
96 3
            $dbName = $connection->getDatabasePlatform()->quoteSingleIdentifier($dbName);
97
        }
98
99 4
        return $this->dropDatabase($output, $connectionName, $connection, $dbName, $shouldDropDatabase);
100
    }
101
102 6
    private function getConnectionName(InputInterface $input): string
103
    {
104
        /** @var string|null $connectionName */
105 6
        $connectionName = $input->getOption('connection');
106
107 6
        if (null !== $connectionName) {
108 3
            return $connectionName;
109
        }
110
111 3
        return $this->connectionRegistry->getDefaultConnectionName();
112
    }
113
114 6
    private function getParams(Connection $connection): array
115
    {
116 6
        $params = $connection->getParams();
117 6
        if (isset($params['master'])) {
118 3
            $params = $params['master'];
119
        }
120
121 6
        return $params;
122
    }
123
124
    /**
125
     * @param array<string, string> $params
126
     */
127
    private function getDbName(array $params): string
128
    {
129 6
        if (isset($params['path'])) {
130
            return $params['path'];
131 6
        }
132 2
133
        if (isset($params['dbname'])) {
134
            return $params['dbname'];
135 4
        }
136 3
137
        throw new \InvalidArgumentException('Connection does not contain a \'path\' or \'dbname\' parameter.');
138
    }
139 1
140
    private function writeMissingForceOutput(OutputInterface $output, string $dbName, string $connectionName): void
141
    {
142 1
        $output->writeln(
143
            '<error>ATTENTION:</error> This operation should not be executed in a production environment.'
144 1
        );
145 1
        $output->writeln('');
146
        $output->writeln(
147 1
            sprintf(
148 1
                '<info>Would drop the database <comment>%s</comment> for connection'
149 1
                    .' named <comment>%s</comment>.</info>',
150
                $dbName,
151 1
                $connectionName
152 1
            )
153 1
        );
154
        $output->writeln('Please run the operation with --force to execute');
155
        $output->writeln('<error>All data will be lost!</error>');
156 1
    }
157 1
158 1
    private function dropDatabase(
159
        OutputInterface $output,
160 4
        string $connectionName,
161
        Connection $connection,
162
        string $dbName,
163
        bool $shouldDropDatabase
164
    ): int {
165
        try {
166
            if ($shouldDropDatabase) {
167
                $connection->getSchemaManager()->dropDatabase($dbName);
168 4
                $output->writeln(
169 3
                    sprintf(
170 2
                        '<info>Dropped database <comment>%s</comment> for connection'
171 2
                            .' named <comment>%s</comment>.</info>',
172
                        $dbName,
173 2
                        $connectionName
174 2
                    )
175 2
                );
176
            } else {
177
                $output->writeln(
178
                    sprintf(
179 1
                        '<info>Database <comment>%s</comment> for connection named <comment>%s</comment>'
180 1
                            .' doesn\'t exist. Skipped.</info>',
181
                        $dbName,
182 1
                        $connectionName
183 1
                    )
184 3
                );
185
            }
186
        } catch (\Exception $exception) {
187
            $output->writeln(
188 1
                sprintf(
189 1
                    '<error>Could not drop database <comment>%s</comment> for connection'
190 1
                        .' named <comment>%s</comment>.</error>',
191
                    $dbName,
192 1
                    $connectionName
193 1
                )
194 1
            );
195
            $output->writeln(sprintf('<error>%s</error>', $exception->getMessage()));
196
197 1
            return self::RETURN_CODE_NOT_DROP;
198
        }
199 1
200
        return 0;
201
    }
202
}
203