Skip to content

Commit ef8926c

Browse files
committed
Fix(migrations) Handle transaction within migrations
This fixes #98
1 parent f47a790 commit ef8926c

File tree

6 files changed

+127
-24
lines changed

6 files changed

+127
-24
lines changed

lib/Doctrine/Export.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -1221,7 +1221,7 @@ public function exportClasses(array $classes)
12211221
}
12221222
}
12231223

1224-
$connection->commit();
1224+
Doctrine_TransactionHelper::commitIfInTransaction($connection);
12251225
}
12261226
}
12271227

lib/Doctrine/Migration.php

+20-23
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ public function loadMigrationClass($name, $path = null)
187187
}
188188

189189
if ($class === false) {
190-
return false;
190+
return;
191191
}
192192

193193
if (empty($this->_migrationClasses)) {
@@ -307,15 +307,13 @@ public function getNextMigrationClassVersion()
307307
*
308308
* @param integer $to Version to migrate to
309309
* @param boolean $dryRun Whether or not to run the migrate process as a dry run
310-
* @return integer $to Version number migrated to
310+
* @return bool True if the migration succeeded, false otherwise
311311
* @throws Doctrine_Exception
312312
*/
313313
public function migrate($to = null, $dryRun = false)
314314
{
315315
$this->clearErrors();
316-
317316
$this->_createMigrationTable();
318-
319317
$this->_connection->beginTransaction();
320318

321319
try {
@@ -335,24 +333,22 @@ public function migrate($to = null, $dryRun = false)
335333

336334
if ($dryRun) {
337335
return false;
338-
} else {
339-
$this->_throwErrorsException();
340-
}
341-
} else {
342-
if ($dryRun) {
343-
$this->_connection->rollback();
344-
if ($this->hasErrors()) {
345-
return false;
346-
} else {
347-
return $to;
348-
}
349-
} else {
350-
$this->_connection->commit();
351-
$this->setCurrentVersion($to);
352-
return $to;
353336
}
337+
338+
$this->_throwErrorsException();
354339
}
355-
return false;
340+
341+
342+
if ($dryRun) {
343+
$this->_connection->rollback();
344+
345+
return !$this->hasErrors();
346+
}
347+
348+
Doctrine_TransactionHelper::commitIfInTransaction($this->_connection);
349+
$this->setCurrentVersion($to);
350+
351+
return true;
356352
}
357353

358354
/**
@@ -437,8 +433,9 @@ public function getMigrationClass($num)
437433
/**
438434
* Throw an exception with all the errors trigged during the migration
439435
*
440-
* @return void
441-
* @throws Doctrine_Migration_Exception $e
436+
* @throws Doctrine_Migration_Exception
437+
*
438+
* @return never
442439
*/
443440
protected function _throwErrorsException()
444441
{
@@ -559,4 +556,4 @@ protected function _createMigrationTable()
559556
return false;
560557
}
561558
}
562-
}
559+
}

lib/Doctrine/TransactionHelper.php

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
/**
4+
* Helper for transactions handling.
5+
*
6+
* @author Kyle McGrogan <[email protected]>
7+
*/
8+
final class Doctrine_TransactionHelper
9+
{
10+
/**
11+
* Execute a commit on the given connection, only if a transaction already started.
12+
*/
13+
public static function commitIfInTransaction(Doctrine_Connection $connection): void
14+
{
15+
$handler = $connection->getDbh();
16+
17+
// Attempt to commit while no transaction is running results in exception since PHP 8 + pdo_mysql combination
18+
if ($handler instanceof PDO && !$handler->inTransaction()) {
19+
return;
20+
}
21+
22+
$connection->commit();
23+
}
24+
}

tests/DoctrineTest/Doctrine_UnitTestCase.php

