From 15657525d4f14a080d51eb7ceb63daed4dbe5d1f Mon Sep 17 00:00:00 2001 From: tianyiw Date: Sat, 28 May 2022 10:16:56 +0800 Subject: [PATCH 1/5] [feature] Transaction callback --- src/Medoo.php | 89 ++++++++++++++++++++ tests/ActionTest.php | 178 ++++++++++++++++++++++++++++++++++++++++ tests/MedooTestCase.php | 3 +- 3 files changed, 269 insertions(+), 1 deletion(-) create mode 100644 tests/ActionTest.php diff --git a/src/Medoo.php b/src/Medoo.php index 00cdb440..353cecc0 100644 --- a/src/Medoo.php +++ b/src/Medoo.php @@ -174,6 +174,27 @@ class Medoo */ public $errorInfo = null; + /** + * Call callback when the transaction has committed. + * + * @var callable[] + */ + public $onActionCommitted = []; + + /** + * Call callback when the transaction has rolled back. + * + * @var callable[] + */ + public $onActionRolledBack = []; + + /** + * Call callback when the transaction has finished. + * + * @var callable[] + */ + public $onActionFinish = []; + /** * Connect the database. * @@ -2102,16 +2123,84 @@ public function action(callable $actions): void if ($result === false) { $this->pdo->rollBack(); + $this->callActionRolledBack(); } else { $this->pdo->commit(); + $this->callActionCommitted(); } } catch (Exception $e) { $this->pdo->rollBack(); + $this->callActionRolledBack(); throw $e; } } } + /** + * Call callback when the transaction has committed. + * + * @return void + */ + protected function callActionCommitted(): void + { + foreach ($this->onActionCommitted as $callback) { + $callback($this); + } + foreach ($this->onActionFinish as $callback) { + $callback($this); + } + $this->onActionCommitted = $this->onActionRolledBack = $this->onActionFinish = []; + } + + /** + * Call callback when the transaction has rolled back. + * + * @return void + */ + protected function callActionRolledBack(): void + { + foreach ($this->onActionRolledBack as $callback) { + $callback($this); + } + foreach ($this->onActionFinish as $callback) { + $callback($this); + } + $this->onActionCommitted = $this->onActionRolledBack = $this->onActionFinish = []; + } + + /** + * Register a callback function and call it after the transaction is successfully committed. + * + * @param callable $callback + * @return void + */ + public function onActionCommitted(callable $callback): void + { + $this->onActionCommitted[] = $callback; + } + + /** + * Register a callback function and call it after the transaction is rolled back. + * + * @param callable $callback + * @return void + */ + public function onActionRolledBack(callable $callback): void + { + $this->onActionRolledBack[] = $callback; + } + + /** + * Register a callback function and call it when the transaction is finished. + * + * @param callable $callback + * @return void + */ + public function onActionFinish(callable $callback): void + { + $this->onActionFinish[] = $callback; + } + /** * Return the ID for the last inserted row. * diff --git a/tests/ActionTest.php b/tests/ActionTest.php new file mode 100644 index 00000000..ac610d51 --- /dev/null +++ b/tests/ActionTest.php @@ -0,0 +1,178 @@ +database->pdo = new class extends PDO + { + public $testBeginTransaction = 0; + public $testRollBack = 0; + public $testCommit = 0; + + function __construct() + { + } + + function beginTransaction(): bool + { + $this->testBeginTransaction++; + return true; + } + + function rollBack(): bool + { + $this->testRollBack++; + return true; + } + + function commit(): bool + { + $this->testCommit++; + return true; + } + }; + } + + public function commitReturnsProvider(): array + { + return [ + 'return null' => [null], + 'return bool' => [true], + 'return string' => ['string'], + 'return object' => [new \stdClass], + 'return 1' => [1], + 'return 0' => [0], + 'return array' => [[]] + ]; + } + + public function rollBackReturnsProvider(): array + { + return [ + 'return bool' => [false], + 'throw exception' => [new \Exception] + ]; + } + + /** + * @covers ::action() + * @covers ::onActionCommitted() + * @covers ::onActionRolledBack() + * @covers ::onActionFinish() + * @covers ::callActionCommitted() + * @dataProvider commitReturnsProvider + */ + public function testActionCommit($return) + { + $onActionCommitted = 0; + $onActionRolledBack = 0; + $onActionFinish = 0; + + $this->database->action(function (Medoo $database) use ($return, &$onActionCommitted, &$onActionRolledBack, &$onActionFinish) { + $database->onActionCommitted(function () use (&$onActionCommitted) { + $onActionCommitted++; + }); + $database->onActionCommitted(function () use (&$onActionCommitted) { + $onActionCommitted++; + }); + + $database->onActionRolledBack(function () use (&$onActionRolledBack) { + $onActionRolledBack++; + }); + $database->onActionRolledBack(function () use (&$onActionRolledBack) { + $onActionRolledBack++; + }); + + $database->onActionFinish(function () use (&$onActionFinish) { + $onActionFinish++; + }); + $database->onActionFinish(function () use (&$onActionFinish) { + $onActionFinish++; + }); + + return $return; + }); + + $this->assertEquals($onActionCommitted, 2); + $this->assertEquals($onActionRolledBack, 0); + $this->assertEquals($onActionFinish, 2); + + $this->assertEquals($this->database->pdo->testBeginTransaction, 1); + $this->assertEquals($this->database->pdo->testRollBack, 0); + $this->assertEquals($this->database->pdo->testCommit, 1); + } + + /** + * @covers ::action() + * @covers ::onActionCommitted() + * @covers ::onActionRolledBack() + * @covers ::onActionFinish() + * @covers ::callActionRolledBack() + * @dataProvider rollBackReturnsProvider + */ + public function testActionRollBack($return) + { + $onActionCommitted = 0; + $onActionRolledBack = 0; + $onActionFinish = 0; + $throwException = 0; + + try { + $this->database->action(function (Medoo $database) use ($return, &$onActionCommitted, &$onActionRolledBack, &$onActionFinish) { + $database->onActionCommitted(function () use (&$onActionCommitted) { + $onActionCommitted++; + }); + $database->onActionCommitted(function () use (&$onActionCommitted) { + $onActionCommitted++; + }); + + $database->onActionRolledBack(function () use (&$onActionRolledBack) { + $onActionRolledBack++; + }); + $database->onActionRolledBack(function () use (&$onActionRolledBack) { + $onActionRolledBack++; + }); + + $database->onActionFinish(function () use (&$onActionFinish) { + $onActionFinish++; + }); + $database->onActionFinish(function () use (&$onActionFinish) { + $onActionFinish++; + }); + + if ($return instanceof \Throwable) { + throw $return; + } + return $return; + }); + } catch (\Throwable $th) { + $throwException++; + } + + $this->assertEquals($onActionCommitted, 0); + $this->assertEquals($onActionRolledBack, 2); + $this->assertEquals($onActionFinish, 2); + + if ($return instanceof \Throwable) { + $this->assertEquals($throwException, 1); + } else { + $this->assertEquals($throwException, 0); + } + + $this->assertEquals($this->database->pdo->testBeginTransaction, 1); + $this->assertEquals($this->database->pdo->testRollBack, 1); + $this->assertEquals($this->database->pdo->testCommit, 0); + } +} diff --git a/tests/MedooTestCase.php b/tests/MedooTestCase.php index 1fae4d7b..159edf59 100644 --- a/tests/MedooTestCase.php +++ b/tests/MedooTestCase.php @@ -7,6 +7,7 @@ class MedooTestCase extends TestCase { + /** @var Medoo */ protected $database; public function setUp(): void @@ -42,7 +43,7 @@ public function expectedQuery($expected): string return preg_replace( '/(?!\'[^\s]+\s?)"([\p{L}_][\p{L}\p{N}@$#\-_]*)"(?!\s?[^\s]+\')/u', $identifier[$this->database->type] ?? '"$1"', - str_replace("\n", " ", $expected) + str_replace(["\r\n", "\n"], " ", $expected) ); } From a372aa47957da7ad990f76fe41d061d8d241cab0 Mon Sep 17 00:00:00 2001 From: tianyiw Date: Sat, 28 May 2022 10:23:19 +0800 Subject: [PATCH 2/5] [feature] Transaction callback --- src/Medoo.php | 14 +++++++------- tests/ActionTest.php | 32 ++++++++++++++++---------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/Medoo.php b/src/Medoo.php index 353cecc0..1b5f35ef 100644 --- a/src/Medoo.php +++ b/src/Medoo.php @@ -193,7 +193,7 @@ class Medoo * * @var callable[] */ - public $onActionFinish = []; + public $onActionFinished = []; /** * Connect the database. @@ -2146,10 +2146,10 @@ protected function callActionCommitted(): void foreach ($this->onActionCommitted as $callback) { $callback($this); } - foreach ($this->onActionFinish as $callback) { + foreach ($this->onActionFinished as $callback) { $callback($this); } - $this->onActionCommitted = $this->onActionRolledBack = $this->onActionFinish = []; + $this->onActionCommitted = $this->onActionRolledBack = $this->onActionFinished = []; } /** @@ -2162,10 +2162,10 @@ protected function callActionRolledBack(): void foreach ($this->onActionRolledBack as $callback) { $callback($this); } - foreach ($this->onActionFinish as $callback) { + foreach ($this->onActionFinished as $callback) { $callback($this); } - $this->onActionCommitted = $this->onActionRolledBack = $this->onActionFinish = []; + $this->onActionCommitted = $this->onActionRolledBack = $this->onActionFinished = []; } /** @@ -2196,9 +2196,9 @@ public function onActionRolledBack(callable $callback): void * @param callable $callback * @return void */ - public function onActionFinish(callable $callback): void + public function onActionFinished(callable $callback): void { - $this->onActionFinish[] = $callback; + $this->onActionFinished[] = $callback; } /** diff --git a/tests/ActionTest.php b/tests/ActionTest.php index ac610d51..1b029500 100644 --- a/tests/ActionTest.php +++ b/tests/ActionTest.php @@ -70,7 +70,7 @@ public function rollBackReturnsProvider(): array * @covers ::action() * @covers ::onActionCommitted() * @covers ::onActionRolledBack() - * @covers ::onActionFinish() + * @covers ::onActionFinished() * @covers ::callActionCommitted() * @dataProvider commitReturnsProvider */ @@ -78,9 +78,9 @@ public function testActionCommit($return) { $onActionCommitted = 0; $onActionRolledBack = 0; - $onActionFinish = 0; + $onActionFinished = 0; - $this->database->action(function (Medoo $database) use ($return, &$onActionCommitted, &$onActionRolledBack, &$onActionFinish) { + $this->database->action(function (Medoo $database) use ($return, &$onActionCommitted, &$onActionRolledBack, &$onActionFinished) { $database->onActionCommitted(function () use (&$onActionCommitted) { $onActionCommitted++; }); @@ -95,11 +95,11 @@ public function testActionCommit($return) $onActionRolledBack++; }); - $database->onActionFinish(function () use (&$onActionFinish) { - $onActionFinish++; + $database->onActionFinished(function () use (&$onActionFinished) { + $onActionFinished++; }); - $database->onActionFinish(function () use (&$onActionFinish) { - $onActionFinish++; + $database->onActionFinished(function () use (&$onActionFinished) { + $onActionFinished++; }); return $return; @@ -107,7 +107,7 @@ public function testActionCommit($return) $this->assertEquals($onActionCommitted, 2); $this->assertEquals($onActionRolledBack, 0); - $this->assertEquals($onActionFinish, 2); + $this->assertEquals($onActionFinished, 2); $this->assertEquals($this->database->pdo->testBeginTransaction, 1); $this->assertEquals($this->database->pdo->testRollBack, 0); @@ -118,7 +118,7 @@ public function testActionCommit($return) * @covers ::action() * @covers ::onActionCommitted() * @covers ::onActionRolledBack() - * @covers ::onActionFinish() + * @covers ::onActionFinished() * @covers ::callActionRolledBack() * @dataProvider rollBackReturnsProvider */ @@ -126,11 +126,11 @@ public function testActionRollBack($return) { $onActionCommitted = 0; $onActionRolledBack = 0; - $onActionFinish = 0; + $onActionFinished = 0; $throwException = 0; try { - $this->database->action(function (Medoo $database) use ($return, &$onActionCommitted, &$onActionRolledBack, &$onActionFinish) { + $this->database->action(function (Medoo $database) use ($return, &$onActionCommitted, &$onActionRolledBack, &$onActionFinished) { $database->onActionCommitted(function () use (&$onActionCommitted) { $onActionCommitted++; }); @@ -145,11 +145,11 @@ public function testActionRollBack($return) $onActionRolledBack++; }); - $database->onActionFinish(function () use (&$onActionFinish) { - $onActionFinish++; + $database->onActionFinished(function () use (&$onActionFinished) { + $onActionFinished++; }); - $database->onActionFinish(function () use (&$onActionFinish) { - $onActionFinish++; + $database->onActionFinished(function () use (&$onActionFinished) { + $onActionFinished++; }); if ($return instanceof \Throwable) { @@ -163,7 +163,7 @@ public function testActionRollBack($return) $this->assertEquals($onActionCommitted, 0); $this->assertEquals($onActionRolledBack, 2); - $this->assertEquals($onActionFinish, 2); + $this->assertEquals($onActionFinished, 2); if ($return instanceof \Throwable) { $this->assertEquals($throwException, 1); From 61afa850f2b5dc587882db20d77727e859f9e0d0 Mon Sep 17 00:00:00 2001 From: tianyiw Date: Sat, 28 May 2022 10:36:07 +0800 Subject: [PATCH 3/5] [feature] Transaction callback --- tests/ActionTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ActionTest.php b/tests/ActionTest.php index 1b029500..d19b163f 100644 --- a/tests/ActionTest.php +++ b/tests/ActionTest.php @@ -49,7 +49,7 @@ public function commitReturnsProvider(): array { return [ 'return null' => [null], - 'return bool' => [true], + 'return true' => [true], 'return string' => ['string'], 'return object' => [new \stdClass], 'return 1' => [1], @@ -61,7 +61,7 @@ public function commitReturnsProvider(): array public function rollBackReturnsProvider(): array { return [ - 'return bool' => [false], + 'return false' => [false], 'throw exception' => [new \Exception] ]; } From 2d8f0ec03e11184c92fd4f715cef688dca45e63c Mon Sep 17 00:00:00 2001 From: tianyiw Date: Sat, 28 May 2022 10:36:07 +0800 Subject: [PATCH 4/5] [feature] Transaction callback --- src/Medoo.php | 4 ++-- tests/ActionTest.php | 28 +++++++++++++++++++--------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/Medoo.php b/src/Medoo.php index 1b5f35ef..d75d849a 100644 --- a/src/Medoo.php +++ b/src/Medoo.php @@ -2147,7 +2147,7 @@ protected function callActionCommitted(): void $callback($this); } foreach ($this->onActionFinished as $callback) { - $callback($this); + $callback($this, true); } $this->onActionCommitted = $this->onActionRolledBack = $this->onActionFinished = []; } @@ -2163,7 +2163,7 @@ protected function callActionRolledBack(): void $callback($this); } foreach ($this->onActionFinished as $callback) { - $callback($this); + $callback($this, false); } $this->onActionCommitted = $this->onActionRolledBack = $this->onActionFinished = []; } diff --git a/tests/ActionTest.php b/tests/ActionTest.php index 1b029500..f4d0c3e5 100644 --- a/tests/ActionTest.php +++ b/tests/ActionTest.php @@ -49,7 +49,7 @@ public function commitReturnsProvider(): array { return [ 'return null' => [null], - 'return bool' => [true], + 'return true' => [true], 'return string' => ['string'], 'return object' => [new \stdClass], 'return 1' => [1], @@ -61,7 +61,7 @@ public function commitReturnsProvider(): array public function rollBackReturnsProvider(): array { return [ - 'return bool' => [false], + 'return false' => [false], 'throw exception' => [new \Exception] ]; } @@ -81,22 +81,27 @@ public function testActionCommit($return) $onActionFinished = 0; $this->database->action(function (Medoo $database) use ($return, &$onActionCommitted, &$onActionRolledBack, &$onActionFinished) { - $database->onActionCommitted(function () use (&$onActionCommitted) { + $this->assertEquals($database, $this->database); + $database->onActionCommitted(function ($database) use (&$onActionCommitted) { $onActionCommitted++; + $this->assertEquals($database, $this->database); }); $database->onActionCommitted(function () use (&$onActionCommitted) { $onActionCommitted++; }); - $database->onActionRolledBack(function () use (&$onActionRolledBack) { + $database->onActionRolledBack(function ($database) use (&$onActionRolledBack) { $onActionRolledBack++; + $this->assertEquals($database, $this->database); }); - $database->onActionRolledBack(function () use (&$onActionRolledBack) { + $database->onActionRolledBack(function ($database) use (&$onActionRolledBack) { $onActionRolledBack++; }); - $database->onActionFinished(function () use (&$onActionFinished) { + $database->onActionFinished(function ($database, $commited) use (&$onActionFinished) { $onActionFinished++; + $this->assertEquals($database, $this->database); + $this->assertEquals($commited, true); }); $database->onActionFinished(function () use (&$onActionFinished) { $onActionFinished++; @@ -131,22 +136,27 @@ public function testActionRollBack($return) try { $this->database->action(function (Medoo $database) use ($return, &$onActionCommitted, &$onActionRolledBack, &$onActionFinished) { - $database->onActionCommitted(function () use (&$onActionCommitted) { + $this->assertEquals($database, $this->database); + $database->onActionCommitted(function ($database) use (&$onActionCommitted) { $onActionCommitted++; + $this->assertEquals($database, $this->database); }); $database->onActionCommitted(function () use (&$onActionCommitted) { $onActionCommitted++; }); - $database->onActionRolledBack(function () use (&$onActionRolledBack) { + $database->onActionRolledBack(function ($database) use (&$onActionRolledBack) { $onActionRolledBack++; + $this->assertEquals($database, $this->database); }); $database->onActionRolledBack(function () use (&$onActionRolledBack) { $onActionRolledBack++; }); - $database->onActionFinished(function () use (&$onActionFinished) { + $database->onActionFinished(function ($database, $commited) use (&$onActionFinished) { $onActionFinished++; + $this->assertEquals($database, $this->database); + $this->assertEquals($commited, false); }); $database->onActionFinished(function () use (&$onActionFinished) { $onActionFinished++; From 87f140d0b5f57866e7ec9e1f883ed6ca48029798 Mon Sep 17 00:00:00 2001 From: tianyiw Date: Sat, 28 May 2022 17:37:36 +0800 Subject: [PATCH 5/5] [feature] Transaction callback --- src/Medoo.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Medoo.php b/src/Medoo.php index d75d849a..6a4c6c50 100644 --- a/src/Medoo.php +++ b/src/Medoo.php @@ -2171,7 +2171,7 @@ protected function callActionRolledBack(): void /** * Register a callback function and call it after the transaction is successfully committed. * - * @param callable $callback + * @param callable $callback `function(Medoo $medoo): void` * @return void */ public function onActionCommitted(callable $callback): void @@ -2182,7 +2182,7 @@ public function onActionCommitted(callable $callback): void /** * Register a callback function and call it after the transaction is rolled back. * - * @param callable $callback + * @param callable $callback `function(Medoo $medoo): void` * @return void */ public function onActionRolledBack(callable $callback): void @@ -2193,7 +2193,7 @@ public function onActionRolledBack(callable $callback): void /** * Register a callback function and call it when the transaction is finished. * - * @param callable $callback + * @param callable $callback `function(Medoo $medoo, bool $committed): void` * @return void */ public function onActionFinished(callable $callback): void