1 | <?php |
||
39 | class DiffCommand extends GenerateCommand |
||
40 | { |
||
41 | /** |
||
42 | * @var SchemaProviderInterface |
||
43 | */ |
||
44 | protected $schemaProvider; |
||
45 | |||
46 | 6 | public function __construct(SchemaProviderInterface $schemaProvider=null) |
|
51 | |||
52 | 6 | protected function configure() |
|
53 | { |
||
54 | 6 | parent::configure(); |
|
55 | |||
56 | $this |
||
57 | 6 | ->setName('migrations:diff') |
|
58 | 6 | ->setDescription('Generate a migration by comparing your current database to your mapping information.') |
|
59 | 6 | ->setHelp(<<<EOT |
|
60 | 6 | The <info>%command.name%</info> command generates a migration by comparing your current database to your mapping information: |
|
61 | |||
62 | <info>%command.full_name%</info> |
||
63 | |||
64 | You can optionally specify a <comment>--editor-cmd</comment> option to open the generated file in your favorite editor: |
||
65 | |||
66 | <info>%command.full_name% --editor-cmd=mate</info> |
||
67 | EOT |
||
68 | ) |
||
69 | 6 | ->addOption('filter-expression', null, InputOption::VALUE_OPTIONAL, 'Tables which are filtered by Regular Expression.') |
|
70 | 6 | ->addOption('formatted', null, InputOption::VALUE_NONE, 'Format the generated SQL.') |
|
71 | 6 | ->addOption('line-length', null, InputOption::VALUE_OPTIONAL, 'Max line length of unformatted lines.', 120) |
|
72 | ; |
||
73 | 6 | } |
|
74 | |||
75 | 6 | public function execute(InputInterface $input, OutputInterface $output) |
|
76 | { |
||
77 | 6 | $isDbalOld = (DbalVersion::compare('2.2.0') > 0); |
|
78 | 6 | $configuration = $this->getMigrationConfiguration($input, $output); |
|
79 | |||
80 | 6 | $conn = $configuration->getConnection(); |
|
81 | 6 | $platform = $conn->getDatabasePlatform(); |
|
82 | |||
83 | 6 | if ($filterExpr = $input->getOption('filter-expression')) { |
|
84 | if ($isDbalOld) { |
||
85 | throw new \InvalidArgumentException('The "--filter-expression" option can only be used as of Doctrine DBAL 2.2'); |
||
86 | } |
||
87 | |||
88 | $conn->getConfiguration() |
||
89 | ->setFilterSchemaAssetsExpression($filterExpr); |
||
90 | } |
||
91 | |||
92 | 6 | $fromSchema = $conn->getSchemaManager()->createSchema(); |
|
93 | 6 | $toSchema = $this->getSchemaProvider()->createSchema(); |
|
94 | |||
95 | //Not using value from options, because filters can be set from config.yml |
||
96 | 6 | if ( ! $isDbalOld && $filterExpr = $conn->getConfiguration()->getFilterSchemaAssetsExpression()) { |
|
97 | 2 | foreach ($toSchema->getTables() as $table) { |
|
98 | 2 | $tableName = $table->getName(); |
|
99 | 2 | if ( ! preg_match($filterExpr, $this->resolveTableName($tableName))) { |
|
100 | 2 | $toSchema->dropTable($tableName); |
|
101 | } |
||
102 | } |
||
103 | } |
||
104 | |||
105 | 6 | $up = $this->buildCodeFromSql( |
|
106 | 6 | $configuration, |
|
107 | 6 | $fromSchema->getMigrateToSql($toSchema, $platform), |
|
108 | 6 | $input->getOption('formatted'), |
|
109 | 6 | $input->getOption('line-length') |
|
110 | ); |
||
111 | 6 | $down = $this->buildCodeFromSql( |
|
112 | 6 | $configuration, |
|
113 | 6 | $fromSchema->getMigrateFromSql($toSchema, $platform), |
|
114 | 6 | $input->getOption('formatted'), |
|
115 | 6 | $input->getOption('line-length') |
|
116 | ); |
||
117 | |||
118 | 6 | if (! $up && ! $down) { |
|
119 | $output->writeln('No changes detected in your mapping information.'); |
||
120 | |||
121 | return; |
||
122 | } |
||
123 | |||
124 | 6 | $version = $configuration->generateVersionNumber(); |
|
125 | 6 | $path = $this->generateMigration($configuration, $input, $version, $up, $down); |
|
126 | |||
127 | 6 | $output->writeln(sprintf('Generated new migration class to "<info>%s</info>" from schema differences.', $path)); |
|
128 | 6 | $output->writeln(file_get_contents($path)); |
|
129 | 6 | } |
|
130 | |||
131 | 6 | private function buildCodeFromSql(Configuration $configuration, array $sql, $formatted=false, $lineLength=120) |
|
132 | { |
||
133 | 6 | $currentPlatform = $configuration->getConnection()->getDatabasePlatform()->getName(); |
|
134 | 6 | $code = []; |
|
135 | 6 | foreach ($sql as $query) { |
|
136 | 6 | if (stripos($query, $configuration->getMigrationsTableName()) !== false) { |
|
137 | continue; |
||
138 | } |
||
139 | |||
140 | 6 | if ($formatted) { |
|
141 | 1 | if (!class_exists('\SqlFormatter')) { |
|
142 | throw new \InvalidArgumentException( |
||
143 | 'The "--formatted" option can only be used if the sql formatter is installed.'. |
||
144 | 'Please run "composer require jdorn/sql-formatter".' |
||
145 | ); |
||
146 | } |
||
147 | |||
148 | 1 | $maxLength = $lineLength - 18 - 8; // max - php code length - indentation |
|
149 | |||
150 | 1 | if (strlen($query) > $maxLength) { |
|
151 | 1 | $query = \SqlFormatter::format($query, false); |
|
152 | } |
||
153 | } |
||
154 | |||
155 | 6 | $code[] = sprintf("\$this->addSql(%s);", var_export($query, true)); |
|
156 | } |
||
157 | |||
158 | 6 | if (!empty($code)) { |
|
159 | 6 | array_unshift( |
|
160 | 6 | $code, |
|
161 | 6 | sprintf( |
|
162 | 6 | "\$this->abortIf(\$this->connection->getDatabasePlatform()->getName() !== %s, %s);", |
|
163 | 6 | var_export($currentPlatform, true), |
|
164 | 6 | var_export(sprintf("Migration can only be executed safely on '%s'.", $currentPlatform), true) |
|
165 | ), |
||
166 | 6 | "" |
|
167 | ); |
||
168 | } |
||
169 | |||
170 | 6 | return implode("\n", $code); |
|
171 | } |
||
172 | |||
173 | 6 | private function getSchemaProvider() |
|
174 | { |
||
175 | 6 | if (!$this->schemaProvider) { |
|
176 | 1 | $this->schemaProvider = new OrmSchemaProvider($this->getHelper('entityManager')->getEntityManager()); |
|
177 | } |
||
178 | |||
179 | 6 | return $this->schemaProvider; |
|
180 | } |
||
181 | |||
182 | /** |
||
183 | * Resolve a table name from its fully qualified name. The `$name` argument |
||
184 | * comes from Doctrine\DBAL\Schema\Table#getName which can sometimes return |
||
185 | * a namespaced name with the form `{namespace}.{tableName}`. This extracts |
||
186 | * the table name from that. |
||
187 | * |
||
188 | * @param string $name |
||
189 | * @return string |
||
190 | */ |
||
191 | 2 | private function resolveTableName($name) |
|
197 | } |
||
198 |