Passed
Branch master (7599e2)
by Sébastien
12:18 queued 06:01
created

DatabaseCommand   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 129
Duplicated Lines 0 %

Test Coverage

Coverage 55%

Importance

Changes 0
Metric Value
wmc 11
eloc 38
dl 0
loc 129
ccs 22
cts 40
cp 0.55
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A configure() 0 5 1
B execute() 0 40 6
A prepareConnectionConfig() 0 14 3
1
<?php
2
3
namespace Bdf\Prime\Console;
4
5
use Bdf\Prime\Connection\ConnectionInterface;
6
use Bdf\Prime\Connection\ConnectionRegistry;
7
use Bdf\Prime\Connection\Factory\ChainFactory;
8
use Bdf\Prime\Connection\Factory\ConnectionFactory;
9
use Bdf\Prime\Connection\Factory\ConnectionFactoryInterface;
10
use Bdf\Prime\Connection\Factory\MasterSlaveConnectionFactory;
11
use Bdf\Prime\Connection\Factory\ShardingConnectionFactory;
12
use Bdf\Prime\ConnectionManager;
13
use Bdf\Prime\ConnectionRegistryInterface;
14
use Bdf\Prime\Exception\PrimeException;
15
use Bdf\Prime\ServiceLocator;
16
use Bdf\Util\Console\BdfStyle;
17
use Doctrine\DBAL\Connection as DoctrineConnection;
18
use Symfony\Component\Console\Command\Command;
19
use Symfony\Component\Console\Input\InputInterface;
20
use Symfony\Component\Console\Input\InputOption;
21
use Symfony\Component\Console\Output\OutputInterface;
22
23
/**
24
 * @todo manage Shard and Master/slave connection
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
25
 * @todo remonve doctrine dependency
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
26
 */
27
abstract class DatabaseCommand extends Command
28
{
29
    /**
30
     * @var ConnectionRegistryInterface
31
     */
32
    private $registry;
33
34
    /**
35
     * @var ConnectionFactoryInterface
36
     */
37
    private $connectionFactory;
38
39
    /**
40
     * @var BdfStyle
41
     */
42
    protected $io;
43
44
    /**
45
     * DatabaseCommand constructor.
46
     *
47
     * @param ConnectionRegistryInterface $registry
48
     * @param ConnectionFactoryInterface $connectionFactory
49
     */
50 1
    public function __construct(ConnectionRegistryInterface $registry, ConnectionFactoryInterface $connectionFactory = null)
51
    {
52 1
        $this->registry = $registry;
53 1
        $this->connectionFactory = $connectionFactory;
54
55 1
        parent::__construct(static::$defaultName);
56 1
    }
57
58
    /**
59
     * {@inheritdoc}
60
     */
61 1
    protected function configure()
62
    {
63 1
        $this->addOption('connection', null, InputOption::VALUE_OPTIONAL, 'Interacts only on the database from this connection');
64 1
        $this->addOption('user', 'u', InputOption::VALUE_REQUIRED, 'Set the user name.', 'root');
65 1
        $this->addOption('password', 'p', InputOption::VALUE_REQUIRED, 'Set the user password.', '');
66 1
    }
67
68
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $input should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $output should have a doc-comment as per coding-style.
Loading history...
69
     * {@inheritdoc}
70
     */
71 1
    protected function execute(InputInterface $input, OutputInterface $output): int
72
    {
73 1
        $this->io = new BdfStyle($input, $output);
74
75 1
        $name = $this->io->option('connection');
76
77 1
        $connections = $name ? [$name] : $this->registry->getConnectionNames();
0 ignored issues
show
Coding Style introduced by
The value of a comparison must not be assigned to a variable
Loading history...
Coding Style introduced by
Inline shorthand IF statement requires brackets around comparison
Loading history...
78
79 1
        foreach ($connections as $connectionName) {
80 1
            $connection = $this->registry->getConnection($connectionName);
81
82 1
            if (!$connection instanceof DoctrineConnection) {
83
                $this->io->line('Connection <comment>%s</comment> is ignored: only doctrine connection can be managed', $connectionName);
84
                continue;
85
            }
86
87 1
            $parameters = $connection->getParams();
88
89
            // Skip connections marked as "ignore" on configuration
90
            // Permit to declare SQLite connections, which do not supports database management
91 1
            if (!empty($parameters['ignore'])) {
92 1
                $this->io->line('Connection <comment>%s</comment> is ignored.', $connectionName);
93 1
                continue;
94
            }
95
96
            $dbName = $this->prepareConnectionConfig($parameters);
97
            $connectionTmp = $this->connectionFactory->create($connectionName, $parameters, $connection->getConfiguration());
98
            $schema = $connectionTmp->schema();
99
100
            if ($schema->hasDatabase($dbName)) {
101
                $this->interactWithDatabase($connectionTmp, $dbName);
102
                continue;
103
            }
104
105
            $this->interactWithNoDatabase($connectionTmp, $dbName);
106
107
            $connectionTmp->close();
0 ignored issues
show
Bug introduced by
The method close() does not exist on Bdf\Prime\Connection\ConnectionInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Bdf\Prime\Connection\ConnectionInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

107
            $connectionTmp->/** @scrutinizer ignore-call */ 
108
                            close();
Loading history...
108
        }
0 ignored issues
show
Coding Style introduced by
End comment for long condition not found; expected "//end foreach"
Loading history...
109
110 1
        return 0;
111
    }
112
113
    /**
114
     * Prepare the configuration of the connection
115
     * Change the user and remove db name.
116
     *
117
     * @param array $parameters
118
     *
119
     * @return string The db name to interact
120
     */
121
    protected function prepareConnectionConfig(&$parameters): string
0 ignored issues
show
introduced by
Type hint "array" missing for $parameters
Loading history...
122
    {
123
        $user = $this->io->option('user');
124
125
        if (!isset($parameters['user']) || $parameters['user'] !== $user) {
126
            $parameters['user'] = $user;
127
            $parameters['password'] = $this->io->option('password');
128
        }
129
130
        // Force the connection with no database to allow doctrine to connect.
131
        $dbName = $parameters['dbname'] ?? $parameters['path'];
0 ignored issues
show
Coding Style introduced by
Operation must be bracketed
Loading history...
132
        $parameters['dbname'] = $parameters['path'] = $parameters['url'] = null;
0 ignored issues
show
Coding Style introduced by
Assignments must be the first block of code on a line
Loading history...
133
134
        return $dbName;
135
    }
136
137
    /**
138
     * Interact if the database exists
139
     *
140
     * @param ConnectionInterface $connection
141
     * @param string $dbName
142
     *
143
     * @throws PrimeException
144
     */
145
    abstract protected function interactWithDatabase($connection, $dbName);
0 ignored issues
show
introduced by
Type hint "ConnectionInterface" missing for $connection
Loading history...
146
147
    /**
148
     * Interact if the database does not exist
149
     *
150
     * @param ConnectionInterface $connection
151
     * @param string $dbName
152
     *
153
     * @throws PrimeException
154
     */
155
    abstract protected function interactWithNoDatabase($connection, $dbName);
0 ignored issues
show
introduced by
Type hint "ConnectionInterface" missing for $connection
Loading history...
156
}
157