From a50e904fcf26e02ffc1c2d9e20f5433428787f7a Mon Sep 17 00:00:00 2001 From: Francisco Neves Date: Sat, 7 Sep 2019 12:06:02 +0100 Subject: [PATCH] Fix #27 --- src/Neves/Events/TransactionalDispatcher.php | 22 ++++++++++ tests/TransactionalDispatcherTest.php | 45 ++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/src/Neves/Events/TransactionalDispatcher.php b/src/Neves/Events/TransactionalDispatcher.php index 0c3decc922..3eed56a668 100644 --- a/src/Neves/Events/TransactionalDispatcher.php +++ b/src/Neves/Events/TransactionalDispatcher.php @@ -158,6 +158,10 @@ protected function addPendingEvent($event, $payload) : void */ private function onTransactionCommit() : void { + if (! $this->isTransactionRunning()) { + return; + } + $committedTransaction = $this->finishTransaction(); if (! $committedTransaction->isRoot()) { @@ -174,6 +178,10 @@ private function onTransactionCommit() : void */ private function onTransactionRollback() : void { + if (! $this->isTransactionRunning()) { + return; + } + $rolledBackTransaction = $this->finishTransaction(); if ($rolledBackTransaction->isRoot()) { @@ -185,6 +193,20 @@ private function onTransactionRollback() : void $this->nextEventIndex -= $rolledBackTransaction->getValue()->count(); } + /** + * Check whether there is at least one transaction running. + * + * @return bool + */ + private function isTransactionRunning() : bool + { + if ($this->currentTransaction) { + return true; + } + + return false; + } + /** * Flush all pending events. * diff --git a/tests/TransactionalDispatcherTest.php b/tests/TransactionalDispatcherTest.php index de93a087e2..6a127b4b51 100644 --- a/tests/TransactionalDispatcherTest.php +++ b/tests/TransactionalDispatcherTest.php @@ -316,6 +316,36 @@ public function it_works_with_non_default_connections() $this->assertEquals('second', $_SERVER['__events'][1]); } + /** + * Regression test: Call to a member function getParent() on null (#27). + * This reproduces the use of DatabaseTransactions and RefreshDatabase traits. + * @test + */ + public function it_ignores_commits_or_rollbacks_when_transactions_are_not_running() + { + $this->withoutEvents(function () { + DB::beginTransaction(); + }); + + $this->dispatcher->listen('foo', function () { + throw new \Exception(); + }); + + try { + DB::beginTransaction(); + $this->dispatcher->dispatch('foo'); + DB::commit(); + } catch (\Exception $e) { + DB::rollBack(); + } + + $this->withoutEvents(function () { + DB::rollBack(); + }); + + $this->assertTrue(true); + } + protected function getPackageProviders($app) { // Add an event listener to the previous event dispatcher. @@ -338,6 +368,21 @@ protected function getEnvironmentSetUp($app) 'database' => ':memory:', ]); } + + protected function withoutEvents(Closure $callback) + { + // Disable Transactional dispatcher. + DB::connection()->unsetEventDispatcher(); + + try { + $callback(); + } catch (\Exception $e) { + throw $e; + } finally { + // Restore the Transactional dispatcher. + DB::connection()->setEventDispatcher($this->dispatcher); + } + } } class CustomEvent implements TransactionalEvent