Completed
Branch master (2fc422)
by Dominik
02:37 queued 31s
created

CreateDatabaseDoctrineCommand::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 4
cts 4
cp 1
rs 10
c 0
b 0
f 0
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/CreateDatabaseDoctrineCommand.php
17
 */
18
final class CreateDatabaseDoctrineCommand extends Command
19
{
20
    /**
21
     * @var ConnectionRegistry
22
     */
23
    private $connectionRegistry;
24
25
    /**
26
     * @param ConnectionRegistry $connectionRegistry
27
     */
28 3
    public function __construct(ConnectionRegistry $connectionRegistry)
29
    {
30 3
        parent::__construct();
31
32 3
        $this->connectionRegistry = $connectionRegistry;
33 3
    }
34
35 3
    protected function configure()
36
    {
37
        $this
38 3
            ->setName('dbal:database:create')
39 3
            ->setDescription('Creates the configured database')
40 3
            ->addOption('shard', null, InputOption::VALUE_REQUIRED, 'The shard connection to use for this command')
41 3
            ->addOption('connection', null, InputOption::VALUE_OPTIONAL, 'The connection to use for this command')
42 3
            ->addOption(
43 3
                'if-not-exists',
44 3
                null,
45 3
                InputOption::VALUE_NONE,
46 3
                'Don\'t trigger an error, when the database already exists'
47
            )
48 3
            ->setHelp(<<<EOT
49 3
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 3
    }
59
60
    /**
61
     * @param InputInterface  $input
62
     * @param OutputInterface $output
63
     *
64
     * @return int
65
     */
66 3
    protected function execute(InputInterface $input, OutputInterface $output): int
67
    {
68 3
        $connectionName = $this->getConnectionName($input);
69
70 3
        $connection = $this->connectionRegistry->getConnection($connectionName);
71
72 3
        $ifNotExists = $input->getOption('if-not-exists');
73
74 3
        $params = $this->getParams($connection);
75
76 3
        $shard = (int) $input->getOption('shard');
77
78
        // Cannot inject `shard` option in parent::getDoctrineConnection
79
        // cause it will try to connect to a non-existing database
80 3
        $params = $this->fixShardInformation($params, $shard);
81
82 3
        $hasPath = isset($params['path']);
83
84 3
        $name = $hasPath ? $params['path'] : (isset($params['dbname']) ? $params['dbname'] : false);
85 3
        if (!$name) {
86 1
            throw new \InvalidArgumentException(
87 1
                'Connection does not contain a \'path\' or \'dbname\' parameter and cannot be dropped.'
88
            );
89
        }
90
91
        // Need to get rid of _every_ occurrence of dbname from connection configuration
92
        // and we have already extracted all relevant info from url
93 2
        unset($params['dbname'], $params['path'], $params['url']);
94
95 2
        $tmpConnection = DriverManager::getConnection($params);
96 2
        $tmpConnection->connect($shard);
0 ignored issues
show
Unused Code introduced by
The call to Connection::connect() has too many arguments starting with $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...
97 2
        $shouldNotCreateDatabase = $ifNotExists && in_array($name, $tmpConnection->getSchemaManager()->listDatabases());
98
99
        // Only quote if we don't have a path
100 2
        if (!$hasPath) {
101
            $name = $tmpConnection->getDatabasePlatform()->quoteSingleIdentifier($name);
102
        }
103
104 2
        $error = false;
105
        try {
106 2
            if ($shouldNotCreateDatabase) {
107
                $output->writeln(
108
                    sprintf(
109
                        '<info>Database <comment>%s</comment> for connection named <comment>%s</comment>'
110
                            .' already exists. Skipped.</info>',
111
                        $name,
112
                        $connectionName
113
                    )
114
                );
115
            } else {
116 2
                $tmpConnection->getSchemaManager()->createDatabase($name);
117 2
                $output->writeln(
118 2
                    sprintf(
119
                        '<info>Created database <comment>%s</comment>'
120 2
                            .' for connection named <comment>%s</comment></info>',
121 2
                        $name,
122 2
                        $connectionName
123
                    )
124
                );
125
            }
126
        } catch (\Exception $e) {
127
            $output->writeln(
128
                sprintf(
129
                    '<error>Could not create database <comment>%s</comment>'
130
                        .' for connection named <comment>%s</comment></error>',
131
                    $name,
132
                    $connectionName
133
                )
134
            );
135
            $output->writeln(sprintf('<error>%s</error>', $e->getMessage()));
136
            $error = true;
137
        }
138
139 2
        $tmpConnection->close();
140
141 2
        return $error ? 1 : 0;
142
    }
143
144
    /**
145
     * @param InputInterface $input
146
     *
147
     * @return string
148
     */
149 3 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...
150
    {
151 3
        $connectionName = $input->getOption('connection');
152
153 3
        if (null !== $connectionName) {
154 1
            return $connectionName;
155
        }
156
157 2
        return $this->connectionRegistry->getDefaultConnectionName();
158
    }
159
160
    /**
161
     * @param Connection $connection
162
     *
163
     * @return array
164
     */
165 3 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...
166
    {
167 3
        $params = $connection->getParams();
168 3
        if (isset($params['master'])) {
169 1
            $params = $params['master'];
170
        }
171
172 3
        return $params;
173
    }
174
175
    /**
176
     * @param array $params
177
     * @param int   $shard
0 ignored issues
show
Bug introduced by
There is no parameter named $shard. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
178
     *
179
     * @return array
180
     */
181 3
    private function fixShardInformation(array $params, int $shardId): array
182
    {
183 3
        if (isset($params['shards'])) {
184 1
            $shards = $params['shards'];
185
            // Default select global
186 1
            $params = array_merge($params, $params['global']);
187 1
            unset($params['global']['dbname']);
188 1
            if ($shardId) {
189 1
                foreach ($shards as $i => $shard) {
190 1
                    if ($shard['id'] === $shardId) {
191
                        // Select sharded database
192 1
                        $params = array_merge($params, $shard);
193 1
                        unset($params['shards'][$i]['dbname'], $params['id']);
194 1
                        break;
195
                    }
196
                }
197
            }
198
        }
199
200 3
        return $params;
201
    }
202
}
203