Transaction   A
last analyzed

Complexity

Total Complexity 20

Size/Duplication

Total Lines 139
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
dl 0
loc 139
rs 10
c 0
b 0
f 0
wmc 20
lcom 1
cbo 3

7 Methods

Rating   Name   Duplication   Size   Complexity  
A setConnection() 0 10 4
A getConnection() 0 8 3
A begin() 0 4 2
A commit() 0 4 2
A rollback() 0 4 2
A perform() 0 21 3
A attempt() 0 19 4
1
<?php
2
3
namespace League\Database\Utils;
4
5
use Closure;
6
use League\Database\Driver\Engine;
7
use League\Database\Driver\TransactionPDO;
8
use League\Database\Exceptions\LogicException;
9
use League\Database\Exceptions\TransactionException;
10
11
class Transaction
12
{
13
    /**
14
     * @var string|TransactionPDO   Connection to database
15
     */
16
    private static $connection;
17
18
    /**
19
     * Set connection name to access for Database Engine
20
     *
21
     * @param $connection
22
     *
23
     * @return bool         True if success
24
     */
25
    public static function setConnection($connection) : bool
26
    {
27
        if (is_string($connection) || (is_object($connection) && is_a($connection, TransactionPDO::class))) {
28
            self::$connection = $connection;
29
30
            return true;
31
        }
32
33
        return false;
34
    }
35
36
    /**
37
     * Get connection to Database, either from string, or TransactionPDO instance
38
     *
39
     * @param string|TransactionPDO $connection
40
     *
41
     * @return TransactionPDO|bool
42
     */
43
    private static function getConnection($connection = null)
44
    {
45
        $connection = self::setConnection($connection) ?: self::$connection;
46
47
        return is_string($connection)
48
            ? Engine::getConnection($connection)
49
            : $connection;
50
    }
51
52
    /**
53
     * Begin transaction on connection
54
     *
55
     * @param string|TransactionPDO $connection
56
     *
57
     * @return bool
58
     */
59
    public static function begin($connection = null) : bool
60
    {
61
        return self::getConnection($connection) && self::getConnection($connection)->beginTransaction();
62
    }
63
64
    /**
65
     * Commit transaction on connection
66
     *
67
     * @param string|TransactionPDO $connection
68
     *
69
     * @return bool
70
     */
71
    public static function commit($connection = null) : bool
72
    {
73
        return self::getConnection($connection) && self::getConnection($connection)->commit();
74
    }
75
76
    /**
77
     * Rollback transaction on connection
78
     *
79
     * @param string|TransactionPDO $connection
80
     *
81
     * @throws \PDOException
82
     * @return bool
83
     */
84
    public static function rollback($connection = null) : bool
85
    {
86
        return self::getConnection($connection) && self::getConnection($connection)->rollBack();
87
    }
88
89
    /**
90
     * Perform some callback while transaction execution
91
     *
92
     * @param Closure               $callback
93
     * @param string|TransactionPDO $connection
94
     *
95
     * @throws LogicException
96
     * @throws TransactionException
97
     */
98
    public static function perform(Closure $callback, $connection = null)
99
    {
100
        /** @var TransactionPDO|bool $connection */
101
        $connection = self::getConnection($connection);
0 ignored issues
show
Bug introduced by
It seems like $connection defined by self::getConnection($connection) on line 101 can also be of type boolean; however, League\Database\Utils\Transaction::getConnection() does only seem to accept string|object<League\Dat...er\TransactionPDO>|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
102
103
        if ($connection === false) {
104
            throw new LogicException('Connection wasn\'t set to perform transaction');
105
        }
106
107
        try {
108
            self::begin();
109
110
            $callback();
111
112
            self::commit();
113
        } catch (\Exception $e) {
114
            self::rollback();
115
116
            throw new TransactionException('Transaction wasn\'t executed', $e->getCode(), $e);
117
        }
118
    }
119
120
    /**
121
     * Try to perform callback while transaction execution several times
122
     *
123
     * @param Closure $callback
124
     * @param int     $attempts
125
     * @param null    $connection
126
     *
127
     * @return bool
128
     * @throws TransactionException
129
     */
130
    public static function attempt(Closure $callback, int $attempts = 1, $connection = null)
131
    {
132
        $attempts = max(1, $attempts);
133
        $currentAttempt = 0;
134
135
        do {
136
            $currentAttempt++;
137
138
            try {
139
                self::perform($callback, $connection);
140
                return true;
141
            } catch (TransactionException $e) {
142
                if ($currentAttempt < $attempts) {
143
                    continue;
144
                }
145
                throw $e;
146
            }
147
        } while ($currentAttempt < $attempts);
148
    }
149
}
150