1<?php
2
3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0.
4// See the LICENCE file in the repository root for full licence text.
5
6namespace App\Libraries;
7
8use Illuminate\Database\ConnectionInterface;
9
10class TransactionState
11{
12 private $connection;
13
14 private $commits = [];
15 private $rollbacks = [];
16
17 public function __construct(ConnectionInterface $connection = null)
18 {
19 $this->connection = $connection;
20 }
21
22 public function isReal()
23 {
24 return $this->connection !== null;
25 }
26
27 public function isCompleted()
28 {
29 // TODO: throw if null connection instead since it should only run with actual transactions?
30 return $this->connection ? $this->connection->transactionLevel() === 0 : true;
31 }
32
33 public function addCommittable($committable)
34 {
35 $this->commits[] = $committable;
36 }
37
38 public function addRollbackable($rollbackable)
39 {
40 $this->rollbacks[] = $rollbackable;
41 }
42
43 public function commit()
44 {
45 foreach ($this->uniqueCommits() as $commit) {
46 $commit->afterCommit();
47 }
48
49 $this->clear();
50 }
51
52 public function rollback()
53 {
54 foreach ($this->uniqueRollbacks() as $rollback) {
55 $rollback->afterRollback();
56 }
57
58 $this->clear();
59 }
60
61 public function clear()
62 {
63 $this->commits = [];
64 $this->rollbacks = [];
65 }
66
67 private function uniqueCommits()
68 {
69 return static::uniqueModels($this->commits);
70 }
71
72 private function uniqueRollbacks()
73 {
74 return static::uniqueModels($this->rollbacks);
75 }
76
77 private static function uniqueModels(array $models)
78 {
79 $array = [];
80
81 foreach ($models as $model) {
82 if (static::uniqueIn($model, $array)) {
83 $array[] = $model;
84 }
85 }
86
87 return $array;
88 }
89
90 private static function uniqueIn($model, $array)
91 {
92 // use model's uniqueness test if model is persisted and has a primary key.
93 // otherwise use a reference comparison.
94 if ($model->exists && $model->getKey() !== null) {
95 foreach ($array as $obj) {
96 if ($model->is($obj)) {
97 return false;
98 }
99 }
100 } else {
101 foreach ($array as $obj) {
102 if ($model === $obj) {
103 return false;
104 }
105 }
106 }
107
108 return true;
109 }
110}