From 342578b1cdcb004236be9186a88bae544f7ae32d Mon Sep 17 00:00:00 2001 From: Hamid Alaei V Date: Wed, 12 Oct 2016 23:47:18 +0330 Subject: [PATCH] roll back to a given transaction level (savepoint). Dont fire event on redundant rollBack() --- src/Illuminate/Database/Connection.php | 20 +++++++++++++++----- tests/Database/DatabaseConnectionTest.php | 11 +++++++++++ 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Database/Connection.php b/src/Illuminate/Database/Connection.php index e920e8fa4918..0600b5bf6bb8 100755 --- a/src/Illuminate/Database/Connection.php +++ b/src/Illuminate/Database/Connection.php @@ -639,19 +639,29 @@ public function commit() /** * Rollback the active database transaction. * + * @param int|null $toLevel * @return void */ - public function rollBack() + public function rollBack($toLevel = null) { - if ($this->transactions == 1) { + if (is_null($toLevel)) { + $toLevel = $this->transactions - 1; + } + + if ($toLevel < 0 || $toLevel >= $this->transactions) { + // Ignore + return; + } + + if ($toLevel == 0) { $this->getPdo()->rollBack(); - } elseif ($this->transactions > 1 && $this->queryGrammar->supportsSavepoints()) { + } elseif ($this->queryGrammar->supportsSavepoints()) { $this->getPdo()->exec( - $this->queryGrammar->compileSavepointRollBack('trans'.$this->transactions) + $this->queryGrammar->compileSavepointRollBack('trans'.($toLevel + 1)) ); } - $this->transactions = max(0, $this->transactions - 1); + $this->transactions = $toLevel; $this->fireConnectionEvent('rollingBack'); } diff --git a/tests/Database/DatabaseConnectionTest.php b/tests/Database/DatabaseConnectionTest.php index 71b74c1b2049..35ced375392e 100755 --- a/tests/Database/DatabaseConnectionTest.php +++ b/tests/Database/DatabaseConnectionTest.php @@ -160,11 +160,22 @@ public function testRollBackedFiresEventsIfSet() $pdo = $this->createMock('DatabaseConnectionTestMockPDO'); $connection = $this->getMockConnection(['getName'], $pdo); $connection->expects($this->any())->method('getName')->will($this->returnValue('name')); + $connection->beginTransaction(); $connection->setEventDispatcher($events = m::mock('Illuminate\Contracts\Events\Dispatcher')); $events->shouldReceive('fire')->once()->with(m::type('Illuminate\Database\Events\TransactionRolledBack')); $connection->rollBack(); } + public function testRedundantRollBackFiresNoEvent() + { + $pdo = $this->createMock('DatabaseConnectionTestMockPDO'); + $connection = $this->getMockConnection(['getName'], $pdo); + $connection->expects($this->any())->method('getName')->will($this->returnValue('name')); + $connection->setEventDispatcher($events = m::mock('Illuminate\Contracts\Events\Dispatcher')); + $events->shouldNotReceive('fire'); + $connection->rollBack(); + } + public function testTransactionMethodRunsSuccessfully() { $pdo = $this->getMockBuilder('DatabaseConnectionTestMockPDO')->setMethods(['beginTransaction', 'commit'])->getMock();