Completed
Push — master ( d76c6e...84d442 )
by Thomas
02:41
created

Connection::getDepth()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 2
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
     * Get current depth.
60
     *
61
     * @return int
62
     */
63
    public function getDepth()
64
    {
65
        return $this->depth;
66
    }
67
68
    /**
69
     * Remove savepoints to and acquire index of latest active savepoint.
70
     *
71
     * @param int $oldDepth
72
     *   The old depth.
73
     * @param $newDepth
74
     *   The new depth.
75
     *
76
     * @return int|null
77
     *   The last index, if found.
78
     */
79 2
    protected function closeSavePoints($oldDepth, $newDepth)
80
    {
81 2
        $idx = null;
82 2
        for ($depth = $newDepth + 1; $depth <= $oldDepth; $depth++) {
83 2
            if (isset($this->savePoints[$depth])) {
84 2
                $idx = isset($idx) ? $idx : $this->savePoints[$depth];
85 2
                unset($this->savePoints[$depth]);
86 2
            }
87 2
        }
88 2
        return $idx;
89
    }
90
91
    /**
92
     * {@inheritdoc}
93
     */
94 1
    public function startTransaction($newDepth = null)
95
    {
96 1
        $this->depth = isset($newDepth) ? $newDepth : $this->depth + 1;
97 1
        $this->savePoints[$this->depth] = $this->idx;
98 1
    }
99
100
    /**
101
     * {@inheritdoc}
102
     */
103 2
    public function commitTransaction($newDepth = null)
104
    {
105 2
        $oldDepth = $this->depth;
106 2
        $this->depth = isset($newDepth) ? $newDepth : $oldDepth - 1;
107 2
        if ($this->depth < 0) {
108 1
            throw new \RuntimeException('Trying to commit non-existant transaction.');
109
        }
110
111
        // Remove savepoints to and acquire index of latest active savepoint.
112 2
        $idx = $this->closeSavePoints($oldDepth, $this->depth);
113
114
        // Is this a real commit.
115 2
        if ($this->depth == 0 && isset($idx)) {
116
            // Perform the operations if any found.
117 2
            end($this->operations);
118 2
            $lastIdx = key($this->operations);
119 2
            for ($removeIdx = $idx; $removeIdx <= $lastIdx; $removeIdx++) {
120 2
                if (isset($this->operations[$removeIdx])) {
121 1
                    $this->operations[$removeIdx]->commit($this);
122 1
                    $this->removeOperation($this->operations[$removeIdx]);
123 1
                }
124 2
            }
125 2
            reset($this->operations);
126 2
        }
127 2
    }
128
129
    /**
130
     * {@inheritdoc}
131
     */
132 2
    public function rollbackTransaction($newDepth = null)
133
    {
134 2
        $oldDepth = $this->depth;
135 2
        $this->depth = isset($newDepth) ? $newDepth : $oldDepth - 1;
136 2
        if ($this->depth < 0) {
137 1
            throw new \RuntimeException('Trying to rollback non-existant transaction.');
138
        }
139
140
        // Remove savepoints to and acquire index of latest active savepoint.
141 2
        $idx = $this->closeSavePoints($oldDepth, $this->depth);
142
143
        // Remove operations up until latest active savepoint.
144 2
        if (isset($idx)) {
145 2
            end($this->operations);
146 2
            $lastIdx = key($this->operations);
147 2
            for ($removeIdx = $idx; $removeIdx <= $lastIdx; $removeIdx++) {
148 2
                if (isset($this->operations[$removeIdx])) {
149 1
                    $this->operations[$removeIdx]->rollback($this);
150 1
                    $this->removeOperation($this->operations[$removeIdx]);
151 1
                }
152 2
            }
153 2
            reset($this->operations);
154 2
        }
155 2
    }
156
157
    /**
158
     * {@inheritdoc}
159
     */
160 1
    public function addOperation(Operation $operation)
161
    {
162 1
        if ($this->depth <= 0) {
163 1
            $operation->commit();
164 1
            return $operation;
165
        }
166 1
        $idx = $this->idx;
167 1
        $this->idx++;
168 1
        $this->operations[$idx] = $operation;
169 1
        $operation->setIdx($this, $idx);
170 1
        return $operation;
171
    }
172
173
    /**
174
     * {@inheritdoc}
175
     */
176 2
    public function hasOperation(Operation $operation)
177
    {
178 2
        return isset($this->operations[$operation->idx($this)]);
179
    }
180
181
    /**
182
     * {@inheritdoc}
183
     */
184 1
    public function removeOperation(Operation $operation)
185
    {
186 1
        unset($this->operations[$operation->idx($this)]);
187 1
    }
188
189
    /**
190
     * Short-hand notation for adding code to be run on commit.
191
     *
192
     * @param callable $callback
193
     *   The code to run on commit.
194
     *
195
     * @return Operation
196
     */
197 1
    public function onCommit(callable $callback)
198
    {
199 1
        return $this->addOperation((new Operation())
200 1
            ->onCommit($callback));
201
    }
202
203
    /**
204
     * Short-hand notation for adding code to be run on rollback.
205
     *
206
     * @param callable $callback
207
     *   The code to run on rollback.
208
     *
209
     * @return Operation
210
     */
211 1
    public function onRollback(callable $callback)
212
    {
213 1
        return $this->addOperation((new Operation())
214 1
            ->onRollback($callback));
215
    }
216
217
    /**
218
     * Short-hand notation for adding code to be run on rollback.
219
     *
220
     * @param mixed $value
221
     *   The value to add.
222
     *
223
     * @return Operation
224
     */
225 1
    public function addValue($value)
226
    {
227 1
        return $this->addOperation((new Operation())
228 1
            ->setValue($value));
229
    }
230
}
231