Skip to content

Commit 23d7f71

Browse files
Merge branch '8.x'
2 parents 173c3df + ca0b82a commit 23d7f71

8 files changed

+662
-0
lines changed

src/Illuminate/Database/Concerns/ManagesTransactions.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Illuminate\Database\Concerns;
44

55
use Closure;
6+
use RuntimeException;
67
use Throwable;
78

89
trait ManagesTransactions
@@ -42,6 +43,8 @@ public function transaction(Closure $callback, $attempts = 1)
4243
try {
4344
if ($this->transactions == 1) {
4445
$this->getPdo()->commit();
46+
47+
optional($this->transactionsManager)->commit($this->getName());
4548
}
4649

4750
$this->transactions = max(0, $this->transactions - 1);
@@ -78,6 +81,10 @@ protected function handleTransactionException(Throwable $e, $currentAttempt, $ma
7881
$this->transactions > 1) {
7982
$this->transactions--;
8083

84+
optional($this->transactionsManager)->rollback(
85+
$this->getName(), $this->transactions
86+
);
87+
8188
throw $e;
8289
}
8390

@@ -107,6 +114,10 @@ public function beginTransaction()
107114

108115
$this->transactions++;
109116

117+
optional($this->transactionsManager)->begin(
118+
$this->getName(), $this->transactions
119+
);
120+
110121
$this->fireConnectionEvent('beganTransaction');
111122
}
112123

@@ -176,6 +187,8 @@ public function commit()
176187
{
177188
if ($this->transactions == 1) {
178189
$this->getPdo()->commit();
190+
191+
optional($this->transactionsManager)->commit($this->getName());
179192
}
180193

181194
$this->transactions = max(0, $this->transactions - 1);
@@ -241,6 +254,10 @@ public function rollBack($toLevel = null)
241254

242255
$this->transactions = $toLevel;
243256

257+
optional($this->transactionsManager)->rollback(
258+
$this->getName(), $this->transactions
259+
);
260+
244261
$this->fireConnectionEvent('rollingBack');
245262
}
246263

@@ -275,6 +292,10 @@ protected function handleRollBackException(Throwable $e)
275292
{
276293
if ($this->causedByLostConnection($e)) {
277294
$this->transactions = 0;
295+
296+
optional($this->transactionsManager)->rollback(
297+
$this->getName(), $this->transactions
298+
);
278299
}
279300

280301
throw $e;
@@ -289,4 +310,18 @@ public function transactionLevel()
289310
{
290311
return $this->transactions;
291312
}
313+
314+
/**
315+
* Execute the callback after a transaction commits.
316+
*
317+
* @return void
318+
*/
319+
public function afterCommit($callback)
320+
{
321+
if ($this->transactionsManager) {
322+
return $this->transactionsManager->addCallback($callback);
323+
}
324+
325+
throw new RuntimeException('Transactions Manager has not been set.');
326+
}
292327
}

src/Illuminate/Database/Connection.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,13 @@ class Connection implements ConnectionInterface
112112
*/
113113
protected $transactions = 0;
114114

