Completed
Branch feature/pre-split (745f0c)
by Anton
03:28
created

Transaction   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 109
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

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

5 Methods

Rating   Name   Duplication   Size   Complexity  
A store() 0 4 1
A delete() 0 4 1
A addCommand() 0 4 1
A getCommands() 0 10 3
C run() 0 50 10
1
<?php
2
/**
3
 * components
4
 *
5
 * @author    Wolfy-J
6
 */
7
namespace Spiral\ORM;
8
9
use Spiral\Database\Entities\Driver;
10
use Spiral\ORM\Exceptions\RecordException;
11
12
/**
13
 * Singular ORM transaction with ability to automatically open transaction for all involved
14
 * drivers.
15
 *
16
 * Drivers will be automatically fetched from commands.
17
 */
18
class Transaction implements TransactionInterface
19
{
20
    /**
21
     * @var CommandInterface[]
22
     */
23
    private $commands = [];
24
25
    /**
26
     * Store entity information (update or insert).
27
     *
28
     * @param RecordInterface $record
29
     *
30
     * @throws RecordException
31
     */
32
    public function store(RecordInterface $record)
33
    {
34
        $this->addCommand($record->queueStore());
35
    }
36
37
    /**
38
     * Delete entity from database.
39
     *
40
     * @param RecordInterface $record
41
     *
42
     * @throws RecordException
43
     */
44
    public function delete(RecordInterface $record)
45
    {
46
        $this->addCommand($record->queueDelete());
47
    }
48
49
    /**
50
     * {@inheritdoc}
51
     */
52
    final public function addCommand(CommandInterface $command)
53
    {
54
        $this->commands[] = $command;
55
    }
56
57
    /**
58
     * @return \Generator
59
     */
60
    final public function getCommands()
61
    {
62
        foreach ($this->commands as $command) {
63
            if ($command instanceof TransactionInterface) {
64
                yield from $command->getCommands();
65
            }
66
67
            yield $command;
68
        }
69
    }
70
71
    /**
72
     * {@inheritdoc}
73
     *
74
     * Executing transaction.
75
     */
76
    public function run()
77
    {
78
        /**
79
         * @var Driver[]           $drivers
80
         * @var CommandInterface[] $executedCommands
81
         */
82
        $drivers = [];
83
        $executedCommands = [];
84
85
        try {
86
            foreach ($this->getCommands() as $command) {
87
                if ($command instanceof TransactionInterface) {
88
                    //All transaction commands are flatten (see getCommands() method)
89
                    continue;
90
                }
91
92
                if ($command instanceof SQLCommandInterface) {
93
                    $driver = $command->getDriver();
94
95
                    if (in_array($driver, $drivers)) {
96
                        //Command requires DBAL driver to open transaction
97
                        $drivers[] = $driver;
98
                        $driver->beginTransaction();
99
                    }
100
                }
101
102
                //Execute command
103
                $command->execute();
104
                $executedCommands[] = $command;
105
            }
106
        } catch (\Throwable $e) {
107
            foreach (array_reverse($drivers) as $driver) {
108
                $driver->rollbackTransaction();
109
            }
110
111
            foreach (array_reverse($executedCommands) as $command) {
112
                $command->rollBack();
113
            }
114
115
            throw $e;
116
        }
117
118
        foreach ($drivers as $driver) {
119
            $driver->commitTransaction();
120
        }
121
122
        foreach ($executedCommands as $command) {
123
            $command->complete();
124
        }
125
    }
126
}