Completed
Push — master ( cd637e...97db54 )
by Thomas
02:44
created

Connection::onCommit()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 5
ccs 3
cts 3
cp 1
rs 9.4285
cc 1
eloc 3
nc 1
nop 1
crap 1
1
<?php
2
3
namespace Gielfeldt\TransactionalPHP;
4
5
/**
6
 * Class Connection
7
 *
8
 * @package Gielfeldt\TransactionalPHP
9
 */
10
class Connection
11
{
12
    /**
13
     * @var Operation[]
14
     */
15
    protected $operations = [];
16
17
    /**
18
     * @var int
19
     */
20
    protected $idx = 0;
21
22
    /**
23
     * @var int[]
24
     */
25
    protected $savePoints = [];
26
27
    /**
28
     * @var int
29
     */
30
    protected $depth = 0;
31
32
    /**
33
     * @var null|string
34
     */
35
    protected $connectionId;
36
37
    /**
38
     * Connection constructor.
39
     *
40
     * @param null|string $connectionId
41
     *   (optional) The id of the connection.
42
     */
43 1
    public function __construct($connectionId = null)
44
    {
45 1
        $this->connectionId = isset($connectionId) ? $connectionId : uniqid();
46 1
    }
47
48
    /**
49
     * Get connection id.
50
     *
51
     * @return null|string
52
     */
53 1
    public function connectionId()
54
    {
55 1
        return $this->connectionId;
56
    }
57
58
    /**
59
     * Remove savepoints to and acquire index of latest active savepoint.
60
     *
61
     * @param int $oldDepth
62
     *   The old depth.
63
     * @param $newDepth
64
     *   The new depth.
65
     *
66
     * @return int|null
67
     *   The last index, if found.
68
     */
69 2
    public function closeSavepoints($oldDepth, $newDepth)
70
    {
71 2
        $idx = null;
72 2
        for ($depth = $newDepth + 1; $depth <= $oldDepth; $depth++) {
73 2
            if (isset($this->savePoints[$depth])) {
74 2
                $idx = isset($idx) ? $idx : $this->savePoints[$depth];
75 2
                unset($this->savePoints[$depth]);
76 2
            }
77 2
        }
78 2
        return $idx;
79
    }
80
81
    /**
82
     * {@inheritdoc}
83
     */
84 1
    public function startTransaction($newDepth = null)
85
    {
86 1
        $this->depth = isset($newDepth) ? $newDepth : $this->depth + 1;
87 1
        $this->savePoints[$this->depth] = $this->idx;
88 1
    }
89
90
    /**
91
     * {@inheritdoc}
92
     */
93 2
    public function commitTransaction($newDepth = null)
94
    {
95 2
        $oldDepth = $this->depth;
96 2
        $this->depth = isset($newDepth) ? $newDepth : $oldDepth - 1;
97 2
        if ($this->depth < 0) {
98 1
            throw new \RuntimeException('Trying to commit non-existant transaction.');
99
        }
100
101
        // Remove savepoints to and acquire index of latest active savepoint.
102 2
        $idx = $this->closeSavepoints($oldDepth, $this->depth);
103
104
        // Is this a real commit.
105 2
        if ($this->depth == 0 && isset($idx)) {
106
            // Perform the operations if any found.
107 2
            end($this->operations);
108 2
            $lastIdx = key($this->operations);
109 2
            for ($removeIdx = $idx; $removeIdx <= $lastIdx; $removeIdx++) {
110 2
                if (isset($this->operations[$removeIdx])) {
111 1
                    $this->operations[$removeIdx]->commit();
112 1
                    $this->removeOperation($this->operations[$removeIdx]);
113 1
                }
114 2
            }
115 2
            $this->idx = $idx;
116 2
        }
117 2
    }
118
119
    /**
120
     * {@inheritdoc}
121
     */
122 2
    public function rollbackTransaction($newDepth = null)
123
    {
124 2
        $oldDepth = $this->depth;
125 2
        $this->depth = isset($newDepth) ? $newDepth : $oldDepth - 1;
126 2
        if ($this->depth < 0) {
127 1
            throw new \RuntimeException('Trying to rollback non-existant transaction.');
128
        }
129
130
        // Remove savepoints to and acquire index of latest active savepoint.
131 2
        $idx = $this->closeSavepoints($oldDepth, $this->depth);
132
133
        // Remove operations up until latest active savepoint.
134 2
        if (isset($idx)) {
135 2
            end($this->operations);
136 2
            $lastIdx = key($this->operations);
137 2
            for ($removeIdx = $idx; $removeIdx <= $lastIdx; $removeIdx++) {
138 2
                if (isset($this->operations[$removeIdx])) {
139 1
                    $this->operations[$removeIdx]->rollback();
140 1
                    $this->removeOperation($this->operations[$removeIdx]);
141 1
                }
142 2
            }
143 2
            reset($this->operations);
144 2
        }
145 2
    }
146
147
    /**
148
     * {@inheritdoc}
149
     */
150 1
    public function addOperation(Operation $operation)
151
    {
152 1
        if ($this->depth <= 0) {
153 1
            $operation->commit();
154 1
        } else {
155 1
            $idx = $this->idx;
156 1
            $this->idx++;
157 1
            $this->operations[$idx] = $operation;
158 1
            $operation->setIdx($this, $idx);
159
        }
160 1
        return $operation;
161
    }
162
163
    /**
164
     * {@inheritdoc}
165
     */
166 2
    public function hasOperation(Operation $operation)
167
    {
168 2
        return isset($this->operations[$operation->idx($this)]);
169
    }
170
171
    /**
172
     * {@inheritdoc}
173
     */
174 1
    public function removeOperation(Operation $operation)
175
    {
176 1
        unset($this->operations[$operation->idx($this)]);
177 1
    }
178
179
    /**
180
     * Short-hand notation for adding code to be run on commit.
181
     *
182
     * @param callable $callback
183
     *   The code to run.
184
     *
185
     * @return Operation
186
     */
187 1
    public function onCommit(callable $callback)
188
    {
189 1
        return $this->addOperation((new Operation())
190 1
            ->onCommit($callback));
191
    }
192
193
    /**
194
     * Short-hand notation for adding code to be run on rollback.
195
     *
196
     * @param callable $callback
197
     *   The code to run.
198
     *
199
     * @return Operation
200
     */
201 1
    public function onRollback(callable $callback)
202
    {
203 1
        return $this->addOperation((new Operation())
204 1
            ->onRollback($callback));
205
    }
206
}
207