115+
/**
116+
* The transaction manager instance.
117+
*
118+
* @var \Illuminate\Database\DatabaseTransactionsManager
119+
*/
120+
protected $transactionsManager;
121+
115122
/**
116123
* Indicates if changes have been made to the database.
117124
*
@@ -1151,6 +1158,29 @@ public function unsetEventDispatcher()
11511158
$this->events = null;
11521159
}
11531160

1161+
/**
1162+
* Set the transaction manager instance on the connection.
1163+
*
1164+
* @param \Illuminate\Database\DatabaseTransactionsManager $manager
1165+
* @return $this
1166+
*/
1167+
public function setTransactionManager($manager)
1168+
{
1169+
$this->transactionsManager = $manager;
1170+
1171+
return $this;
1172+
}
1173+
1174+
/**
1175+
* Unset the transaction manager for this connection.
1176+
*
1177+
* @return void
1178+
*/
1179+
public function unsetTransactionManager()
1180+
{
1181+
$this->transactionsManager = null;
1182+
}
1183+
11541184
/**
11551185
* Determine if the connection is in a "dry run".
11561186
*

src/Illuminate/Database/DatabaseManager.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,10 @@ protected function configure(Connection $connection, $type)
174174
$connection->setEventDispatcher($this->app['events']);
175175
}
176176

177+
if ($this->app->bound('db.transactions')) {
178+
$connection->setTransactionManager($this->app['db.transactions']);
179+
}
180+
177181
// Here we'll set a reconnector callback. This reconnector can be any callable
178182
// so we will set a Closure to reconnect from this manager with the name of
179183
// the connection, which will allow us to reconnect from the connections.

src/Illuminate/Database/DatabaseServiceProvider.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ protected function registerConnectionServices()
7171
$this->app->bind('db.connection', function ($app) {
7272
return $app['db']->connection();
7373
});
74+
75+
$this->app->singleton('db.transactions', function ($app) {
76+
return new DatabaseTransactionsManager;
77+
});
7478
}
7579

7680
/**
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?php
2+
3+
namespace Illuminate\Database;
4+
5+
class DatabaseTransactionRecord
6+
{
7+
/**
8+
* The name of the database connection.
9+
*
10+
* @var string
11+
*/
12+
public $connection;
13+
14+
/**
15+
* The transaction level.
16+
*
17+
* @var int
18+
*/
19+
public $level;
20+
21+
/**
22+
* The callbacks that should be executed after committing.
23+
*
24+
* @var array
25+
*/
26+
protected $callbacks = [];
27+
28+
/**
29+
* Create a new database transaction record instance.
30+
*
31+
* @param string $connection
32+
* @param int $level
33+
* @retunr void
34+
*/
35+
public function __construct($connection, $level)
36+
{
37+
$this->connection = $connection;
38+
$this->level = $level;
39+
}
40+
41+
/**
42+
* Register a callback to be executed after committing.
43+
*
44+
* @param callable $callback
45+
* @return void
46+
*/
47+
public function addCallback($callback)
48+
{
49+
$this->callbacks[] = $callback;
50+
}
51+
52+
/**
53+
* Execute all of the callbacks.
54+
*
55+
* @return void
56+
*/
57+
public function executeCallbacks()
58+
{
59+
foreach ($this->callbacks as $callback) {
60+
call_user_func($callback);
61+
}
62+
}
63+
64+
/**
65+
* Get all of the callbacks.
66+
*
67+
* @return array
68+
*/
69+
public function getCallbacks()
70+
{
71+
return $this->callbacks;
72+
}
73+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
3+
namespace Illuminate\Database;
4+
5+
class DatabaseTransactionsManager
6+
{
7+
/**
8+
* All of the recorded transactions.
9+
*
10+
* @var \Illuminate\Support\Collection
11+
*/
12+
protected $transactions;
13+
14+
/**
15+
* Create a new database transactions manager instance.
16+
*
17+
* @return void
18+
*/
19+
public function __construct()
20+
{
21+
$this->transactions = collect();
22+
}
23+
24+
/**
25+
* Start a new database transaction.
26+
*
27+
* @param string $connection
28+
* @param int $level
29+
* @return void
30+
*/
31+
public function begin($connection, $level)
32+
{
33+
$this->transactions->push(
34+
new DatabaseTransactionRecord($connection, $level)
35+
);
36+
}
37+
38+
/**
39+
* Rollback the active database transaction.
40+
*
41+
* @param string $connection
42+
* @param int $level
43+
* @return void
44+
*/
45+
public function rollback($connection, $level)
46+
{
47+
$this->transactions = $this->transactions->reject(function ($transaction) use ($connection, $level) {
48+
return $transaction->connection == $connection &&
49+
$transaction->level > $level;
50+
})->values();
51+
}
52+
53+
/**
54+
* Commit the active database transaction.
55+
*
56+
* @param string $connection
57+
* @return void
58+
*/
59+
public function commit($connection)
60+
{
61+
$this->transactions = $this->transactions->reject(function ($transaction) use ($connection) {
62+
if ($transaction->connection == $connection) {
63+
$transaction->executeCallbacks();
64+
65+
return true;
66+
}
67+
68+
return false;
69+
})->values();
70+
}
71+
72+
/**
73+
* Register a transaction callback.
74+
*
75+
* @param callable $callback
76+
* @return void
77+
*/
78+
public function addCallback($callback)
79+
{
80+
if ($current = $this->transactions->last()) {
81+
return $current->addCallback($callback);
82+
}
83+
84+
call_user_func($callback);
85+
}
86+
87+
/**
88+
* Get all the transactions.
89+
*
90+
* @return \Illuminate\Support\Collection
91+
*/
92+
public function getTransactions()
93+
{
94+
return $this->transactions;
95+
}
96+
}

0 commit comments

Comments
 (0)