TYPO3 CMS  TYPO3_8-7
SchemaMigratorTest.php
Go to the documentation of this file.
1 <?php
2 declare(strict_types = 1);
3 
5 
6 /*
7  * This file is part of the TYPO3 CMS project.
8  *
9  * It is free software; you can redistribute it and/or modify it under
10  * the terms of the GNU General Public License, either version 2
11  * of the License, or any later version.
12  *
13  * For the full copyright and license information, please read the
14  * LICENSE.txt file that was distributed with this source code.
15  *
16  * The TYPO3 project - inspiring people to share!
17  */
18 
27 
31 class SchemaMigratorTest extends \TYPO3\TestingFramework\Core\Functional\FunctionalTestCase
32 {
36  protected $sqlReader;
37 
41  protected $connectionPool;
42 
46  protected $schemaManager;
47 
51  protected $subject;
52 
56  protected $tableName = 'a_test_table';
57 
61  protected function setUp()
62  {
63  parent::setUp();
64  $this->subject = GeneralUtility::makeInstance(SchemaMigrator::class);
65  $this->sqlReader = GeneralUtility::makeInstance(SqlReader::class);
66  $this->connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
67  $this->schemaManager = $this->connectionPool->getConnectionForTable($this->tableName)->getSchemaManager();
68  $this->prepareTestTable();
69  }
70 
74  protected function tearDown()
75  {
76  parent::tearDown();
77 
78  if ($this->schemaManager->tablesExist([$this->tableName])) {
79  $this->schemaManager->dropTable($this->tableName);
80  }
81  if ($this->schemaManager->tablesExist(['zzz_deleted_' . $this->tableName])) {
82  $this->schemaManager->dropTable('zzz_deleted_' . $this->tableName);
83  }
84  if ($this->schemaManager->tablesExist(['another_test_table'])) {
85  $this->schemaManager->dropTable('another_test_table');
86  }
87  }
88 
92  public function createNewTable()
93  {
94  if ($this->schemaManager->tablesExist([$this->tableName])) {
95  $this->schemaManager->dropTable($this->tableName);
96  }
97 
98  $statements = $this->readFixtureFile('newTable');
99  $updateSuggestions = $this->subject->getUpdateSuggestions($statements);
100 
101  $this->subject->migrate(
102  $statements,
103  $updateSuggestions[ConnectionPool::DEFAULT_CONNECTION_NAME]['create_table']
104  );
105 
106  $this->assertCount(6, $this->getTableDetails()->getColumns());
107  }
108 
112  public function createNewTableIfNotExists()
113  {
114  $statements = $this->readFixtureFile('ifNotExists');
115  $updateSuggestions = $this->subject->getUpdateSuggestions($statements);
116 
117  $this->subject->migrate(
118  $statements,
119  $updateSuggestions[ConnectionPool::DEFAULT_CONNECTION_NAME]['create_table']
120  );
121 
122  $this->assertTrue($this->schemaManager->tablesExist(['another_test_table']));
123  }
124 
128  public function addNewColumns()
129  {
130  $statements = $this->readFixtureFile('addColumnsToTable');
131  $updateSuggestions = $this->subject->getUpdateSuggestions($statements);
132 
133  $this->subject->migrate(
134  $statements,
135  $updateSuggestions[ConnectionPool::DEFAULT_CONNECTION_NAME]['add']
136  );
137 
138  $this->assertCount(7, $this->getTableDetails()->getColumns());
139  $this->assertTrue($this->getTableDetails()->hasColumn('title'));
140  $this->assertTrue($this->getTableDetails()->hasColumn('description'));
141  }
142 
146  public function changeExistingColumn()
147  {
148  $statements = $this->readFixtureFile('changeExistingColumn');
149  $updateSuggestions = $this->subject->getUpdateSuggestions($statements);
150 
151  $this->assertEquals(50, $this->getTableDetails()->getColumn('title')->getLength());
152  $this->assertEmpty($this->getTableDetails()->getColumn('title')->getDefault());
153 
154  $this->subject->migrate(
155  $statements,
156  $updateSuggestions[ConnectionPool::DEFAULT_CONNECTION_NAME]['change']
157  );
158 
159  $this->assertEquals(100, $this->getTableDetails()->getColumn('title')->getLength());
160  $this->assertEquals('Title', $this->getTableDetails()->getColumn('title')->getDefault());
161  }
162 
166  public function notNullWithoutDefaultValue()
167  {
168  $statements = $this->readFixtureFile('notNullWithoutDefaultValue');
169  $updateSuggestions = $this->subject->getUpdateSuggestions($statements);
170 
171  $this->subject->migrate(
172  $statements,
173  $updateSuggestions[ConnectionPool::DEFAULT_CONNECTION_NAME]['add']
174  );
175 
176  $updateSuggestions = $this->subject->getUpdateSuggestions($statements);
177  $this->assertEmpty($updateSuggestions[ConnectionPool::DEFAULT_CONNECTION_NAME]['change']);
178  $this->assertTrue($this->getTableDetails()->getColumn('aTestField')->getNotnull());
179  }
180 
184  public function defaultNullWithoutNotNull()
185  {
186  $statements = $this->readFixtureFile('defaultNullWithoutNotNull');
187  $updateSuggestions = $this->subject->getUpdateSuggestions($statements);
188 
189  $this->subject->migrate(
190  $statements,
191  $updateSuggestions[ConnectionPool::DEFAULT_CONNECTION_NAME]['add']
192  );
193 
194  $updateSuggestions = $this->subject->getUpdateSuggestions($statements);
195  $this->assertEmpty($updateSuggestions[ConnectionPool::DEFAULT_CONNECTION_NAME]['change']);
196  $this->assertFalse($this->getTableDetails()->getColumn('aTestField')->getNotnull());
197  $this->assertNull($this->getTableDetails()->getColumn('aTestField')->getDefault());
198  }
199 
205  public function renameUnusedField()
206  {
207  $statements = $this->readFixtureFile('unusedColumn');
208  $updateSuggestions = $this->subject->getUpdateSuggestions($statements, true);
209 
210  $this->subject->migrate(
211  $statements,
212  $updateSuggestions[ConnectionPool::DEFAULT_CONNECTION_NAME]['change']
213  );
214 
215  $this->assertFalse($this->getTableDetails()->hasColumn('hidden'));
216  $this->assertTrue($this->getTableDetails()->hasColumn('zzz_deleted_hidden'));
217  }
218 
222  public function renameUnusedTable()
223  {
224  $statements = $this->readFixtureFile('unusedTable');
225  $updateSuggestions = $this->subject->getUpdateSuggestions($statements, true);
226 
227  $this->subject->migrate(
228  $statements,
229  $updateSuggestions[ConnectionPool::DEFAULT_CONNECTION_NAME]['change_table']
230  );
231 
232  $this->assertNotContains($this->tableName, $this->schemaManager->listTableNames());
233  $this->assertContains('zzz_deleted_' . $this->tableName, $this->schemaManager->listTableNames());
234  }
235 
239  public function dropUnusedField()
240  {
241  $connection = $this->connectionPool->getConnectionForTable($this->tableName);
242  $fromSchema = $this->schemaManager->createSchema();
243  $toSchema = clone $fromSchema;
244  $toSchema->getTable($this->tableName)->addColumn('zzz_deleted_testfield', 'integer');
245  $statements = $fromSchema->getMigrateToSql(
246  $toSchema,
247  $connection->getDatabasePlatform()
248  );
249  $connection->executeUpdate($statements[0]);
250  $this->assertTrue($this->getTableDetails()->hasColumn('zzz_deleted_testfield'));
251 
252  $statements = $this->readFixtureFile('newTable');
253  $updateSuggestions = $this->subject->getUpdateSuggestions($statements, true);
254  $this->subject->migrate(
255  $statements,
256  $updateSuggestions[ConnectionPool::DEFAULT_CONNECTION_NAME]['drop']
257  );
258 
259  $this->assertFalse($this->getTableDetails()->hasColumn('zzz_deleted_testfield'));
260  }
261 
265  public function dropUnusedTable()
266  {
267  $this->schemaManager->renameTable($this->tableName, 'zzz_deleted_' . $this->tableName);
268  $this->assertNotContains($this->tableName, $this->schemaManager->listTableNames());
269  $this->assertContains('zzz_deleted_' . $this->tableName, $this->schemaManager->listTableNames());
270 
271  $statements = $this->readFixtureFile('newTable');
272  $updateSuggestions = $this->subject->getUpdateSuggestions($statements, true);
273  $this->subject->migrate(
274  $statements,
275  $updateSuggestions[ConnectionPool::DEFAULT_CONNECTION_NAME]['drop_table']
276  );
277 
278  $this->assertNotContains($this->tableName, $this->schemaManager->listTableNames());
279  $this->assertNotContains('zzz_deleted_' . $this->tableName, $this->schemaManager->listTableNames());
280  }
281 
287  {
288  $statements = $this->readFixtureFile('addCreateChange');
289  $this->subject->install($statements, true);
290 
291  $this->assertContains('another_test_table', $this->schemaManager->listTableNames());
292  $this->assertTrue($this->getTableDetails()->hasColumn('title'));
293  $this->assertTrue($this->getTableDetails()->hasIndex('title'));
294  $this->assertTrue($this->getTableDetails()->getIndex('title')->isUnique());
295  $this->assertNotInstanceOf(BigIntType::class, $this->getTableDetails()->getColumn('pid')->getType());
296  }
297 
302  {
303  $statements = $this->readFixtureFile('addIndexOnChangedColumn');
304  $this->subject->install($statements, true);
305 
306  $this->assertNotInstanceOf(TextType::class, $this->getTableDetails()->getColumn('title')->getType());
307  $this->assertFalse($this->getTableDetails()->hasIndex('title'));
308  }
309 
316  {
317  $statements = $this->readFixtureFile('addCreateChange');
318  $this->subject->install($statements);
319 
320  $this->assertContains('another_test_table', $this->schemaManager->listTableNames());
321  $this->assertTrue($this->getTableDetails()->hasColumn('title'));
322  $this->assertTrue($this->getTableDetails()->hasIndex('title'));
323  $this->assertTrue($this->getTableDetails()->getIndex('title')->isUnique());
324  $this->assertInstanceOf(BigIntType::class, $this->getTableDetails()->getColumn('pid')->getType());
325  }
326 
333  {
334  $sqlCode = file_get_contents(implode(DIRECTORY_SEPARATOR, [__DIR__, '..', 'Fixtures', 'importStaticData.sql']));
335  $connection = $this->connectionPool->getConnectionForTable($this->tableName);
336  $statements = $this->sqlReader->getInsertStatementArray($sqlCode);
337  $this->subject->importStaticData($statements);
338 
339  $this->assertEquals(2, $connection->count('*', $this->tableName, []));
340  }
341 
346  {
347  $sqlCode = file_get_contents(implode(DIRECTORY_SEPARATOR, [__DIR__, '..', 'Fixtures', 'importStaticData.sql']));
348  $statements = $this->sqlReader->getStatementArray($sqlCode);
349  $this->subject->importStaticData($statements);
350 
351  $this->assertNotContains('another_test_table', $this->schemaManager->listTableNames());
352  }
353 
359  public function changeTableEngine()
360  {
361  $statements = $this->readFixtureFile('alterTableEngine');
362  $updateSuggestions = $this->subject->getUpdateSuggestions($statements);
363 
364  $index = array_keys($updateSuggestions[ConnectionPool::DEFAULT_CONNECTION_NAME]['change'])[0];
365  $this->assertStringEndsWith(
366  'ENGINE = MyISAM',
367  $updateSuggestions[ConnectionPool::DEFAULT_CONNECTION_NAME]['change'][$index]
368  );
369 
370  $this->subject->migrate(
371  $statements,
372  $updateSuggestions[ConnectionPool::DEFAULT_CONNECTION_NAME]['change']
373  );
374 
375  $updateSuggestions = $this->subject->getUpdateSuggestions($statements);
376  $this->assertEmpty($updateSuggestions[ConnectionPool::DEFAULT_CONNECTION_NAME]['change']);
377  $this->assertEmpty($updateSuggestions[ConnectionPool::DEFAULT_CONNECTION_NAME]['change']);
378  }
379 
383  protected function prepareTestTable()
384  {
385  $statements = $this->readFixtureFile('newTable');
386  $this->subject->install($statements, true);
387  }
388 
394  protected function getTableDetails(): Table
395  {
396  return $this->schemaManager->listTableDetails($this->tableName);
397  }
398 
405  protected function readFixtureFile(string $fixtureName): array
406  {
407  $sqlCode = file_get_contents(implode(DIRECTORY_SEPARATOR, [__DIR__, '..', 'Fixtures', $fixtureName]) . '.sql');
408 
409  return $this->sqlReader->getCreateTableStatementArray($sqlCode);
410  }
411 }
static makeInstance($className,... $constructorArguments)