ReservedWordsCommand.php 5.95 KB
Newer Older
1 2 3 4
<?php

namespace Doctrine\DBAL\Tools\Console\Command;

5
use Doctrine\DBAL\Connection;
6 7 8 9 10 11 12 13
use Doctrine\DBAL\Platforms\Keywords\DB2Keywords;
use Doctrine\DBAL\Platforms\Keywords\MySQL57Keywords;
use Doctrine\DBAL\Platforms\Keywords\MySQL80Keywords;
use Doctrine\DBAL\Platforms\Keywords\MySQLKeywords;
use Doctrine\DBAL\Platforms\Keywords\OracleKeywords;
use Doctrine\DBAL\Platforms\Keywords\PostgreSQL91Keywords;
use Doctrine\DBAL\Platforms\Keywords\PostgreSQL92Keywords;
use Doctrine\DBAL\Platforms\Keywords\PostgreSQLKeywords;
14
use Doctrine\DBAL\Platforms\Keywords\ReservedKeywordsValidator;
15 16 17 18 19 20 21 22 23
use Doctrine\DBAL\Platforms\Keywords\SQLAnywhere11Keywords;
use Doctrine\DBAL\Platforms\Keywords\SQLAnywhere12Keywords;
use Doctrine\DBAL\Platforms\Keywords\SQLAnywhere16Keywords;
use Doctrine\DBAL\Platforms\Keywords\SQLAnywhereKeywords;
use Doctrine\DBAL\Platforms\Keywords\SQLiteKeywords;
use Doctrine\DBAL\Platforms\Keywords\SQLServer2005Keywords;
use Doctrine\DBAL\Platforms\Keywords\SQLServer2008Keywords;
use Doctrine\DBAL\Platforms\Keywords\SQLServer2012Keywords;
use Doctrine\DBAL\Platforms\Keywords\SQLServerKeywords;
24
use InvalidArgumentException;
Benjamin Morel's avatar
Benjamin Morel committed
25 26
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
27
use Symfony\Component\Console\Input\InputOption;
Benjamin Morel's avatar
Benjamin Morel committed
28
use Symfony\Component\Console\Output\OutputInterface;
29 30 31
use function array_keys;
use function count;
use function implode;
32 33 34

class ReservedWordsCommand extends Command
{
35
    /** @var string[] */
36
    private $keywordListClasses = [
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
        'mysql'         => MySQLKeywords::class,
        'mysql57'       => MySQL57Keywords::class,
        'mysql80'       => MySQL80Keywords::class,
        'sqlserver'     => SQLServerKeywords::class,
        'sqlserver2005' => SQLServer2005Keywords::class,
        'sqlserver2008' => SQLServer2008Keywords::class,
        'sqlserver2012' => SQLServer2012Keywords::class,
        'sqlite'        => SQLiteKeywords::class,
        'pgsql'         => PostgreSQLKeywords::class,
        'pgsql91'       => PostgreSQL91Keywords::class,
        'pgsql92'       => PostgreSQL92Keywords::class,
        'oracle'        => OracleKeywords::class,
        'db2'           => DB2Keywords::class,
        'sqlanywhere'   => SQLAnywhereKeywords::class,
        'sqlanywhere11' => SQLAnywhere11Keywords::class,
        'sqlanywhere12' => SQLAnywhere12Keywords::class,
        'sqlanywhere16' => SQLAnywhere16Keywords::class,
54
    ];
55

56
    /**
Benjamin Morel's avatar
Benjamin Morel committed
57
     * If you want to add or replace a keywords list use this command.
58
     *
59
     * @param string $name
60
     * @param string $class
Benjamin Morel's avatar
Benjamin Morel committed
61 62
     *
     * @return void
63 64 65 66 67
     */
    public function setKeywordListClass($name, $class)
    {
        $this->keywordListClasses[$name] = $class;
    }
68

69
    /**
Benjamin Morel's avatar
Benjamin Morel committed
70
     * {@inheritdoc}
71 72 73 74 75 76
     */
    protected function configure()
    {
        $this
        ->setName('dbal:reserved-words')
        ->setDescription('Checks if the current database contains identifiers that are reserved.')
77 78 79 80 81 82
        ->setDefinition([new InputOption(
            'list',
            'l',
            InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY,
            'Keyword-List name.'
        ),
83
        ])
84 85 86 87
        ->setHelp(<<<EOT
Checks if the current database contains tables and columns
with names that are identifiers in this dialect or in other SQL dialects.

88 89
By default SQLite, MySQL, PostgreSQL, Microsoft SQL Server, Oracle
and SQL Anywhere keywords are checked:
90

91
    <info>%command.full_name%</info>
92

93 94 95
If you want to check against specific dialects you can
pass them to the command:

96
    <info>%command.full_name% -l mysql -l pgsql</info>
97

98 99 100
The following keyword lists are currently shipped with Doctrine:

    * mysql
101
    * mysql57
102
    * mysql80
103
    * pgsql
104
    * pgsql92
105 106
    * sqlite
    * oracle
107
    * sqlserver
108 109 110
    * sqlserver2005
    * sqlserver2008
    * sqlserver2012
111 112 113
    * sqlanywhere
    * sqlanywhere11
    * sqlanywhere12
114
    * sqlanywhere16
115 116 117 118
    * db2 (Not checked by default)
EOT
        );
    }
119

120
    /**
Benjamin Morel's avatar
Benjamin Morel committed
121
     * {@inheritdoc}
122 123 124
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {
125
        /** @var Connection $conn */
126
        $conn = $this->getHelper('db')->getConnection();
127

128
        $keywordLists = (array) $input->getOption('list');
129
        if (! $keywordLists) {
130
            $keywordLists = [
131
                'mysql',
132
                'mysql57',
133
                'mysql80',
134
                'pgsql',
135
                'pgsql92',
136 137 138 139 140
                'sqlite',
                'oracle',
                'sqlserver',
                'sqlserver2005',
                'sqlserver2008',
141 142 143
                'sqlserver2012',
                'sqlanywhere',
                'sqlanywhere11',
144
                'sqlanywhere12',
145
                'sqlanywhere16',
146
            ];
147
        }
148

149
        $keywords = [];
150
        foreach ($keywordLists as $keywordList) {
151 152 153 154
            if (! isset($this->keywordListClasses[$keywordList])) {
                throw new InvalidArgumentException(
                    "There exists no keyword list with name '" . $keywordList . "'. " .
                    'Known lists: ' . implode(', ', array_keys($this->keywordListClasses))
155 156
                );
            }
157 158
            $class      = $this->keywordListClasses[$keywordList];
            $keywords[] = new $class();
159
        }
160

161
        $output->write('Checking keyword violations for <comment>' . implode(', ', $keywordLists) . '</comment>...', true);
162

163
        $schema  = $conn->getSchemaManager()->createSchema();
164 165
        $visitor = new ReservedKeywordsValidator($keywords);
        $schema->visit($visitor);
166

167
        $violations = $visitor->getViolations();
168
        if (count($violations) !== 0) {
169
            $output->write('There are <error>' . count($violations) . '</error> reserved keyword violations in your database schema:', true);
170
            foreach ($violations as $violation) {
171 172
                $output->write('  - ' . $violation, true);
            }
173 174

            return 1;
175
        }
176

177 178
        $output->write('No reserved keywords violations have been found!', true);

179
        return 0;
180 181
    }
}