1 | <?php |
||
2 | |||
3 | namespace Doctrine\Tests\DBAL\Functional\Schema; |
||
4 | |||
5 | use Doctrine\Common\EventManager; |
||
6 | use Doctrine\DBAL\Events; |
||
7 | use Doctrine\DBAL\Platforms\OraclePlatform; |
||
8 | use Doctrine\DBAL\Schema\Column; |
||
9 | use Doctrine\DBAL\Schema\ColumnDiff; |
||
10 | use Doctrine\DBAL\Schema\Comparator; |
||
11 | use Doctrine\DBAL\Schema\Table; |
||
12 | use Doctrine\DBAL\Schema\TableDiff; |
||
13 | use Doctrine\DBAL\Types\Type; |
||
14 | |||
15 | class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTestCase |
||
16 | { |
||
17 | /** |
||
18 | * @var \Doctrine\DBAL\Schema\AbstractSchemaManager |
||
19 | */ |
||
20 | protected $_sm; |
||
21 | |||
22 | protected function getPlatformName() |
||
23 | { |
||
24 | $class = get_class($this); |
||
25 | $e = explode('\\', $class); |
||
26 | $testClass = end($e); |
||
27 | $dbms = strtolower(str_replace('SchemaManagerTest', null, $testClass)); |
||
28 | return $dbms; |
||
29 | } |
||
30 | |||
31 | protected function setUp() |
||
32 | { |
||
33 | parent::setUp(); |
||
34 | |||
35 | $dbms = $this->getPlatformName(); |
||
36 | |||
37 | if ($this->_conn->getDatabasePlatform()->getName() !== $dbms) { |
||
38 | $this->markTestSkipped(get_class($this) . ' requires the use of ' . $dbms); |
||
39 | } |
||
40 | |||
41 | $this->_sm = $this->_conn->getSchemaManager(); |
||
42 | } |
||
43 | |||
44 | /** |
||
45 | * @group DBAL-1220 |
||
46 | */ |
||
47 | public function testDropsDatabaseWithActiveConnections() |
||
48 | { |
||
49 | if (! $this->_sm->getDatabasePlatform()->supportsCreateDropDatabase()) { |
||
50 | $this->markTestSkipped('Cannot drop Database client side with this Driver.'); |
||
51 | } |
||
52 | |||
53 | $this->_sm->dropAndCreateDatabase('test_drop_database'); |
||
54 | |||
55 | $knownDatabases = $this->_sm->listDatabases(); |
||
56 | if ($this->_conn->getDatabasePlatform() instanceof OraclePlatform) { |
||
57 | self::assertContains('TEST_DROP_DATABASE', $knownDatabases); |
||
58 | } else { |
||
59 | self::assertContains('test_drop_database', $knownDatabases); |
||
60 | } |
||
61 | |||
62 | $params = $this->_conn->getParams(); |
||
63 | if ($this->_conn->getDatabasePlatform() instanceof OraclePlatform) { |
||
64 | $params['user'] = 'test_drop_database'; |
||
65 | } else { |
||
66 | $params['dbname'] = 'test_drop_database'; |
||
67 | } |
||
68 | |||
69 | $user = $params['user'] ?? null; |
||
70 | $password = $params['password'] ?? null; |
||
71 | |||
72 | $connection = $this->_conn->getDriver()->connect($params, $user, $password); |
||
73 | |||
74 | self::assertInstanceOf('Doctrine\DBAL\Driver\Connection', $connection); |
||
75 | |||
76 | $this->_sm->dropDatabase('test_drop_database'); |
||
77 | |||
78 | self::assertNotContains('test_drop_database', $this->_sm->listDatabases()); |
||
79 | } |
||
80 | |||
81 | /** |
||
82 | * @group DBAL-195 |
||
83 | */ |
||
84 | public function testDropAndCreateSequence() |
||
85 | { |
||
86 | if ( ! $this->_conn->getDatabasePlatform()->supportsSequences()) { |
||
87 | $this->markTestSkipped($this->_conn->getDriver()->getName().' does not support sequences.'); |
||
88 | } |
||
89 | |||
90 | $name = 'dropcreate_sequences_test_seq'; |
||
91 | |||
92 | $this->_sm->dropAndCreateSequence(new \Doctrine\DBAL\Schema\Sequence($name, 20, 10)); |
||
93 | |||
94 | self::assertTrue($this->hasElementWithName($this->_sm->listSequences(), $name)); |
||
95 | } |
||
96 | |||
97 | private function hasElementWithName(array $items, string $name) : bool |
||
98 | { |
||
99 | $filteredList = array_filter( |
||
100 | $items, |
||
101 | function (\Doctrine\DBAL\Schema\AbstractAsset $item) use ($name) : bool { |
||
102 | return $item->getShortestName($item->getNamespaceName()) === $name; |
||
103 | } |
||
104 | ); |
||
105 | |||
106 | return count($filteredList) === 1; |
||
107 | } |
||
108 | |||
109 | public function testListSequences() |
||
110 | { |
||
111 | if(!$this->_conn->getDatabasePlatform()->supportsSequences()) { |
||
112 | $this->markTestSkipped($this->_conn->getDriver()->getName().' does not support sequences.'); |
||
113 | } |
||
114 | |||
115 | $sequence = new \Doctrine\DBAL\Schema\Sequence('list_sequences_test_seq', 20, 10); |
||
116 | $this->_sm->createSequence($sequence); |
||
117 | |||
118 | $sequences = $this->_sm->listSequences(); |
||
119 | |||
120 | self::assertInternalType('array', $sequences, 'listSequences() should return an array.'); |
||
121 | |||
122 | $foundSequence = null; |
||
123 | foreach($sequences as $sequence) { |
||
124 | self::assertInstanceOf('Doctrine\DBAL\Schema\Sequence', $sequence, 'Array elements of listSequences() should be Sequence instances.'); |
||
125 | if(strtolower($sequence->getName()) == 'list_sequences_test_seq') { |
||
126 | $foundSequence = $sequence; |
||
127 | } |
||
128 | } |
||
129 | |||
130 | self::assertNotNull($foundSequence, "Sequence with name 'list_sequences_test_seq' was not found."); |
||
131 | self::assertEquals(20, $foundSequence->getAllocationSize(), "Allocation Size is expected to be 20."); |
||
132 | self::assertEquals(10, $foundSequence->getInitialValue(), "Initial Value is expected to be 10."); |
||
133 | } |
||
134 | |||
135 | public function testListDatabases() |
||
136 | { |
||
137 | if (!$this->_sm->getDatabasePlatform()->supportsCreateDropDatabase()) { |
||
138 | $this->markTestSkipped('Cannot drop Database client side with this Driver.'); |
||
139 | } |
||
140 | |||
141 | $this->_sm->dropAndCreateDatabase('test_create_database'); |
||
142 | $databases = $this->_sm->listDatabases(); |
||
143 | |||
144 | $databases = array_map('strtolower', $databases); |
||
145 | |||
146 | self::assertContains('test_create_database', $databases); |
||
147 | } |
||
148 | |||
149 | /** |
||
150 | * @group DBAL-1058 |
||
151 | */ |
||
152 | public function testListNamespaceNames() |
||
153 | { |
||
154 | if (!$this->_sm->getDatabasePlatform()->supportsSchemas()) { |
||
155 | $this->markTestSkipped('Platform does not support schemas.'); |
||
156 | } |
||
157 | |||
158 | // Currently dropping schemas is not supported, so we have to workaround here. |
||
159 | $namespaces = $this->_sm->listNamespaceNames(); |
||
160 | $namespaces = array_map('strtolower', $namespaces); |
||
161 | |||
162 | if (!in_array('test_create_schema', $namespaces)) { |
||
163 | $this->_conn->executeUpdate($this->_sm->getDatabasePlatform()->getCreateSchemaSQL('test_create_schema')); |
||
164 | |||
165 | $namespaces = $this->_sm->listNamespaceNames(); |
||
166 | $namespaces = array_map('strtolower', $namespaces); |
||
167 | } |
||
168 | |||
169 | self::assertContains('test_create_schema', $namespaces); |
||
170 | } |
||
171 | |||
172 | public function testListTables() |
||
173 | { |
||
174 | $this->createTestTable('list_tables_test'); |
||
175 | $tables = $this->_sm->listTables(); |
||
176 | |||
177 | self::assertInternalType('array', $tables); |
||
178 | self::assertTrue(count($tables) > 0, "List Tables has to find at least one table named 'list_tables_test'."); |
||
179 | |||
180 | $foundTable = false; |
||
181 | foreach ($tables as $table) { |
||
182 | self::assertInstanceOf('Doctrine\DBAL\Schema\Table', $table); |
||
183 | if (strtolower($table->getName()) == 'list_tables_test') { |
||
184 | $foundTable = true; |
||
185 | |||
186 | self::assertTrue($table->hasColumn('id')); |
||
187 | self::assertTrue($table->hasColumn('test')); |
||
188 | self::assertTrue($table->hasColumn('foreign_key_test')); |
||
189 | } |
||
190 | } |
||
191 | |||
192 | self::assertTrue( $foundTable , "The 'list_tables_test' table has to be found."); |
||
193 | } |
||
194 | |||
195 | public function createListTableColumns() |
||
196 | { |
||
197 | $table = new Table('list_table_columns'); |
||
198 | $table->addColumn('id', 'integer', array('notnull' => true)); |
||
199 | $table->addColumn('test', 'string', array('length' => 255, 'notnull' => false, 'default' => 'expected default')); |
||
200 | $table->addColumn('foo', 'text', array('notnull' => true)); |
||
201 | $table->addColumn('bar', 'decimal', array('precision' => 10, 'scale' => 4, 'notnull' => false)); |
||
202 | $table->addColumn('baz1', 'datetime'); |
||
203 | $table->addColumn('baz2', 'time'); |
||
204 | $table->addColumn('baz3', 'date'); |
||
205 | $table->setPrimaryKey(array('id')); |
||
206 | |||
207 | return $table; |
||
208 | } |
||
209 | |||
210 | public function testListTableColumns() |
||
211 | { |
||
212 | $table = $this->createListTableColumns(); |
||
213 | |||
214 | $this->_sm->dropAndCreateTable($table); |
||
215 | |||
216 | $columns = $this->_sm->listTableColumns('list_table_columns'); |
||
217 | $columnsKeys = array_keys($columns); |
||
218 | |||
219 | self::assertArrayHasKey('id', $columns); |
||
220 | self::assertEquals(0, array_search('id', $columnsKeys)); |
||
221 | self::assertEquals('id', strtolower($columns['id']->getname())); |
||
222 | self::assertInstanceOf('Doctrine\DBAL\Types\IntegerType', $columns['id']->gettype()); |
||
223 | self::assertEquals(false, $columns['id']->getunsigned()); |
||
224 | self::assertEquals(true, $columns['id']->getnotnull()); |
||
225 | self::assertEquals(null, $columns['id']->getdefault()); |
||
226 | self::assertInternalType('array', $columns['id']->getPlatformOptions()); |
||
227 | |||
228 | self::assertArrayHasKey('test', $columns); |
||
229 | self::assertEquals(1, array_search('test', $columnsKeys)); |
||
230 | self::assertEquals('test', strtolower($columns['test']->getname())); |
||
231 | self::assertInstanceOf('Doctrine\DBAL\Types\StringType', $columns['test']->gettype()); |
||
232 | self::assertEquals(255, $columns['test']->getlength()); |
||
233 | self::assertEquals(false, $columns['test']->getfixed()); |
||
234 | self::assertEquals(false, $columns['test']->getnotnull()); |
||
235 | self::assertEquals('expected default', $columns['test']->getdefault()); |
||
236 | self::assertInternalType('array', $columns['test']->getPlatformOptions()); |
||
237 | |||
238 | self::assertEquals('foo', strtolower($columns['foo']->getname())); |
||
239 | self::assertEquals(2, array_search('foo', $columnsKeys)); |
||
240 | self::assertInstanceOf('Doctrine\DBAL\Types\TextType', $columns['foo']->gettype()); |
||
241 | self::assertEquals(false, $columns['foo']->getunsigned()); |
||
242 | self::assertEquals(false, $columns['foo']->getfixed()); |
||
243 | self::assertEquals(true, $columns['foo']->getnotnull()); |
||
244 | self::assertEquals(null, $columns['foo']->getdefault()); |
||
245 | self::assertInternalType('array', $columns['foo']->getPlatformOptions()); |
||
246 | |||
247 | self::assertEquals('bar', strtolower($columns['bar']->getname())); |
||
248 | self::assertEquals(3, array_search('bar', $columnsKeys)); |
||
249 | self::assertInstanceOf('Doctrine\DBAL\Types\DecimalType', $columns['bar']->gettype()); |
||
250 | self::assertEquals(null, $columns['bar']->getlength()); |
||
251 | self::assertEquals(10, $columns['bar']->getprecision()); |
||
252 | self::assertEquals(4, $columns['bar']->getscale()); |
||
253 | self::assertEquals(false, $columns['bar']->getunsigned()); |
||
254 | self::assertEquals(false, $columns['bar']->getfixed()); |
||
255 | self::assertEquals(false, $columns['bar']->getnotnull()); |
||
256 | self::assertEquals(null, $columns['bar']->getdefault()); |
||
257 | self::assertInternalType('array', $columns['bar']->getPlatformOptions()); |
||
258 | |||
259 | self::assertEquals('baz1', strtolower($columns['baz1']->getname())); |
||
260 | self::assertEquals(4, array_search('baz1', $columnsKeys)); |
||
261 | self::assertInstanceOf('Doctrine\DBAL\Types\DateTimeType', $columns['baz1']->gettype()); |
||
262 | self::assertEquals(true, $columns['baz1']->getnotnull()); |
||
263 | self::assertEquals(null, $columns['baz1']->getdefault()); |
||
264 | self::assertInternalType('array', $columns['baz1']->getPlatformOptions()); |
||
265 | |||
266 | self::assertEquals('baz2', strtolower($columns['baz2']->getname())); |
||
267 | self::assertEquals(5, array_search('baz2', $columnsKeys)); |
||
268 | self::assertContains($columns['baz2']->gettype()->getName(), array('time', 'date', 'datetime')); |
||
269 | self::assertEquals(true, $columns['baz2']->getnotnull()); |
||
270 | self::assertEquals(null, $columns['baz2']->getdefault()); |
||
271 | self::assertInternalType('array', $columns['baz2']->getPlatformOptions()); |
||
272 | |||
273 | self::assertEquals('baz3', strtolower($columns['baz3']->getname())); |
||
274 | self::assertEquals(6, array_search('baz3', $columnsKeys)); |
||
275 | self::assertContains($columns['baz3']->gettype()->getName(), array('time', 'date', 'datetime')); |
||
276 | self::assertEquals(true, $columns['baz3']->getnotnull()); |
||
277 | self::assertEquals(null, $columns['baz3']->getdefault()); |
||
278 | self::assertInternalType('array', $columns['baz3']->getPlatformOptions()); |
||
279 | } |
||
280 | |||
281 | /** |
||
282 | * @group DBAL-1078 |
||
283 | */ |
||
284 | View Code Duplication | public function testListTableColumnsWithFixedStringColumn() |
|
285 | { |
||
286 | $tableName = 'test_list_table_fixed_string'; |
||
287 | |||
288 | $table = new Table($tableName); |
||
289 | $table->addColumn('column_char', 'string', array('fixed' => true, 'length' => 2)); |
||
290 | |||
291 | $this->_sm->createTable($table); |
||
292 | |||
293 | $columns = $this->_sm->listTableColumns($tableName); |
||
294 | |||
295 | self::assertArrayHasKey('column_char', $columns); |
||
296 | self::assertInstanceOf('Doctrine\DBAL\Types\StringType', $columns['column_char']->getType()); |
||
297 | self::assertTrue($columns['column_char']->getFixed()); |
||
298 | self::assertSame(2, $columns['column_char']->getLength()); |
||
299 | } |
||
300 | |||
301 | public function testListTableColumnsDispatchEvent() |
||
302 | { |
||
303 | $table = $this->createListTableColumns(); |
||
304 | |||
305 | $this->_sm->dropAndCreateTable($table); |
||
306 | |||
307 | $listenerMock = $this |
||
308 | ->getMockBuilder('ListTableColumnsDispatchEventListener') |
||
309 | ->setMethods(['onSchemaColumnDefinition']) |
||
310 | ->getMock(); |
||
311 | $listenerMock |
||
312 | ->expects($this->exactly(7)) |
||
313 | ->method('onSchemaColumnDefinition'); |
||
314 | |||
315 | $oldEventManager = $this->_sm->getDatabasePlatform()->getEventManager(); |
||
316 | |||
317 | $eventManager = new EventManager(); |
||
318 | $eventManager->addEventListener(array(Events::onSchemaColumnDefinition), $listenerMock); |
||
319 | |||
320 | $this->_sm->getDatabasePlatform()->setEventManager($eventManager); |
||
321 | |||
322 | $this->_sm->listTableColumns('list_table_columns'); |
||
323 | |||
324 | $this->_sm->getDatabasePlatform()->setEventManager($oldEventManager); |
||
325 | } |
||
326 | |||
327 | public function testListTableIndexesDispatchEvent() |
||
328 | { |
||
329 | $table = $this->getTestTable('list_table_indexes_test'); |
||
330 | $table->addUniqueIndex(array('test'), 'test_index_name'); |
||
331 | $table->addIndex(array('id', 'test'), 'test_composite_idx'); |
||
332 | |||
333 | $this->_sm->dropAndCreateTable($table); |
||
334 | |||
335 | $listenerMock = $this |
||
336 | ->getMockBuilder('ListTableIndexesDispatchEventListener') |
||
337 | ->setMethods(['onSchemaIndexDefinition']) |
||
338 | ->getMock(); |
||
339 | $listenerMock |
||
340 | ->expects($this->exactly(3)) |
||
341 | ->method('onSchemaIndexDefinition'); |
||
342 | |||
343 | $oldEventManager = $this->_sm->getDatabasePlatform()->getEventManager(); |
||
344 | |||
345 | $eventManager = new EventManager(); |
||
346 | $eventManager->addEventListener(array(Events::onSchemaIndexDefinition), $listenerMock); |
||
347 | |||
348 | $this->_sm->getDatabasePlatform()->setEventManager($eventManager); |
||
349 | |||
350 | $this->_sm->listTableIndexes('list_table_indexes_test'); |
||
351 | |||
352 | $this->_sm->getDatabasePlatform()->setEventManager($oldEventManager); |
||
353 | } |
||
354 | |||
355 | public function testDiffListTableColumns() |
||
356 | { |
||
357 | if ($this->_sm->getDatabasePlatform()->getName() == 'oracle') { |
||
358 | $this->markTestSkipped('Does not work with Oracle, since it cannot detect DateTime, Date and Time differenecs (at the moment).'); |
||
359 | } |
||
360 | |||
361 | $offlineTable = $this->createListTableColumns(); |
||
362 | $this->_sm->dropAndCreateTable($offlineTable); |
||
363 | $onlineTable = $this->_sm->listTableDetails('list_table_columns'); |
||
364 | |||
365 | $comparator = new \Doctrine\DBAL\Schema\Comparator(); |
||
366 | $diff = $comparator->diffTable($offlineTable, $onlineTable); |
||
367 | |||
368 | self::assertFalse($diff, "No differences should be detected with the offline vs online schema."); |
||
369 | } |
||
370 | |||
371 | public function testListTableIndexes() |
||
372 | { |
||
373 | $table = $this->getTestCompositeTable('list_table_indexes_test'); |
||
374 | $table->addUniqueIndex(array('test'), 'test_index_name'); |
||
375 | $table->addIndex(array('id', 'test'), 'test_composite_idx'); |
||
376 | |||
377 | $this->_sm->dropAndCreateTable($table); |
||
378 | |||
379 | $tableIndexes = $this->_sm->listTableIndexes('list_table_indexes_test'); |
||
380 | |||
381 | self::assertEquals(3, count($tableIndexes)); |
||
382 | |||
383 | self::assertArrayHasKey('primary', $tableIndexes, 'listTableIndexes() has to return a "primary" array key.'); |
||
384 | self::assertEquals(array('id', 'other_id'), array_map('strtolower', $tableIndexes['primary']->getColumns())); |
||
385 | self::assertTrue($tableIndexes['primary']->isUnique()); |
||
386 | self::assertTrue($tableIndexes['primary']->isPrimary()); |
||
387 | |||
388 | self::assertEquals('test_index_name', strtolower($tableIndexes['test_index_name']->getName())); |
||
389 | self::assertEquals(array('test'), array_map('strtolower', $tableIndexes['test_index_name']->getColumns())); |
||
390 | self::assertTrue($tableIndexes['test_index_name']->isUnique()); |
||
391 | self::assertFalse($tableIndexes['test_index_name']->isPrimary()); |
||
392 | |||
393 | self::assertEquals('test_composite_idx', strtolower($tableIndexes['test_composite_idx']->getName())); |
||
394 | self::assertEquals(array('id', 'test'), array_map('strtolower', $tableIndexes['test_composite_idx']->getColumns())); |
||
395 | self::assertFalse($tableIndexes['test_composite_idx']->isUnique()); |
||
396 | self::assertFalse($tableIndexes['test_composite_idx']->isPrimary()); |
||
397 | } |
||
398 | |||
399 | public function testDropAndCreateIndex() |
||
400 | { |
||
401 | $table = $this->getTestTable('test_create_index'); |
||
402 | $table->addUniqueIndex(array('test'), 'test'); |
||
403 | $this->_sm->dropAndCreateTable($table); |
||
404 | |||
405 | $this->_sm->dropAndCreateIndex($table->getIndex('test'), $table); |
||
406 | $tableIndexes = $this->_sm->listTableIndexes('test_create_index'); |
||
407 | self::assertInternalType('array', $tableIndexes); |
||
408 | |||
409 | self::assertEquals('test', strtolower($tableIndexes['test']->getName())); |
||
410 | self::assertEquals(array('test'), array_map('strtolower', $tableIndexes['test']->getColumns())); |
||
411 | self::assertTrue($tableIndexes['test']->isUnique()); |
||
412 | self::assertFalse($tableIndexes['test']->isPrimary()); |
||
413 | } |
||
414 | |||
415 | public function testCreateTableWithForeignKeys() |
||
416 | { |
||
417 | if(!$this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) { |
||
418 | $this->markTestSkipped('Platform does not support foreign keys.'); |
||
419 | } |
||
420 | |||
421 | $tableB = $this->getTestTable('test_foreign'); |
||
422 | |||
423 | $this->_sm->dropAndCreateTable($tableB); |
||
424 | |||
425 | $tableA = $this->getTestTable('test_create_fk'); |
||
426 | $tableA->addForeignKeyConstraint('test_foreign', array('foreign_key_test'), array('id')); |
||
427 | |||
428 | $this->_sm->dropAndCreateTable($tableA); |
||
429 | |||
430 | $fkTable = $this->_sm->listTableDetails('test_create_fk'); |
||
431 | $fkConstraints = $fkTable->getForeignKeys(); |
||
432 | self::assertEquals(1, count($fkConstraints), "Table 'test_create_fk1' has to have one foreign key."); |
||
433 | |||
434 | $fkConstraint = current($fkConstraints); |
||
435 | self::assertInstanceOf('\Doctrine\DBAL\Schema\ForeignKeyConstraint', $fkConstraint); |
||
436 | self::assertEquals('test_foreign', strtolower($fkConstraint->getForeignTableName())); |
||
437 | self::assertEquals(array('foreign_key_test'), array_map('strtolower', $fkConstraint->getColumns())); |
||
438 | self::assertEquals(array('id'), array_map('strtolower', $fkConstraint->getForeignColumns())); |
||
439 | |||
440 | self::assertTrue($fkTable->columnsAreIndexed($fkConstraint->getColumns()), "The columns of a foreign key constraint should always be indexed."); |
||
441 | } |
||
442 | |||
443 | public function testListForeignKeys() |
||
444 | { |
||
445 | if(!$this->_conn->getDatabasePlatform()->supportsForeignKeyConstraints()) { |
||
446 | $this->markTestSkipped('Does not support foreign key constraints.'); |
||
447 | } |
||
448 | |||
449 | $this->createTestTable('test_create_fk1'); |
||
450 | $this->createTestTable('test_create_fk2'); |
||
451 | |||
452 | $foreignKey = new \Doctrine\DBAL\Schema\ForeignKeyConstraint( |
||
453 | array('foreign_key_test'), 'test_create_fk2', array('id'), 'foreign_key_test_fk', array('onDelete' => 'CASCADE') |
||
454 | ); |
||
455 | |||
456 | $this->_sm->createForeignKey($foreignKey, 'test_create_fk1'); |
||
457 | |||
458 | $fkeys = $this->_sm->listTableForeignKeys('test_create_fk1'); |
||
459 | |||
460 | self::assertEquals(1, count($fkeys), "Table 'test_create_fk1' has to have one foreign key."); |
||
461 | |||
462 | self::assertInstanceOf('Doctrine\DBAL\Schema\ForeignKeyConstraint', $fkeys[0]); |
||
463 | self::assertEquals(array('foreign_key_test'), array_map('strtolower', $fkeys[0]->getLocalColumns())); |
||
464 | self::assertEquals(array('id'), array_map('strtolower', $fkeys[0]->getForeignColumns())); |
||
465 | self::assertEquals('test_create_fk2', strtolower($fkeys[0]->getForeignTableName())); |
||
466 | |||
467 | if($fkeys[0]->hasOption('onDelete')) { |
||
468 | self::assertEquals('CASCADE', $fkeys[0]->getOption('onDelete')); |
||
469 | } |
||
470 | } |
||
471 | |||
472 | protected function getCreateExampleViewSql() |
||
473 | { |
||
474 | $this->markTestSkipped('No Create Example View SQL was defined for this SchemaManager'); |
||
475 | } |
||
476 | |||
477 | public function testCreateSchema() |
||
478 | { |
||
479 | $this->createTestTable('test_table'); |
||
480 | |||
481 | $schema = $this->_sm->createSchema(); |
||
482 | self::assertTrue($schema->hasTable('test_table')); |
||
483 | } |
||
484 | |||
485 | public function testAlterTableScenario() |
||
486 | { |
||
487 | if(!$this->_sm->getDatabasePlatform()->supportsAlterTable()) { |
||
488 | $this->markTestSkipped('Alter Table is not supported by this platform.'); |
||
489 | } |
||
490 | |||
491 | $alterTable = $this->createTestTable('alter_table'); |
||
492 | $this->createTestTable('alter_table_foreign'); |
||
493 | |||
494 | $table = $this->_sm->listTableDetails('alter_table'); |
||
495 | self::assertTrue($table->hasColumn('id')); |
||
496 | self::assertTrue($table->hasColumn('test')); |
||
497 | self::assertTrue($table->hasColumn('foreign_key_test')); |
||
498 | self::assertEquals(0, count($table->getForeignKeys())); |
||
499 | self::assertEquals(1, count($table->getIndexes())); |
||
500 | |||
501 | $tableDiff = new \Doctrine\DBAL\Schema\TableDiff("alter_table"); |
||
502 | $tableDiff->fromTable = $alterTable; |
||
503 | $tableDiff->addedColumns['foo'] = new \Doctrine\DBAL\Schema\Column('foo', Type::getType('integer')); |
||
504 | $tableDiff->removedColumns['test'] = $table->getColumn('test'); |
||
505 | |||
506 | $this->_sm->alterTable($tableDiff); |
||
507 | |||
508 | $table = $this->_sm->listTableDetails('alter_table'); |
||
509 | self::assertFalse($table->hasColumn('test')); |
||
510 | self::assertTrue($table->hasColumn('foo')); |
||
511 | |||
512 | $tableDiff = new \Doctrine\DBAL\Schema\TableDiff("alter_table"); |
||
513 | $tableDiff->fromTable = $table; |
||
514 | $tableDiff->addedIndexes[] = new \Doctrine\DBAL\Schema\Index('foo_idx', array('foo')); |
||
515 | |||
516 | $this->_sm->alterTable($tableDiff); |
||
517 | |||
518 | $table = $this->_sm->listTableDetails('alter_table'); |
||
519 | self::assertEquals(2, count($table->getIndexes())); |
||
520 | self::assertTrue($table->hasIndex('foo_idx')); |
||
521 | self::assertEquals(array('foo'), array_map('strtolower', $table->getIndex('foo_idx')->getColumns())); |
||
522 | self::assertFalse($table->getIndex('foo_idx')->isPrimary()); |
||
523 | self::assertFalse($table->getIndex('foo_idx')->isUnique()); |
||
524 | |||
525 | $tableDiff = new \Doctrine\DBAL\Schema\TableDiff("alter_table"); |
||
526 | $tableDiff->fromTable = $table; |
||
527 | $tableDiff->changedIndexes[] = new \Doctrine\DBAL\Schema\Index('foo_idx', array('foo', 'foreign_key_test')); |
||
528 | |||
529 | $this->_sm->alterTable($tableDiff); |
||
530 | |||
531 | $table = $this->_sm->listTableDetails('alter_table'); |
||
532 | self::assertEquals(2, count($table->getIndexes())); |
||
533 | self::assertTrue($table->hasIndex('foo_idx')); |
||
534 | self::assertEquals(array('foo', 'foreign_key_test'), array_map('strtolower', $table->getIndex('foo_idx')->getColumns())); |
||
535 | |||
536 | $tableDiff = new \Doctrine\DBAL\Schema\TableDiff("alter_table"); |
||
537 | $tableDiff->fromTable = $table; |
||
538 | $tableDiff->renamedIndexes['foo_idx'] = new \Doctrine\DBAL\Schema\Index('bar_idx', array('foo', 'foreign_key_test')); |
||
539 | |||
540 | $this->_sm->alterTable($tableDiff); |
||
541 | |||
542 | $table = $this->_sm->listTableDetails('alter_table'); |
||
543 | self::assertEquals(2, count($table->getIndexes())); |
||
544 | self::assertTrue($table->hasIndex('bar_idx')); |
||
545 | self::assertFalse($table->hasIndex('foo_idx')); |
||
546 | self::assertEquals(array('foo', 'foreign_key_test'), array_map('strtolower', $table->getIndex('bar_idx')->getColumns())); |
||
547 | self::assertFalse($table->getIndex('bar_idx')->isPrimary()); |
||
548 | self::assertFalse($table->getIndex('bar_idx')->isUnique()); |
||
549 | |||
550 | $tableDiff = new \Doctrine\DBAL\Schema\TableDiff("alter_table"); |
||
551 | $tableDiff->fromTable = $table; |
||
552 | $tableDiff->removedIndexes[] = new \Doctrine\DBAL\Schema\Index('bar_idx', array('foo', 'foreign_key_test')); |
||
553 | $fk = new \Doctrine\DBAL\Schema\ForeignKeyConstraint(array('foreign_key_test'), 'alter_table_foreign', array('id')); |
||
554 | $tableDiff->addedForeignKeys[] = $fk; |
||
555 | |||
556 | $this->_sm->alterTable($tableDiff); |
||
557 | $table = $this->_sm->listTableDetails('alter_table'); |
||
558 | |||
559 | // dont check for index size here, some platforms automatically add indexes for foreign keys. |
||
560 | self::assertFalse($table->hasIndex('bar_idx')); |
||
561 | |||
562 | if ($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) { |
||
563 | $fks = $table->getForeignKeys(); |
||
564 | self::assertCount(1, $fks); |
||
565 | $foreignKey = current($fks); |
||
566 | self::assertEquals('alter_table_foreign', strtolower($foreignKey->getForeignTableName())); |
||
567 | self::assertEquals(array('foreign_key_test'), array_map('strtolower', $foreignKey->getColumns())); |
||
568 | self::assertEquals(array('id'), array_map('strtolower', $foreignKey->getForeignColumns())); |
||
569 | } |
||
570 | } |
||
571 | |||
572 | public function testCreateAndListViews() |
||
573 | { |
||
574 | if (!$this->_sm->getDatabasePlatform()->supportsViews()) { |
||
575 | $this->markTestSkipped('Views is not supported by this platform.'); |
||
576 | } |
||
577 | |||
578 | $this->createTestTable('view_test_table'); |
||
579 | |||
580 | $name = "doctrine_test_view"; |
||
581 | $sql = "SELECT * FROM view_test_table"; |
||
582 | |||
583 | $view = new \Doctrine\DBAL\Schema\View($name, $sql); |
||
584 | |||
585 | $this->_sm->dropAndCreateView($view); |
||
586 | |||
587 | self::assertTrue($this->hasElementWithName($this->_sm->listViews(), $name)); |
||
588 | } |
||
589 | |||
590 | View Code Duplication | public function testAutoincrementDetection() |
|
591 | { |
||
592 | if (!$this->_sm->getDatabasePlatform()->supportsIdentityColumns()) { |
||
593 | $this->markTestSkipped('This test is only supported on platforms that have autoincrement'); |
||
594 | } |
||
595 | |||
596 | $table = new Table('test_autoincrement'); |
||
597 | $table->setSchemaConfig($this->_sm->createSchemaConfig()); |
||
598 | $table->addColumn('id', 'integer', array('autoincrement' => true)); |
||
599 | $table->setPrimaryKey(array('id')); |
||
600 | |||
601 | $this->_sm->createTable($table); |
||
602 | |||
603 | $inferredTable = $this->_sm->listTableDetails('test_autoincrement'); |
||
604 | self::assertTrue($inferredTable->hasColumn('id')); |
||
605 | self::assertTrue($inferredTable->getColumn('id')->getAutoincrement()); |
||
606 | } |
||
607 | |||
608 | /** |
||
609 | * @group DBAL-792 |
||
610 | */ |
||
611 | View Code Duplication | public function testAutoincrementDetectionMulticolumns() |
|
612 | { |
||
613 | if (!$this->_sm->getDatabasePlatform()->supportsIdentityColumns()) { |
||
614 | $this->markTestSkipped('This test is only supported on platforms that have autoincrement'); |
||
615 | } |
||
616 | |||
617 | $table = new Table('test_not_autoincrement'); |
||
618 | $table->setSchemaConfig($this->_sm->createSchemaConfig()); |
||
619 | $table->addColumn('id', 'integer'); |
||
620 | $table->addColumn('other_id', 'integer'); |
||
621 | $table->setPrimaryKey(array('id', 'other_id')); |
||
622 | |||
623 | $this->_sm->createTable($table); |
||
624 | |||
625 | $inferredTable = $this->_sm->listTableDetails('test_not_autoincrement'); |
||
626 | self::assertTrue($inferredTable->hasColumn('id')); |
||
627 | self::assertFalse($inferredTable->getColumn('id')->getAutoincrement()); |
||
628 | } |
||
629 | |||
630 | /** |
||
631 | * @group DDC-887 |
||
632 | */ |
||
633 | public function testUpdateSchemaWithForeignKeyRenaming() |
||
634 | { |
||
635 | if (!$this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) { |
||
636 | $this->markTestSkipped('This test is only supported on platforms that have foreign keys.'); |
||
637 | } |
||
638 | |||
639 | $table = new Table('test_fk_base'); |
||
640 | $table->addColumn('id', 'integer'); |
||
641 | $table->setPrimaryKey(array('id')); |
||
642 | |||
643 | $tableFK = new Table('test_fk_rename'); |
||
644 | $tableFK->setSchemaConfig($this->_sm->createSchemaConfig()); |
||
645 | $tableFK->addColumn('id', 'integer'); |
||
646 | $tableFK->addColumn('fk_id', 'integer'); |
||
647 | $tableFK->setPrimaryKey(array('id')); |
||
648 | $tableFK->addIndex(array('fk_id'), 'fk_idx'); |
||
649 | $tableFK->addForeignKeyConstraint('test_fk_base', array('fk_id'), array('id')); |
||
650 | |||
651 | $this->_sm->createTable($table); |
||
652 | $this->_sm->createTable($tableFK); |
||
653 | |||
654 | $tableFKNew = new Table('test_fk_rename'); |
||
655 | $tableFKNew->setSchemaConfig($this->_sm->createSchemaConfig()); |
||
656 | $tableFKNew->addColumn('id', 'integer'); |
||
657 | $tableFKNew->addColumn('rename_fk_id', 'integer'); |
||
658 | $tableFKNew->setPrimaryKey(array('id')); |
||
659 | $tableFKNew->addIndex(array('rename_fk_id'), 'fk_idx'); |
||
660 | $tableFKNew->addForeignKeyConstraint('test_fk_base', array('rename_fk_id'), array('id')); |
||
661 | |||
662 | $c = new \Doctrine\DBAL\Schema\Comparator(); |
||
663 | $tableDiff = $c->diffTable($tableFK, $tableFKNew); |
||
664 | |||
665 | $this->_sm->alterTable($tableDiff); |
||
666 | |||
667 | $table = $this->_sm->listTableDetails('test_fk_rename'); |
||
668 | $foreignKeys = $table->getForeignKeys(); |
||
669 | |||
670 | self::assertTrue($table->hasColumn('rename_fk_id')); |
||
671 | self::assertCount(1, $foreignKeys); |
||
672 | self::assertSame(['rename_fk_id'], array_map('strtolower', current($foreignKeys)->getColumns())); |
||
673 | } |
||
674 | |||
675 | /** |
||
676 | * @group DBAL-1062 |
||
677 | */ |
||
678 | public function testRenameIndexUsedInForeignKeyConstraint() |
||
679 | { |
||
680 | if (! $this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) { |
||
681 | $this->markTestSkipped('This test is only supported on platforms that have foreign keys.'); |
||
682 | } |
||
683 | |||
684 | $primaryTable = new Table('test_rename_index_primary'); |
||
685 | $primaryTable->addColumn('id', 'integer'); |
||
686 | $primaryTable->setPrimaryKey(array('id')); |
||
687 | |||
688 | $foreignTable = new Table('test_rename_index_foreign'); |
||
689 | $foreignTable->addColumn('fk', 'integer'); |
||
690 | $foreignTable->addIndex(array('fk'), 'rename_index_fk_idx'); |
||
691 | $foreignTable->addForeignKeyConstraint( |
||
692 | 'test_rename_index_primary', |
||
693 | array('fk'), |
||
694 | array('id'), |
||
695 | array(), |
||
696 | 'fk_constraint' |
||
697 | ); |
||
698 | |||
699 | $this->_sm->dropAndCreateTable($primaryTable); |
||
700 | $this->_sm->dropAndCreateTable($foreignTable); |
||
701 | |||
702 | $foreignTable2 = clone $foreignTable; |
||
703 | $foreignTable2->renameIndex('rename_index_fk_idx', 'renamed_index_fk_idx'); |
||
704 | |||
705 | $comparator = new Comparator(); |
||
706 | |||
707 | $this->_sm->alterTable($comparator->diffTable($foreignTable, $foreignTable2)); |
||
708 | |||
709 | $foreignTable = $this->_sm->listTableDetails('test_rename_index_foreign'); |
||
710 | |||
711 | self::assertFalse($foreignTable->hasIndex('rename_index_fk_idx')); |
||
712 | self::assertTrue($foreignTable->hasIndex('renamed_index_fk_idx')); |
||
713 | self::assertTrue($foreignTable->hasForeignKey('fk_constraint')); |
||
714 | } |
||
715 | |||
716 | /** |
||
717 | * @group DBAL-42 |
||
718 | */ |
||
719 | public function testGetColumnComment() |
||
720 | { |
||
721 | View Code Duplication | if ( ! $this->_conn->getDatabasePlatform()->supportsInlineColumnComments() && |
|
722 | ! $this->_conn->getDatabasePlatform()->supportsCommentOnStatement() && |
||
723 | $this->_conn->getDatabasePlatform()->getName() != 'mssql') { |
||
724 | $this->markTestSkipped('Database does not support column comments.'); |
||
725 | } |
||
726 | |||
727 | $table = new Table('column_comment_test'); |
||
728 | $table->addColumn('id', 'integer', array('comment' => 'This is a comment')); |
||
729 | $table->setPrimaryKey(array('id')); |
||
730 | |||
731 | $this->_sm->createTable($table); |
||
732 | |||
733 | $columns = $this->_sm->listTableColumns("column_comment_test"); |
||
734 | self::assertEquals(1, count($columns)); |
||
735 | self::assertEquals('This is a comment', $columns['id']->getComment()); |
||
736 | |||
737 | $tableDiff = new \Doctrine\DBAL\Schema\TableDiff('column_comment_test'); |
||
738 | $tableDiff->fromTable = $table; |
||
739 | $tableDiff->changedColumns['id'] = new \Doctrine\DBAL\Schema\ColumnDiff( |
||
740 | 'id', new \Doctrine\DBAL\Schema\Column( |
||
741 | 'id', \Doctrine\DBAL\Types\Type::getType('integer'), array('primary' => true) |
||
742 | ), |
||
743 | array('comment'), |
||
744 | new \Doctrine\DBAL\Schema\Column( |
||
745 | 'id', \Doctrine\DBAL\Types\Type::getType('integer'), array('comment' => 'This is a comment') |
||
746 | ) |
||
747 | ); |
||
748 | |||
749 | $this->_sm->alterTable($tableDiff); |
||
750 | |||
751 | $columns = $this->_sm->listTableColumns("column_comment_test"); |
||
752 | self::assertEquals(1, count($columns)); |
||
753 | self::assertEmpty($columns['id']->getComment()); |
||
754 | } |
||
755 | |||
756 | /** |
||
757 | * @group DBAL-42 |
||
758 | */ |
||
759 | public function testAutomaticallyAppendCommentOnMarkedColumns() |
||
760 | { |
||
761 | View Code Duplication | if ( ! $this->_conn->getDatabasePlatform()->supportsInlineColumnComments() && |
|
762 | ! $this->_conn->getDatabasePlatform()->supportsCommentOnStatement() && |
||
763 | $this->_conn->getDatabasePlatform()->getName() != 'mssql') { |
||
764 | $this->markTestSkipped('Database does not support column comments.'); |
||
765 | } |
||
766 | |||
767 | $table = new Table('column_comment_test2'); |
||
768 | $table->addColumn('id', 'integer', array('comment' => 'This is a comment')); |
||
769 | $table->addColumn('obj', 'object', array('comment' => 'This is a comment')); |
||
770 | $table->addColumn('arr', 'array', array('comment' => 'This is a comment')); |
||
771 | $table->setPrimaryKey(array('id')); |
||
772 | |||
773 | $this->_sm->createTable($table); |
||
774 | |||
775 | $columns = $this->_sm->listTableColumns("column_comment_test2"); |
||
776 | self::assertEquals(3, count($columns)); |
||
777 | self::assertEquals('This is a comment', $columns['id']->getComment()); |
||
778 | self::assertEquals('This is a comment', $columns['obj']->getComment(), "The Doctrine2 Typehint should be stripped from comment."); |
||
779 | self::assertInstanceOf('Doctrine\DBAL\Types\ObjectType', $columns['obj']->getType(), "The Doctrine2 should be detected from comment hint."); |
||
780 | self::assertEquals('This is a comment', $columns['arr']->getComment(), "The Doctrine2 Typehint should be stripped from comment."); |
||
781 | self::assertInstanceOf('Doctrine\DBAL\Types\ArrayType', $columns['arr']->getType(), "The Doctrine2 should be detected from comment hint."); |
||
782 | } |
||
783 | |||
784 | /** |
||
785 | * @group DBAL-1228 |
||
786 | */ |
||
787 | public function testCommentHintOnDateIntervalTypeColumn() |
||
788 | { |
||
789 | View Code Duplication | if ( ! $this->_conn->getDatabasePlatform()->supportsInlineColumnComments() && |
|
790 | ! $this->_conn->getDatabasePlatform()->supportsCommentOnStatement() && |
||
791 | $this->_conn->getDatabasePlatform()->getName() != 'mssql') { |
||
792 | $this->markTestSkipped('Database does not support column comments.'); |
||
793 | } |
||
794 | |||
795 | $table = new Table('column_dateinterval_comment'); |
||
796 | $table->addColumn('id', 'integer', array('comment' => 'This is a comment')); |
||
797 | $table->addColumn('date_interval', 'dateinterval', array('comment' => 'This is a comment')); |
||
798 | $table->setPrimaryKey(array('id')); |
||
799 | |||
800 | $this->_sm->createTable($table); |
||
801 | |||
802 | $columns = $this->_sm->listTableColumns("column_dateinterval_comment"); |
||
803 | self::assertEquals(2, count($columns)); |
||
804 | self::assertEquals('This is a comment', $columns['id']->getComment()); |
||
805 | self::assertEquals('This is a comment', $columns['date_interval']->getComment(), "The Doctrine2 Typehint should be stripped from comment."); |
||
806 | self::assertInstanceOf('Doctrine\DBAL\Types\DateIntervalType', $columns['date_interval']->getType(), "The Doctrine2 should be detected from comment hint."); |
||
807 | } |
||
808 | |||
809 | /** |
||
810 | * @group DBAL-825 |
||
811 | */ |
||
812 | public function testChangeColumnsTypeWithDefaultValue() |
||
813 | { |
||
814 | $tableName = 'column_def_change_type'; |
||
815 | $table = new Table($tableName); |
||
816 | |||
817 | $table->addColumn('col_int', 'smallint', array('default' => 666)); |
||
818 | $table->addColumn('col_string', 'string', array('default' => 'foo')); |
||
819 | |||
820 | $this->_sm->dropAndCreateTable($table); |
||
821 | |||
822 | $tableDiff = new TableDiff($tableName); |
||
823 | $tableDiff->fromTable = $table; |
||
824 | $tableDiff->changedColumns['col_int'] = new ColumnDiff( |
||
825 | 'col_int', |
||
826 | new Column('col_int', Type::getType('integer'), array('default' => 666)), |
||
827 | array('type'), |
||
828 | new Column('col_int', Type::getType('smallint'), array('default' => 666)) |
||
829 | ); |
||
830 | |||
831 | $tableDiff->changedColumns['col_string'] = new ColumnDiff( |
||
832 | 'col_string', |
||
833 | new Column('col_string', Type::getType('string'), array('default' => 'foo', 'fixed' => true)), |
||
834 | array('fixed'), |
||
835 | new Column('col_string', Type::getType('string'), array('default' => 'foo')) |
||
836 | ); |
||
837 | |||
838 | $this->_sm->alterTable($tableDiff); |
||
839 | |||
840 | $columns = $this->_sm->listTableColumns($tableName); |
||
841 | |||
842 | self::assertInstanceOf('Doctrine\DBAL\Types\IntegerType', $columns['col_int']->getType()); |
||
843 | self::assertEquals(666, $columns['col_int']->getDefault()); |
||
844 | |||
845 | self::assertInstanceOf('Doctrine\DBAL\Types\StringType', $columns['col_string']->getType()); |
||
846 | self::assertEquals('foo', $columns['col_string']->getDefault()); |
||
847 | } |
||
848 | |||
849 | /** |
||
850 | * @group DBAL-197 |
||
851 | */ |
||
852 | public function testListTableWithBlob() |
||
853 | { |
||
854 | $table = new Table('test_blob_table'); |
||
855 | $table->addColumn('id', 'integer', ['comment' => 'This is a comment']); |
||
856 | $table->addColumn('binarydata', 'blob', []); |
||
857 | $table->setPrimaryKey(['id']); |
||
858 | |||
859 | $this->_sm->createTable($table); |
||
860 | |||
861 | $created = $this->_sm->listTableDetails('test_blob_table'); |
||
862 | |||
863 | self::assertTrue($created->hasColumn('id')); |
||
864 | self::assertTrue($created->hasColumn('binarydata')); |
||
865 | self::assertTrue($created->hasPrimaryKey()); |
||
866 | } |
||
867 | |||
868 | /** |
||
869 | * @param string $name |
||
870 | * @param array $data |
||
871 | * @return Table |
||
872 | */ |
||
873 | protected function createTestTable($name = 'test_table', $data = array()) |
||
874 | { |
||
875 | $options = array(); |
||
876 | if (isset($data['options'])) { |
||
877 | $options = $data['options']; |
||
878 | } |
||
879 | |||
880 | $table = $this->getTestTable($name, $options); |
||
881 | |||
882 | $this->_sm->dropAndCreateTable($table); |
||
883 | |||
884 | return $table; |
||
885 | } |
||
886 | |||
887 | protected function getTestTable($name, $options=array()) |
||
888 | { |
||
889 | $table = new Table($name, array(), array(), array(), false, $options); |
||
890 | $table->setSchemaConfig($this->_sm->createSchemaConfig()); |
||
891 | $table->addColumn('id', 'integer', array('notnull' => true)); |
||
892 | $table->setPrimaryKey(array('id')); |
||
893 | $table->addColumn('test', 'string', array('length' => 255)); |
||
894 | $table->addColumn('foreign_key_test', 'integer'); |
||
895 | return $table; |
||
896 | } |
||
897 | |||
898 | protected function getTestCompositeTable($name) |
||
899 | { |
||
900 | $table = new Table($name, array(), array(), array(), false, array()); |
||
901 | $table->setSchemaConfig($this->_sm->createSchemaConfig()); |
||
902 | $table->addColumn('id', 'integer', array('notnull' => true)); |
||
903 | $table->addColumn('other_id', 'integer', array('notnull' => true)); |
||
904 | $table->setPrimaryKey(array('id', 'other_id')); |
||
905 | $table->addColumn('test', 'string', array('length' => 255)); |
||
906 | return $table; |
||
907 | } |
||
908 | |||
909 | protected function assertHasTable($tables, $tableName) |
||
910 | { |
||
911 | $foundTable = false; |
||
912 | View Code Duplication | foreach ($tables as $table) { |
|
913 | self::assertInstanceOf('Doctrine\DBAL\Schema\Table', $table, 'No Table instance was found in tables array.'); |
||
914 | if (strtolower($table->getName()) == 'list_tables_test_new_name') { |
||
915 | $foundTable = true; |
||
916 | } |
||
917 | } |
||
918 | self::assertTrue($foundTable, "Could not find new table"); |
||
919 | } |
||
920 | |||
921 | public function testListForeignKeysComposite() |
||
922 | { |
||
923 | if(!$this->_conn->getDatabasePlatform()->supportsForeignKeyConstraints()) { |
||
924 | $this->markTestSkipped('Does not support foreign key constraints.'); |
||
925 | } |
||
926 | |||
927 | $this->_sm->createTable($this->getTestTable('test_create_fk3')); |
||
928 | $this->_sm->createTable($this->getTestCompositeTable('test_create_fk4')); |
||
929 | |||
930 | $foreignKey = new \Doctrine\DBAL\Schema\ForeignKeyConstraint( |
||
931 | array('id', 'foreign_key_test'), 'test_create_fk4', array('id', 'other_id'), 'foreign_key_test_fk2' |
||
932 | ); |
||
933 | |||
934 | $this->_sm->createForeignKey($foreignKey, 'test_create_fk3'); |
||
935 | |||
936 | $fkeys = $this->_sm->listTableForeignKeys('test_create_fk3'); |
||
937 | |||
938 | self::assertEquals(1, count($fkeys), "Table 'test_create_fk3' has to have one foreign key."); |
||
939 | |||
940 | self::assertInstanceOf('Doctrine\DBAL\Schema\ForeignKeyConstraint', $fkeys[0]); |
||
941 | self::assertEquals(array('id', 'foreign_key_test'), array_map('strtolower', $fkeys[0]->getLocalColumns())); |
||
942 | self::assertEquals(array('id', 'other_id'), array_map('strtolower', $fkeys[0]->getForeignColumns())); |
||
943 | } |
||
944 | |||
945 | /** |
||
946 | * @group DBAL-44 |
||
947 | */ |
||
948 | public function testColumnDefaultLifecycle() |
||
949 | { |
||
950 | $table = new Table("col_def_lifecycle"); |
||
951 | $table->addColumn('id', 'integer', array('primary' => true, 'autoincrement' => true)); |
||
952 | $table->addColumn('column1', 'string', array('default' => null)); |
||
953 | $table->addColumn('column2', 'string', array('default' => false)); |
||
954 | $table->addColumn('column3', 'string', array('default' => true)); |
||
955 | $table->addColumn('column4', 'string', array('default' => 0)); |
||
956 | $table->addColumn('column5', 'string', array('default' => '')); |
||
957 | $table->addColumn('column6', 'string', array('default' => 'def')); |
||
958 | $table->addColumn('column7', 'integer', array('default' => 0)); |
||
959 | $table->setPrimaryKey(array('id')); |
||
960 | |||
961 | $this->_sm->dropAndCreateTable($table); |
||
962 | |||
963 | $columns = $this->_sm->listTableColumns('col_def_lifecycle'); |
||
964 | |||
965 | self::assertNull($columns['id']->getDefault()); |
||
966 | self::assertNull($columns['column1']->getDefault()); |
||
967 | self::assertSame('', $columns['column2']->getDefault()); |
||
968 | self::assertSame('1', $columns['column3']->getDefault()); |
||
969 | self::assertSame('0', $columns['column4']->getDefault()); |
||
970 | self::assertSame('', $columns['column5']->getDefault()); |
||
971 | self::assertSame('def', $columns['column6']->getDefault()); |
||
972 | self::assertSame('0', $columns['column7']->getDefault()); |
||
973 | |||
974 | $diffTable = clone $table; |
||
975 | |||
976 | $diffTable->changeColumn('column1', array('default' => false)); |
||
977 | $diffTable->changeColumn('column2', array('default' => null)); |
||
978 | $diffTable->changeColumn('column3', array('default' => false)); |
||
979 | $diffTable->changeColumn('column4', array('default' => null)); |
||
980 | $diffTable->changeColumn('column5', array('default' => false)); |
||
981 | $diffTable->changeColumn('column6', array('default' => 666)); |
||
982 | $diffTable->changeColumn('column7', array('default' => null)); |
||
983 | |||
984 | $comparator = new Comparator(); |
||
985 | |||
986 | $this->_sm->alterTable($comparator->diffTable($table, $diffTable)); |
||
987 | |||
988 | $columns = $this->_sm->listTableColumns('col_def_lifecycle'); |
||
989 | |||
990 | self::assertSame('', $columns['column1']->getDefault()); |
||
991 | self::assertNull($columns['column2']->getDefault()); |
||
992 | self::assertSame('', $columns['column3']->getDefault()); |
||
993 | self::assertNull($columns['column4']->getDefault()); |
||
994 | self::assertSame('', $columns['column5']->getDefault()); |
||
995 | self::assertSame('666', $columns['column6']->getDefault()); |
||
996 | self::assertNull($columns['column7']->getDefault()); |
||
997 | } |
||
998 | |||
999 | View Code Duplication | public function testListTableWithBinary() |
|
1000 | { |
||
1001 | $tableName = 'test_binary_table'; |
||
1002 | |||
1003 | $table = new Table($tableName); |
||
1004 | $table->addColumn('id', 'integer'); |
||
1005 | $table->addColumn('column_varbinary', 'binary', array()); |
||
1006 | $table->addColumn('column_binary', 'binary', array('fixed' => true)); |
||
1007 | $table->setPrimaryKey(array('id')); |
||
1008 | |||
1009 | $this->_sm->createTable($table); |
||
1010 | |||
1011 | $table = $this->_sm->listTableDetails($tableName); |
||
1012 | |||
1013 | self::assertInstanceOf('Doctrine\DBAL\Types\BinaryType', $table->getColumn('column_varbinary')->getType()); |
||
1014 | self::assertFalse($table->getColumn('column_varbinary')->getFixed()); |
||
1015 | |||
1016 | self::assertInstanceOf('Doctrine\DBAL\Types\BinaryType', $table->getColumn('column_binary')->getType()); |
||
1017 | self::assertTrue($table->getColumn('column_binary')->getFixed()); |
||
1018 | } |
||
1019 | |||
1020 | public function testListTableDetailsWithFullQualifiedTableName() |
||
1021 | { |
||
1022 | if ( ! $this->_sm->getDatabasePlatform()->supportsSchemas()) { |
||
1023 | $this->markTestSkipped('Test only works on platforms that support schemas.'); |
||
1024 | } |
||
1025 | |||
1026 | $defaultSchemaName = $this->_sm->getDatabasePlatform()->getDefaultSchemaName(); |
||
1027 | $primaryTableName = 'primary_table'; |
||
1028 | $foreignTableName = 'foreign_table'; |
||
1029 | |||
1030 | $table = new Table($foreignTableName); |
||
1031 | $table->addColumn('id', 'integer', array('autoincrement' => true)); |
||
1032 | $table->setPrimaryKey(array('id')); |
||
1033 | |||
1034 | $this->_sm->dropAndCreateTable($table); |
||
1035 | |||
1036 | $table = new Table($primaryTableName); |
||
1037 | $table->addColumn('id', 'integer', array('autoincrement' => true)); |
||
1038 | $table->addColumn('foo', 'integer'); |
||
1039 | $table->addColumn('bar', 'string'); |
||
1040 | $table->addForeignKeyConstraint($foreignTableName, array('foo'), array('id')); |
||
1041 | $table->addIndex(array('bar')); |
||
1042 | $table->setPrimaryKey(array('id')); |
||
1043 | |||
1044 | $this->_sm->dropAndCreateTable($table); |
||
1045 | |||
1046 | self::assertEquals( |
||
1047 | $this->_sm->listTableColumns($primaryTableName), |
||
1048 | $this->_sm->listTableColumns($defaultSchemaName . '.' . $primaryTableName) |
||
1049 | ); |
||
1050 | self::assertEquals( |
||
1051 | $this->_sm->listTableIndexes($primaryTableName), |
||
1052 | $this->_sm->listTableIndexes($defaultSchemaName . '.' . $primaryTableName) |
||
1053 | ); |
||
1054 | self::assertEquals( |
||
1055 | $this->_sm->listTableForeignKeys($primaryTableName), |
||
1056 | $this->_sm->listTableForeignKeys($defaultSchemaName . '.' . $primaryTableName) |
||
1057 | ); |
||
1058 | } |
||
1059 | |||
1060 | public function testCommentStringsAreQuoted() |
||
1061 | { |
||
1062 | View Code Duplication | if ( ! $this->_conn->getDatabasePlatform()->supportsInlineColumnComments() && |
|
1063 | ! $this->_conn->getDatabasePlatform()->supportsCommentOnStatement() && |
||
1064 | $this->_conn->getDatabasePlatform()->getName() != 'mssql') { |
||
1065 | $this->markTestSkipped('Database does not support column comments.'); |
||
1066 | } |
||
1067 | |||
1068 | $table = new Table('my_table'); |
||
1069 | $table->addColumn('id', 'integer', array('comment' => "It's a comment with a quote")); |
||
1070 | $table->setPrimaryKey(array('id')); |
||
1071 | |||
1072 | $this->_sm->createTable($table); |
||
1073 | |||
1074 | $columns = $this->_sm->listTableColumns("my_table"); |
||
1075 | self::assertEquals("It's a comment with a quote", $columns['id']->getComment()); |
||
1076 | } |
||
1077 | |||
1078 | public function testCommentNotDuplicated() |
||
1079 | { |
||
1080 | if ( ! $this->_conn->getDatabasePlatform()->supportsInlineColumnComments()) { |
||
1081 | $this->markTestSkipped('Database does not support column comments.'); |
||
1082 | } |
||
1083 | |||
1084 | $options = array( |
||
1085 | 'type' => Type::getType('integer'), |
||
1086 | 'default' => 0, |
||
1087 | 'notnull' => true, |
||
1088 | 'comment' => 'expected+column+comment', |
||
1089 | ); |
||
1090 | $columnDefinition = substr($this->_conn->getDatabasePlatform()->getColumnDeclarationSQL('id', $options), strlen('id') + 1); |
||
1091 | |||
1092 | $table = new Table('my_table'); |
||
1093 | $table->addColumn('id', 'integer', array('columnDefinition' => $columnDefinition, 'comment' => 'unexpected_column_comment')); |
||
1094 | $sql = $this->_conn->getDatabasePlatform()->getCreateTableSQL($table); |
||
1095 | |||
1096 | self::assertContains('expected+column+comment', $sql[0]); |
||
1097 | self::assertNotContains('unexpected_column_comment', $sql[0]); |
||
1098 | } |
||
1099 | |||
1100 | /** |
||
1101 | * @group DBAL-1009 |
||
1102 | * |
||
1103 | * @dataProvider getAlterColumnComment |
||
1104 | */ |
||
1105 | public function testAlterColumnComment($comment1, $expectedComment1, $comment2, $expectedComment2) |
||
1106 | { |
||
1107 | View Code Duplication | if ( ! $this->_conn->getDatabasePlatform()->supportsInlineColumnComments() && |
|
1108 | ! $this->_conn->getDatabasePlatform()->supportsCommentOnStatement() && |
||
1109 | $this->_conn->getDatabasePlatform()->getName() != 'mssql') { |
||
1110 | $this->markTestSkipped('Database does not support column comments.'); |
||
1111 | } |
||
1112 | |||
1113 | $offlineTable = new Table('alter_column_comment_test'); |
||
1114 | $offlineTable->addColumn('comment1', 'integer', array('comment' => $comment1)); |
||
1115 | $offlineTable->addColumn('comment2', 'integer', array('comment' => $comment2)); |
||
1116 | $offlineTable->addColumn('no_comment1', 'integer'); |
||
1117 | $offlineTable->addColumn('no_comment2', 'integer'); |
||
1118 | $this->_sm->dropAndCreateTable($offlineTable); |
||
1119 | |||
1120 | $onlineTable = $this->_sm->listTableDetails("alter_column_comment_test"); |
||
1121 | |||
1122 | self::assertSame($expectedComment1, $onlineTable->getColumn('comment1')->getComment()); |
||
1123 | self::assertSame($expectedComment2, $onlineTable->getColumn('comment2')->getComment()); |
||
1124 | self::assertNull($onlineTable->getColumn('no_comment1')->getComment()); |
||
1125 | self::assertNull($onlineTable->getColumn('no_comment2')->getComment()); |
||
1126 | |||
1127 | $onlineTable->changeColumn('comment1', array('comment' => $comment2)); |
||
1128 | $onlineTable->changeColumn('comment2', array('comment' => $comment1)); |
||
1129 | $onlineTable->changeColumn('no_comment1', array('comment' => $comment1)); |
||
1130 | $onlineTable->changeColumn('no_comment2', array('comment' => $comment2)); |
||
1131 | |||
1132 | $comparator = new Comparator(); |
||
1133 | |||
1134 | $tableDiff = $comparator->diffTable($offlineTable, $onlineTable); |
||
1135 | |||
1136 | self::assertInstanceOf('Doctrine\DBAL\Schema\TableDiff', $tableDiff); |
||
1137 | |||
1138 | $this->_sm->alterTable($tableDiff); |
||
1139 | |||
1140 | $onlineTable = $this->_sm->listTableDetails("alter_column_comment_test"); |
||
1141 | |||
1142 | self::assertSame($expectedComment2, $onlineTable->getColumn('comment1')->getComment()); |
||
1143 | self::assertSame($expectedComment1, $onlineTable->getColumn('comment2')->getComment()); |
||
1144 | self::assertSame($expectedComment1, $onlineTable->getColumn('no_comment1')->getComment()); |
||
1145 | self::assertSame($expectedComment2, $onlineTable->getColumn('no_comment2')->getComment()); |
||
1146 | } |
||
1147 | |||
1148 | public function getAlterColumnComment() |
||
1149 | { |
||
1150 | return array( |
||
1151 | array(null, null, ' ', ' '), |
||
1152 | array(null, null, '0', '0'), |
||
1153 | array(null, null, 'foo', 'foo'), |
||
1154 | |||
1155 | array('', null, ' ', ' '), |
||
1156 | array('', null, '0', '0'), |
||
1157 | array('', null, 'foo', 'foo'), |
||
1158 | |||
1159 | array(' ', ' ', '0', '0'), |
||
1160 | array(' ', ' ', 'foo', 'foo'), |
||
1161 | |||
1162 | array('0', '0', 'foo', 'foo'), |
||
1163 | ); |
||
1164 | } |
||
1165 | |||
1166 | /** |
||
1167 | * @group DBAL-1095 |
||
1168 | */ |
||
1169 | public function testDoesNotListIndexesImplicitlyCreatedByForeignKeys() |
||
1170 | { |
||
1171 | if (! $this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) { |
||
1172 | $this->markTestSkipped('This test is only supported on platforms that have foreign keys.'); |
||
1173 | } |
||
1174 | |||
1175 | $primaryTable = new Table('test_list_index_impl_primary'); |
||
1176 | $primaryTable->addColumn('id', 'integer'); |
||
1177 | $primaryTable->setPrimaryKey(array('id')); |
||
1178 | |||
1179 | $foreignTable = new Table('test_list_index_impl_foreign'); |
||
1180 | $foreignTable->addColumn('fk1', 'integer'); |
||
1181 | $foreignTable->addColumn('fk2', 'integer'); |
||
1182 | $foreignTable->addIndex(array('fk1'), 'explicit_fk1_idx'); |
||
1183 | $foreignTable->addForeignKeyConstraint('test_list_index_impl_primary', array('fk1'), array('id')); |
||
1184 | $foreignTable->addForeignKeyConstraint('test_list_index_impl_primary', array('fk2'), array('id')); |
||
1185 | |||
1186 | $this->_sm->dropAndCreateTable($primaryTable); |
||
1187 | $this->_sm->dropAndCreateTable($foreignTable); |
||
1188 | |||
1189 | $indexes = $this->_sm->listTableIndexes('test_list_index_impl_foreign'); |
||
1190 | |||
1191 | self::assertCount(2, $indexes); |
||
1192 | self::assertArrayHasKey('explicit_fk1_idx', $indexes); |
||
1193 | self::assertArrayHasKey('idx_3d6c147fdc58d6c', $indexes); |
||
1194 | } |
||
1195 | |||
1196 | /** |
||
1197 | * @after |
||
1198 | */ |
||
1199 | public function removeJsonArrayTable() : void |
||
1200 | { |
||
1201 | if ($this->_sm->tablesExist(['json_array_test'])) { |
||
1202 | $this->_sm->dropTable('json_array_test'); |
||
1203 | } |
||
1204 | } |
||
1205 | |||
1206 | /** |
||
1207 | * @group 2782 |
||
1208 | * @group 6654 |
||
1209 | */ |
||
1210 | View Code Duplication | public function testComparatorShouldReturnFalseWhenLegacyJsonArrayColumnHasComment() : void |
|
0 ignored issues
–
show
|
|||
1211 | { |
||
1212 | $table = new Table('json_array_test'); |
||
1213 | $table->addColumn('parameters', 'json_array'); |
||
1214 | |||
1215 | $this->_sm->createTable($table); |
||
1216 | |||
1217 | $comparator = new Comparator(); |
||
1218 | $tableDiff = $comparator->diffTable($this->_sm->listTableDetails('json_array_test'), $table); |
||
1219 | |||
1220 | self::assertFalse($tableDiff); |
||
1221 | } |
||
1222 | |||
1223 | /** |
||
1224 | * @group 2782 |
||
1225 | * @group 6654 |
||
1226 | */ |
||
1227 | public function testComparatorShouldModifyOnlyTheCommentWhenUpdatingFromJsonArrayTypeOnLegacyPlatforms() : void |
||
1228 | { |
||
1229 | if ($this->_sm->getDatabasePlatform()->hasNativeJsonType()) { |
||
1230 | $this->markTestSkipped('This test is only supported on platforms that do not have native JSON type.'); |
||
1231 | } |
||
1232 | |||
1233 | $table = new Table('json_array_test'); |
||
1234 | $table->addColumn('parameters', 'json_array'); |
||
1235 | |||
1236 | $this->_sm->createTable($table); |
||
1237 | |||
1238 | $table = new Table('json_array_test'); |
||
1239 | $table->addColumn('parameters', 'json'); |
||
1240 | |||
1241 | $comparator = new Comparator(); |
||
1242 | $tableDiff = $comparator->diffTable($this->_sm->listTableDetails('json_array_test'), $table); |
||
1243 | |||
1244 | self::assertInstanceOf(TableDiff::class, $tableDiff); |
||
1245 | |||
1246 | $changedColumn = $tableDiff->changedColumns['parameters'] ?? $tableDiff->changedColumns['PARAMETERS']; |
||
1247 | |||
1248 | self::assertSame(['comment'], $changedColumn->changedProperties); |
||
1249 | } |
||
1250 | |||
1251 | /** |
||
1252 | * @group 2782 |
||
1253 | * @group 6654 |
||
1254 | */ |
||
1255 | View Code Duplication | public function testComparatorShouldAddCommentToLegacyJsonArrayTypeThatDoesNotHaveIt() : void |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
1256 | { |
||
1257 | if ( ! $this->_sm->getDatabasePlatform()->hasNativeJsonType()) { |
||
1258 | $this->markTestSkipped('This test is only supported on platforms that have native JSON type.'); |
||
1259 | } |
||
1260 | |||
1261 | $this->_conn->executeQuery('CREATE TABLE json_array_test (parameters JSON NOT NULL)'); |
||
1262 | |||
1263 | $table = new Table('json_array_test'); |
||
1264 | $table->addColumn('parameters', 'json_array'); |
||
1265 | |||
1266 | $comparator = new Comparator(); |
||
1267 | $tableDiff = $comparator->diffTable($this->_sm->listTableDetails('json_array_test'), $table); |
||
1268 | |||
1269 | self::assertInstanceOf(TableDiff::class, $tableDiff); |
||
1270 | self::assertSame(['comment'], $tableDiff->changedColumns['parameters']->changedProperties); |
||
1271 | } |
||
1272 | |||
1273 | /** |
||
1274 | * @group 2782 |
||
1275 | * @group 6654 |
||
1276 | */ |
||
1277 | View Code Duplication | public function testComparatorShouldReturnAllChangesWhenUsingLegacyJsonArrayType() : void |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
1278 | { |
||
1279 | if ( ! $this->_sm->getDatabasePlatform()->hasNativeJsonType()) { |
||
1280 | $this->markTestSkipped('This test is only supported on platforms that have native JSON type.'); |
||
1281 | } |
||
1282 | |||
1283 | $this->_conn->executeQuery('CREATE TABLE json_array_test (parameters JSON DEFAULT NULL)'); |
||
1284 | |||
1285 | $table = new Table('json_array_test'); |
||
1286 | $table->addColumn('parameters', 'json_array'); |
||
1287 | |||
1288 | $comparator = new Comparator(); |
||
1289 | $tableDiff = $comparator->diffTable($this->_sm->listTableDetails('json_array_test'), $table); |
||
1290 | |||
1291 | self::assertInstanceOf(TableDiff::class, $tableDiff); |
||
1292 | self::assertSame(['notnull', 'comment'], $tableDiff->changedColumns['parameters']->changedProperties); |
||
1293 | } |
||
1294 | |||
1295 | /** |
||
1296 | * @group 2782 |
||
1297 | * @group 6654 |
||
1298 | */ |
||
1299 | View Code Duplication | public function testComparatorShouldReturnAllChangesWhenUsingLegacyJsonArrayTypeEvenWhenPlatformHasJsonSupport() : void |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
1300 | { |
||
1301 | if ( ! $this->_sm->getDatabasePlatform()->hasNativeJsonType()) { |
||
1302 | $this->markTestSkipped('This test is only supported on platforms that have native JSON type.'); |
||
1303 | } |
||
1304 | |||
1305 | $this->_conn->executeQuery('CREATE TABLE json_array_test (parameters JSON DEFAULT NULL)'); |
||
1306 | |||
1307 | $table = new Table('json_array_test'); |
||
1308 | $table->addColumn('parameters', 'json_array'); |
||
1309 | |||
1310 | $comparator = new Comparator(); |
||
1311 | $tableDiff = $comparator->diffTable($this->_sm->listTableDetails('json_array_test'), $table); |
||
1312 | |||
1313 | self::assertInstanceOf(TableDiff::class, $tableDiff); |
||
1314 | self::assertSame(['notnull', 'comment'], $tableDiff->changedColumns['parameters']->changedProperties); |
||
1315 | } |
||
1316 | |||
1317 | /** |
||
1318 | * @group 2782 |
||
1319 | * @group 6654 |
||
1320 | */ |
||
1321 | public function testComparatorShouldNotAddCommentToJsonTypeSinceItIsTheDefaultNow() : void |
||
1322 | { |
||
1323 | if ( ! $this->_sm->getDatabasePlatform()->hasNativeJsonType()) { |
||
1324 | $this->markTestSkipped('This test is only supported on platforms that have native JSON type.'); |
||
1325 | } |
||
1326 | |||
1327 | $this->_conn->executeQuery('CREATE TABLE json_test (parameters JSON NOT NULL)'); |
||
1328 | |||
1329 | $table = new Table('json_test'); |
||
1330 | $table->addColumn('parameters', 'json'); |
||
1331 | |||
1332 | $comparator = new Comparator(); |
||
1333 | $tableDiff = $comparator->diffTable($this->_sm->listTableDetails('json_test'), $table); |
||
1334 | |||
1335 | self::assertFalse($tableDiff); |
||
1336 | } |
||
1337 | } |
||
1338 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.