+13
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ public function init()
216216
}
217217
}
218218
}
219+
219220
public function prepareTables() {
220221
foreach($this->tables as $name) {
221222
$name = ucwords($name);
@@ -230,6 +231,7 @@ public function prepareTables() {
230231
$this->conn->export->exportClasses($this->tables);
231232
$this->objTable = $this->connection->getTable('User');
232233
}
234+
233235
public function prepareData()
234236
{
235237
$groups = new Doctrine_Collection($this->connection->getTable('Group'));
@@ -307,6 +309,17 @@ public function getDeclaration($type)
307309
return $this->dataDict->getPortableDeclaration(array('type' => $type, 'name' => 'colname', 'length' => 1, 'fixed' => true));
308310
}
309311

312+
/**
313+
* @param string $pdoDsn
314+
* @return Doctrine_Connection
315+
*/
316+
protected function openAdditionalPdoConnection(string $pdoDsn)
317+
{
318+
$pdoFromDsn = new PDO($pdoDsn);
319+
320+
return $this->openAdditionalConnection($pdoFromDsn);
321+
}
322+
310323
protected function openAdditionalConnection($adapter = null, $name = null)
311324
{
312325
$connection = $this->manager->openConnection($adapter, $name);

tests/MigrationMysqlTestCase.php

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
/*
3+
* $Id$
4+
*
5+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
6+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
7+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
8+
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
9+
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
10+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
11+
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
12+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
13+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
15+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16+
*
17+
* This software consists of voluntary contributions made by many individuals
18+
* and is licensed under the LGPL. For more information, see
19+
* <http://www.doctrine-project.org>.
20+
*/
21+
22+
/**
23+
* Doctrine_Migration_TestCase
24+
*
25+
* @package Doctrine
26+
* @author Konsta Vesterinen <[email protected]>
27+
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
28+
* @category Object Relational Mapping
29+
* @link www.doctrine-project.org
30+
* @since 1.0
31+
* @version $Revision$
32+
*/
33+
class Doctrine_MigrationMysql_TestCase extends Doctrine_UnitTestCase
34+
{
35+
public function setUp()
36+
{
37+
parent::setUp();
38+
$dsn = getenv('MYSQL_TEST_DSN') ?? '';
39+
40+
$this->connection = $this->openAdditionalPdoConnection($dsn);
41+
$this->connection->setOption('dsn', $dsn);
42+
$this->connection->dropDatabase();
43+
$this->connection->createDatabase();
44+
}
45+
46+
public function testAfterSuccessfullMigrationItWillSetMigratedVersionAsCurrentVersionInMysqlDB()
47+
{
48+
$migration = new Doctrine_Migration(__DIR__.'/migration_classes', $this->connection);
49+
$this->assertFalse($migration->hasMigrated());
50+
$migration->setCurrentVersion(0);
51+
$this->assertFalse($this->connection->import->tableExists('migration_phonenumber'));
52+
$this->assertFalse($this->connection->import->tableExists('migration_user'));
53+
$this->assertFalse($this->connection->import->tableExists('migration_profile'));
54+
55+
$migration->migrate(3);
56+
$this->assertTrue($migration->hasMigrated());
57+
$this->assertEqual($migration->getCurrentVersion(), 3);
58+
$this->assertTrue($this->connection->import->tableExists('migration_phonenumber'));
59+
$this->assertTrue($this->connection->import->tableExists('migration_user'));
60+
$this->assertTrue($this->connection->import->tableExists('migration_profile'));
61+
62+
$migration->migrate(4);
63+
$this->assertEqual($migration->getCurrentVersion(), 4);
64+
$this->assertTrue($this->connection->import->tableExists('migration_phonenumber'));
65+
$this->assertTrue($this->connection->import->tableExists('migration_user'));
66+
$this->assertFalse($this->connection->import->tableExists('migration_profile'));
67+
}
68+
}

tests/run.php

+1
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@
279279
// Migration Tests
280280
$migration = new GroupTest('Migration Tests', 'migration');
281281
$migration->addTestCase(new Doctrine_Migration_TestCase());
282+
$migration->addTestCase(new Doctrine_MigrationMysql_TestCase());
282283
$migration->addTestCase(new Doctrine_Migration_Base_TestCase());
283284
$migration->addTestCase(new Doctrine_Migration_Diff_TestCase());
284285
$test->addTestCase($migration);

0 commit comments

Comments
 (0)