Completed
Push — master ( 94e8ce...f590db )
by Thomas
02:37
created

Connection::addValue()   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 1
Metric Value
c 1
b 0
f 1
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
            reset($this->operations);
116 2
            $this->idx = $idx;
117 2
        }
118 2
    }
119
120
    /**
121
     * {@inheritdoc}
122
     */
123 2
    public function rollbackTransaction($newDepth = null)
124
    {
125 2
        $oldDepth = $this->depth;
126 2
        $this->depth = isset($newDepth) ? $newDepth : $oldDepth - 1;
127 2
        if ($this->depth < 0) {
128 1
            throw new \RuntimeException('Trying to rollback non-existant transaction.');
129
        }
130
131
        // Remove savepoints to and acquire index of latest active savepoint.
132 2
        $idx = $this->closeSavepoints($oldDepth, $this->depth);
133
134
        // Remove operations up until latest active savepoint.
135 2
        if (isset($idx)) {
136 2
            end($this->operations);
137 2
            $lastIdx = key($this->operations);
138 2
            for ($removeIdx = $idx; $removeIdx <= $lastIdx; $removeIdx++) {
139 2
                if (isset($this->operations[$removeIdx])) {
140 1
                    $this->operations[$removeIdx]->rollback();
141 1
                    $this->removeOperation($this->operations[$removeIdx]);
142 1
                }
143 2
            }
144 2
            reset($this->operations);
145 2
            $this->idx = $idx;
146 2
        }
147 2
    }
148
149
    /**
150
     * {@inheritdoc}
151
     */
152 1
    public function addOperation(Operation $operation)
153
    {
154 1
        if ($this->depth <= 0) {
155 1
            $operation->commit();
156 1
        } else {
157 1
            $idx = $this->idx;
158 1
            $this->idx++;
159 1
            $this->operations[$idx] = $operation;
160 1
            $operation->setIdx($this, $idx);
161
        }
162 1
        return $operation;
163
    }
164
165
    /**
166
     * {@inheritdoc}
167
     */
168 2
    public function hasOperation(Operation $operation)
169
    {
170 2
        return isset($this->operations[$operation->idx($this)]);
171
    }
172
173
    /**
174
     * {@inheritdoc}
175
     */
176 1
    public function removeOperation(Operation $operation)
177
    {
178 1
        unset($this->operations[$operation->idx($this)]);
179 1
    }
180
181
    /**
182
     * Short-hand notation for adding code to be run on commit.
183
     *
184
     * @param callable $callback
185
     *   The code to run on commit.
186
     *
187
     * @return Operation
188
     */
189 1
    public function onCommit(callable $callback)
190
    {
191 1
        return $this->addOperation((new Operation())
192 1
            ->onCommit($callback));
193
    }
194
195
    /**
196
     * Short-hand notation for adding code to be run on rollback.
197
     *
198
     * @param callable $callback
199
     *   The code to run on rollback.
200
     *
201
     * @return Operation
202
     */
203 1
    public function onRollback(callable $callback)
204
    {
205 1
        return $this->addOperation((new Operation())
206 1
            ->onRollback($callback));
207
    }
208
209
    /**
210
     * Short-hand notation for adding code to be run on rollback.
211
     *
212
     * @param mixed $value
213
     *   The value to add.
214
     *
215
     * @return Operation
216
     */
217 1
    public function addValue($value)
218
    {
219 1
        return $this->addOperation((new Operation())
220 1
            ->setValue($value));
221
    }
222
}
223