Passed
Push — master ( 52b8fa...e2a99d )
by Dominik
02:01
created

DropDatabaseDoctrineCommand::execute()   C

Complexity

Conditions 9
Paths 88

Size

Total Lines 90

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 0
Metric Value
dl 0
loc 90
ccs 0
cts 72
cp 0
rs 6.6626
c 0
b 0
f 0
cc 9
nc 88
nop 2
crap 90

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
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
    /**
30
     * @param ConnectionRegistry $connectionRegistry
31
     */
32
    public function __construct(ConnectionRegistry $connectionRegistry)
33
    {
34
        parent::__construct();
35
36
        $this->connectionRegistry = $connectionRegistry;
37
    }
38
39
    protected function configure()
40
    {
41
        $this
42
            ->setName('dbal:database:drop')
43
            ->setDescription('Drops the configured database')
44
            ->addOption('shard', null, InputOption::VALUE_REQUIRED, 'The shard connection to use for this command')
45
            ->addOption('connection', null, InputOption::VALUE_OPTIONAL, 'The connection to use for this command')
46
            ->addOption(
47
                'if-exists',
48
                null,
49
                InputOption::VALUE_NONE,
50
                'Don\'t trigger an error, when the database doesn\'t exist'
51
            )
52
            ->addOption('force', null, InputOption::VALUE_NONE, 'Set this parameter to execute this action')
53
            ->setHelp(<<<EOT
54
The <info>%command.name%</info> command drops the default connections database:
55
56
    <info>php %command.full_name%</info>
57
58
The <info>--force</info> parameter has to be used to actually drop the database.
59
60
You can also optionally specify the name of a connection to drop the database for:
61
62
    <info>php %command.full_name% --connection=default</info>
63
64
<error>Be careful: All data in a given database will be lost when executing this command.</error>
65
EOT
66
            );
67
    }
68
69
    /**
70
     * @param InputInterface  $input
71
     * @param OutputInterface $output
72
     *
73
     * @return int
74
     */
75
    protected function execute(InputInterface $input, OutputInterface $output): int
76
    {
77
        $connectionName = $this->getConnectionName($input);
78
79
        $connection = $this->connectionRegistry->getConnection($connectionName);
80
81
        $ifExists = $input->getOption('if-exists');
82
83
        $params = $this->getParams($connection);
84
85
        // Cannot inject `shard` option in parent::getDoctrineConnection
86
        // cause it will try to connect to a non-existing database
87
        $params = $this->fixShardInformation($input, $params);
88
89
        $name = isset($params['path']) ? $params['path'] : (isset($params['dbname']) ? $params['dbname'] : false);
90
        if (!$name) {
91
            throw new \InvalidArgumentException(
92
                'Connection does not contain a \'path\' or \'dbname\' parameter and cannot be dropped.'
93
            );
94
        }
95
96
        unset($params['dbname'], $params['url']);
97
98
        if (!$input->getOption('force')) {
99
            $output->writeln(
100
                '<error>ATTENTION:</error> This operation should not be executed in a production environment.'
101
            );
102
            $output->writeln('');
103
            $output->writeln(
104
                sprintf(
105
                    '<info>Would drop the database <comment>%s</comment> for connection'
106
                        .' named <comment>%s</comment>.</info>',
107
                    $name,
108
                    $connectionName
109
                )
110
            );
111
            $output->writeln('Please run the operation with --force to execute');
112
            $output->writeln('<error>All data will be lost!</error>');
113
114
            return self::RETURN_CODE_NO_FORCE;
115
        }
116
117
        // Reopen connection without database name set
118
        // as some vendors do not allow dropping the database connected to.
119
        $connection->close();
120
        $connection = DriverManager::getConnection($params);
121
        $shouldDropDatabase = !$ifExists || in_array($name, $connection->getSchemaManager()->listDatabases());
122
123
        // Only quote if we don't have a path
124
        if (!isset($params['path'])) {
125
            $name = $connection->getDatabasePlatform()->quoteSingleIdentifier($name);
126
        }
127
128
        try {
129
            if ($shouldDropDatabase) {
130
                $connection->getSchemaManager()->dropDatabase($name);
131
                $output->writeln(
132
                    sprintf(
133
                        '<info>Dropped database <comment>%s</comment> for connection'
134
                            .' named <comment>%s</comment></info>',
135
                        $name,
136
                        $connectionName
137
                    )
138
                );
139
            } else {
140
                $output->writeln(
141
                    sprintf(
142
                        '<info>Database <comment>%s</comment> for connection named <comment>%s</comment>'
143
                            .' doesn\'t exist. Skipped.</info>',
144
                        $name,
145
                        $connectionName
146
                    )
147
                );
148
            }
149
        } catch (\Exception $e) {
150
            $output->writeln(
151
                sprintf(
152
                    '<error>Could not drop database <comment>%s</comment> for connection'
153
                        .' named <comment>%s</comment></error>',
154
                    $name,
155
                    $connectionName
156
                )
157
            );
158
            $output->writeln(sprintf('<error>%s</error>', $e->getMessage()));
159
160
            return self::RETURN_CODE_NOT_DROP;
161
        }
162
163
        return 0;
164
    }
165
166
    /**
167
     * @param InputInterface $input
168
     *
169
     * @return string
170
     */
171 View Code Duplication
    private function getConnectionName(InputInterface $input): string
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
172
    {
173
        $connectionName = $input->getOption('connection');
174
175
        if ('' !== $connectionName) {
176
            return $connectionName;
177
        }
178
179
        return $this->connectionRegistry->getDefaultConnectionName();
180
    }
181
182
    /**
183
     * @param Connection $connection
184
     *
185
     * @return array
186
     */
187 View Code Duplication
    private function getParams(Connection $connection): array
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
188
    {
189
        $params = $connection->getParams();
190
        if (isset($params['master'])) {
191
            $params = $params['master'];
192
        }
193
194
        return $params;
195
    }
196
197
    /**
198
     * @param InputInterface $input
199
     * @param array          $params
200
     *
201
     * @return array
202
     */
203
    private function fixShardInformation(InputInterface $input, array $params): array
204
    {
205
        if (isset($params['shards'])) {
206
            $shards = $params['shards'];
207
            // Default select global
208
            $params = array_merge($params, $params['global']);
209
            if ($input->getOption('shard')) {
210
                foreach ($shards as $shard) {
211
                    if ($shard['id'] === (int) $input->getOption('shard')) {
212
                        // Select sharded database
213
                        $params = $shard;
214
                        unset($params['id']);
215
                        break;
216
                    }
217
                }
218
            }
219
        }
220
221
        return $params;
222
    }
223
}
224