Completed
Pull Request — 2.11.x (#3956)
by David
14:33
created

ReservedWordsCommand::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 9
ccs 0
cts 8
cp 0
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 6
1
<?php
2
3
namespace Doctrine\DBAL\Tools\Console\Command;
4
5
use Doctrine\DBAL\Connection;
6
use Doctrine\DBAL\Platforms\Keywords\DB2Keywords;
7
use Doctrine\DBAL\Platforms\Keywords\MySQL57Keywords;
8
use Doctrine\DBAL\Platforms\Keywords\MySQL80Keywords;
9
use Doctrine\DBAL\Platforms\Keywords\MySQLKeywords;
10
use Doctrine\DBAL\Platforms\Keywords\OracleKeywords;
11
use Doctrine\DBAL\Platforms\Keywords\PostgreSQL91Keywords;
12
use Doctrine\DBAL\Platforms\Keywords\PostgreSQL92Keywords;
13
use Doctrine\DBAL\Platforms\Keywords\PostgreSQLKeywords;
14
use Doctrine\DBAL\Platforms\Keywords\ReservedKeywordsValidator;
15
use Doctrine\DBAL\Platforms\Keywords\SQLAnywhere11Keywords;
16
use Doctrine\DBAL\Platforms\Keywords\SQLAnywhere12Keywords;
17
use Doctrine\DBAL\Platforms\Keywords\SQLAnywhere16Keywords;
18
use Doctrine\DBAL\Platforms\Keywords\SQLAnywhereKeywords;
19
use Doctrine\DBAL\Platforms\Keywords\SQLiteKeywords;
20
use Doctrine\DBAL\Platforms\Keywords\SQLServer2005Keywords;
21
use Doctrine\DBAL\Platforms\Keywords\SQLServer2008Keywords;
22
use Doctrine\DBAL\Platforms\Keywords\SQLServer2012Keywords;
23
use Doctrine\DBAL\Platforms\Keywords\SQLServerKeywords;
24
use Doctrine\DBAL\Tools\Console\ConnectionProvider;
25
use Exception;
26
use InvalidArgumentException;
27
use Symfony\Component\Console\Command\Command;
28
use Symfony\Component\Console\Input\InputInterface;
29
use Symfony\Component\Console\Input\InputOption;
30
use Symfony\Component\Console\Output\OutputInterface;
31
use const E_USER_DEPRECATED;
32
use function array_keys;
33
use function count;
34
use function implode;
35
use function trigger_error;
36
37
class ReservedWordsCommand extends Command
38
{
39
    /** @var string[] */
40
    private $keywordListClasses = [
41
        'mysql'         => MySQLKeywords::class,
42
        'mysql57'       => MySQL57Keywords::class,
43
        'mysql80'       => MySQL80Keywords::class,
44
        'sqlserver'     => SQLServerKeywords::class,
45
        'sqlserver2005' => SQLServer2005Keywords::class,
46
        'sqlserver2008' => SQLServer2008Keywords::class,
47
        'sqlserver2012' => SQLServer2012Keywords::class,
48
        'sqlite'        => SQLiteKeywords::class,
49
        'pgsql'         => PostgreSQLKeywords::class,
50
        'pgsql91'       => PostgreSQL91Keywords::class,
51
        'pgsql92'       => PostgreSQL92Keywords::class,
52
        'oracle'        => OracleKeywords::class,
53
        'db2'           => DB2Keywords::class,
54
        'sqlanywhere'   => SQLAnywhereKeywords::class,
55
        'sqlanywhere11' => SQLAnywhere11Keywords::class,
56
        'sqlanywhere12' => SQLAnywhere12Keywords::class,
57
        'sqlanywhere16' => SQLAnywhere16Keywords::class,
58
    ];
59
60
    /** @var ConnectionProvider|null */
61
    private $connectionProvider;
62
63
    public function __construct(?ConnectionProvider $connectionProvider = null)
64
    {
65
        parent::__construct();
66
        $this->connectionProvider = $connectionProvider;
67
        if ($connectionProvider !== null) {
68
            return;
69
        }
70
71
        @trigger_error('Not passing a connection provider as the first constructor argument is deprecated', E_USER_DEPRECATED);
72
    }
73
74
    /**
75
     * If you want to add or replace a keywords list use this command.
76
     *
77
     * @param string $name
78
     * @param string $class
79
     *
80
     * @return void
81
     */
82
    public function setKeywordListClass($name, $class)
83
    {
84
        $this->keywordListClasses[$name] = $class;
85
    }
86
87
    /** @return void */
88
    protected function configure()
89
    {
90
        $this
91
        ->setName('dbal:reserved-words')
92
        ->setDescription('Checks if the current database contains identifiers that are reserved.')
93
        ->setDefinition([
94
            new InputOption('connection', null, InputOption::VALUE_REQUIRED, 'The named database connection'),
95
            new InputOption(
96
                'list',
97
                'l',
98
                InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY,
99
                'Keyword-List name.'
100
            ),
101
        ])
102
        ->setHelp(<<<EOT
103
Checks if the current database contains tables and columns
104
with names that are identifiers in this dialect or in other SQL dialects.
105
106
By default SQLite, MySQL, PostgreSQL, Microsoft SQL Server, Oracle
107
and SQL Anywhere keywords are checked:
108
109
    <info>%command.full_name%</info>
110
111
If you want to check against specific dialects you can
112
pass them to the command:
113
114
    <info>%command.full_name% -l mysql -l pgsql</info>
115
116
The following keyword lists are currently shipped with Doctrine:
117
118
    * mysql
119
    * mysql57
120
    * mysql80
121
    * pgsql
122
    * pgsql92
123
    * sqlite
124
    * oracle
125
    * sqlserver
126
    * sqlserver2005
127
    * sqlserver2008
128
    * sqlserver2012
129
    * sqlanywhere
130
    * sqlanywhere11
131
    * sqlanywhere12
132
    * sqlanywhere16
133
    * db2 (Not checked by default)
134
EOT
135
        );
136
    }
137
138
    /**
139
     * {@inheritdoc}
140
     */
141
    protected function execute(InputInterface $input, OutputInterface $output)
142
    {
143
        $conn = $this->getConnection($input);
144
145
        $keywordLists = (array) $input->getOption('list');
146
        if (! $keywordLists) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $keywordLists of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
147
            $keywordLists = [
148
                'mysql',
149
                'mysql57',
150
                'mysql80',
151
                'pgsql',
152
                'pgsql92',
153
                'sqlite',
154
                'oracle',
155
                'sqlserver',
156
                'sqlserver2005',
157
                'sqlserver2008',
158
                'sqlserver2012',
159
                'sqlanywhere',
160
                'sqlanywhere11',
161
                'sqlanywhere12',
162
                'sqlanywhere16',
163
            ];
164
        }
165
166
        $keywords = [];
167
        foreach ($keywordLists as $keywordList) {
168
            if (! isset($this->keywordListClasses[$keywordList])) {
169
                throw new InvalidArgumentException(
170
                    "There exists no keyword list with name '" . $keywordList . "'. " .
171
                    'Known lists: ' . implode(', ', array_keys($this->keywordListClasses))
172
                );
173
            }
174
            $class      = $this->keywordListClasses[$keywordList];
175
            $keywords[] = new $class();
176
        }
177
178
        $output->write('Checking keyword violations for <comment>' . implode(', ', $keywordLists) . '</comment>...', true);
179
180
        $schema  = $conn->getSchemaManager()->createSchema();
181
        $visitor = new ReservedKeywordsValidator($keywords);
182
        $schema->visit($visitor);
183
184
        $violations = $visitor->getViolations();
185
        if (count($violations) !== 0) {
186
            $output->write('There are <error>' . count($violations) . '</error> reserved keyword violations in your database schema:', true);
187
            foreach ($violations as $violation) {
188
                $output->write('  - ' . $violation, true);
189
            }
190
191
            return 1;
192
        }
193
194
        $output->write('No reserved keywords violations have been found!', true);
195
196
        return 0;
197
    }
198
199
    private function getConnection(InputInterface $input) : Connection
200
    {
201
        /** @var string|null $connectionName */
202
        $connectionName = $input->getOption('connection');
203
204
        if ($this->connectionProvider === null) {
205
            if ($connectionName !== null) {
206
                throw new Exception('Specifying a connection is only supported when a ConnectionProvider is used.');
207
            }
208
209
            return $this->getHelper('db')->getConnection();
210
        }
211
212
        if ($connectionName !== null) {
213
            return $this->connectionProvider->getConnection($connectionName);
214
        }
215
216
        return $this->connectionProvider->getDefaultConnection();
217
    }
218
}
219