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

CreateDatabaseDoctrineCommand::execute()   C

Complexity

Conditions 9
Paths 164

Size

Total Lines 75

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 0
Metric Value
dl 0
loc 75
ccs 0
cts 58
cp 0
rs 6.5632
c 0
b 0
f 0
cc 9
nc 164
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\DriverManager;
9
use Symfony\Component\Console\Command\Command;
10
use Symfony\Component\Console\Input\InputInterface;
11
use Symfony\Component\Console\Input\InputOption;
12
use Symfony\Component\Console\Output\OutputInterface;
13
use Doctrine\DBAL\Connection;
14
15
/**
16
 * @see https://github.com/doctrine/DoctrineBundle/blob/master/Command/CreateDatabaseDoctrineCommand.php
17
 */
18
class CreateDatabaseDoctrineCommand extends Command
19
{
20
    /**
21
     * @var ConnectionRegistry
22
     */
23
    private $connectionRegistry;
24
25
    /**
26
     * @param ConnectionRegistry $connectionRegistry
27
     */
28
    public function __construct(ConnectionRegistry $connectionRegistry)
29
    {
30
        parent::__construct();
31
32
        $this->connectionRegistry = $connectionRegistry;
33
    }
34
35
    protected function configure()
36
    {
37
        $this
38
            ->setName('dbal:database:create')
39
            ->setDescription('Creates the configured database')
40
            ->addOption('shard', null, InputOption::VALUE_REQUIRED, 'The shard connection to use for this command')
41
            ->addOption('connection', null, InputOption::VALUE_OPTIONAL, 'The connection to use for this command')
42
            ->addOption(
43
                'if-not-exists',
44
                null,
45
                InputOption::VALUE_NONE,
46
                'Don\'t trigger an error, when the database already exists'
47
            )
48
            ->setHelp(<<<EOT
49
The <info>%command.name%</info> command creates the default connections database:
50
51
    <info>php %command.full_name%</info>
52
53
You can also optionally specify the name of a connection to create the database for:
54
55
    <info>php %command.full_name% --connection=default</info>
56
EOT
57
            );
58
    }
59
60
    /**
61
     * @param InputInterface  $input
62
     * @param OutputInterface $output
63
     *
64
     * @return int
65
     */
66
    protected function execute(InputInterface $input, OutputInterface $output): int
67
    {
68
        $connectionName = $this->getConnectionName($input);
69
70
        $connection = $this->connectionRegistry->getConnection($connectionName);
71
72
        $ifNotExists = $input->getOption('if-not-exists');
73
74
        $params = $this->getParams($connection);
75
76
        // Cannot inject `shard` option in parent::getDoctrineConnection
77
        // cause it will try to connect to a non-existing database
78
        $params = $this->fixShardInformation($input, $params);
79
80
        $hasPath = isset($params['path']);
81
82
        $name = $hasPath ? $params['path'] : (isset($params['dbname']) ? $params['dbname'] : false);
83
        if (!$name) {
84
            throw new \InvalidArgumentException(
85
                'Connection does not contain a \'path\' or \'dbname\' parameter and cannot be dropped.'
86
            );
87
        }
88
89
        // Need to get rid of _every_ occurrence of dbname from connection configuration
90
        // and we have already extracted all relevant info from url
91
        unset($params['dbname'], $params['path'], $params['url']);
92
93
        $tmpConnection = DriverManager::getConnection($params);
94
        $tmpConnection->connect($input->getOption('shard'));
0 ignored issues
show
Unused Code introduced by
The call to Connection::connect() has too many arguments starting with $input->getOption('shard').

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
95
        $shouldNotCreateDatabase = $ifNotExists && in_array($name, $tmpConnection->getSchemaManager()->listDatabases());
96
97
        // Only quote if we don't have a path
98
        if (!$hasPath) {
99
            $name = $tmpConnection->getDatabasePlatform()->quoteSingleIdentifier($name);
100
        }
101
102
        $error = false;
103
        try {
104
            if ($shouldNotCreateDatabase) {
105
                $output->writeln(
106
                    sprintf(
107
                        '<info>Database <comment>%s</comment> for connection named <comment>%s</comment>'
108
                            .' already exists. Skipped.</info>',
109
                        $name,
110
                        $connectionName
111
                    )
112
                );
113
            } else {
114
                $tmpConnection->getSchemaManager()->createDatabase($name);
115
                $output->writeln(
116
                    sprintf(
117
                        '<info>Created database <comment>%s</comment>'
118
                            .' for connection named <comment>%s</comment></info>',
119
                        $name,
120
                        $connectionName
121
                    )
122
                );
123
            }
124
        } catch (\Exception $e) {
125
            $output->writeln(
126
                sprintf(
127
                    '<error>Could not create database <comment>%s</comment>'
128
                        .' for connection named <comment>%s</comment></error>',
129
                    $name,
130
                    $connectionName
131
                )
132
            );
133
            $output->writeln(sprintf('<error>%s</error>', $e->getMessage()));
134
            $error = true;
135
        }
136
137
        $tmpConnection->close();
138
139
        return $error ? 1 : 0;
140
    }
141
142
    /**
143
     * @param InputInterface $input
144
     *
145
     * @return string
146
     */
147 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...
148
    {
149
        $connectionName = $input->getOption('connection');
150
151
        if ('' !== $connectionName) {
152
            return $connectionName;
153
        }
154
155
        return $this->connectionRegistry->getDefaultConnectionName();
156
    }
157
158
    /**
159
     * @param Connection $connection
160
     *
161
     * @return array
162
     */
163 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...
164
    {
165
        $params = $connection->getParams();
166
        if (isset($params['master'])) {
167
            $params = $params['master'];
168
        }
169
170
        return $params;
171
    }
172
173
    /**
174
     * @param InputInterface $input
175
     * @param array          $params
176
     *
177
     * @return array
178
     */
179
    private function fixShardInformation(InputInterface $input, array $params): array
180
    {
181
        if (isset($params['shards'])) {
182
            $shards = $params['shards'];
183
            // Default select global
184
            $params = array_merge($params, $params['global']);
185
            unset($params['global']['dbname']);
186
            if ($input->getOption('shard')) {
187
                foreach ($shards as $i => $shard) {
188
                    if ($shard['id'] === (int) $input->getOption('shard')) {
189
                        // Select sharded database
190
                        $params = array_merge($params, $shard);
191
                        unset($params['shards'][$i]['dbname'], $params['id']);
192
                        break;
193
                    }
194
                }
195
            }
196
        }
197
198
        return $params;
199
    }
200
}
201