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

namespace Doctrine\DBAL\Tools\Console\Command;

5
use Doctrine\DBAL\Connection;
6
use Doctrine\DBAL\Platforms\Keywords\DB2Keywords;
7
use Doctrine\DBAL\Platforms\Keywords\MariaDb102Keywords;
8 9 10 11
use Doctrine\DBAL\Platforms\Keywords\MySQL57Keywords;
use Doctrine\DBAL\Platforms\Keywords\MySQL80Keywords;
use Doctrine\DBAL\Platforms\Keywords\MySQLKeywords;
use Doctrine\DBAL\Platforms\Keywords\OracleKeywords;
12
use Doctrine\DBAL\Platforms\Keywords\PostgreSQL100Keywords;
13
use Doctrine\DBAL\Platforms\Keywords\PostgreSQL94Keywords;
14
use Doctrine\DBAL\Platforms\Keywords\ReservedKeywordsValidator;
15 16
use Doctrine\DBAL\Platforms\Keywords\SQLAnywhereKeywords;
use Doctrine\DBAL\Platforms\Keywords\SQLiteKeywords;
17
use Doctrine\DBAL\Platforms\Keywords\SQLServer2012Keywords;
18
use InvalidArgumentException;
Benjamin Morel's avatar
Benjamin Morel committed
19 20
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
21
use Symfony\Component\Console\Input\InputOption;
Benjamin Morel's avatar
Benjamin Morel committed
22
use Symfony\Component\Console\Output\OutputInterface;
23
use function array_keys;
Grégoire Paris's avatar
Grégoire Paris committed
24
use function assert;
25 26
use function count;
use function implode;
27 28 29

class ReservedWordsCommand extends Command
{
30
    /** @var string[] */
31
    private $keywordListClasses = [
32
        'db2'           => DB2Keywords::class,
33 34 35
        'mysql'         => MySQLKeywords::class,
        'mysql57'       => MySQL57Keywords::class,
        'mysql80'       => MySQL80Keywords::class,
36
        'mariadb102'    => MariaDb102Keywords::class,
37
        'oracle'        => OracleKeywords::class,
38
        'pgsql'         => PostgreSQL94Keywords::class,
39
        'pgsql100'      => PostgreSQL100Keywords::class,
40
        'sqlanywhere'   => SQLAnywhereKeywords::class,
41
        'sqlite'        => SQLiteKeywords::class,
42
        'sqlserver'     => SQLServer2012Keywords::class,
43
    ];
44

45
    /**
Benjamin Morel's avatar
Benjamin Morel committed
46
     * If you want to add or replace a keywords list use this command.
47
     *
48
     * @param string $name
49
     * @param string $class
Benjamin Morel's avatar
Benjamin Morel committed
50 51
     *
     * @return void
52 53 54 55 56
     */
    public function setKeywordListClass($name, $class)
    {
        $this->keywordListClasses[$name] = $class;
    }
57

58
    /** @return void */
59 60 61 62 63
    protected function configure()
    {
        $this
        ->setName('dbal:reserved-words')
        ->setDescription('Checks if the current database contains identifiers that are reserved.')
64 65 66 67 68 69
        ->setDefinition([new InputOption(
            'list',
            'l',
            InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY,
            'Keyword-List name.'
        ),
70
        ])
71 72 73 74
        ->setHelp(<<<EOT
Checks if the current database contains tables and columns
with names that are identifiers in this dialect or in other SQL dialects.

75 76
By default SQLite, MySQL, PostgreSQL, Microsoft SQL Server, Oracle
and SQL Anywhere keywords are checked:
77

78
    <info>%command.full_name%</info>
79

80 81 82
If you want to check against specific dialects you can
pass them to the command:

83
    <info>%command.full_name% -l mysql -l pgsql</info>
84

85 86 87
The following keyword lists are currently shipped with Doctrine:

    * mysql
88
    * mysql57
89
    * mysql80
90
    * mariadb102
91
    * pgsql
92
    * pgsql100
93 94
    * sqlite
    * oracle
95
    * sqlserver
96
    * sqlserver2012
97
    * sqlanywhere
98 99 100 101
    * db2 (Not checked by default)
EOT
        );
    }
102

103
    /**
Benjamin Morel's avatar
Benjamin Morel committed
104
     * {@inheritdoc}
105 106 107 108
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $conn = $this->getHelper('db')->getConnection();
Grégoire Paris's avatar
Grégoire Paris committed
109
        assert($conn instanceof Connection);
110

111
        $keywordLists = (array) $input->getOption('list');
112
        if (count($keywordLists) === 0) {
113
            $keywordLists = array_keys($this->keywordListClasses);
114
        }
115

116
        $keywords = [];
117
        foreach ($keywordLists as $keywordList) {
118 119 120 121
            if (! isset($this->keywordListClasses[$keywordList])) {
                throw new InvalidArgumentException(
                    "There exists no keyword list with name '" . $keywordList . "'. " .
                    'Known lists: ' . implode(', ', array_keys($this->keywordListClasses))
122 123
                );
            }
Grégoire Paris's avatar
Grégoire Paris committed
124

125 126
            $class      = $this->keywordListClasses[$keywordList];
            $keywords[] = new $class();
127
        }
128

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

131
        $schema  = $conn->getSchemaManager()->createSchema();
132 133
        $visitor = new ReservedKeywordsValidator($keywords);
        $schema->visit($visitor);
134

135
        $violations = $visitor->getViolations();
136
        if (count($violations) !== 0) {
137
            $output->write('There are <error>' . count($violations) . '</error> reserved keyword violations in your database schema:', true);
138
            foreach ($violations as $violation) {
139 140
                $output->write('  - ' . $violation, true);
            }
141 142

            return 1;
143
        }
144

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

147
        return 0;
148 149
    }
}