Completed
Push — master ( c4e3cd...c5cae6 )
by Anton
05:38
created

SynchronizationBus   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 136
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 17
c 3
b 0
f 0
lcom 1
cbo 5
dl 0
loc 136
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A getTables() 0 4 1
A sortedTables() 0 13 2
A syncronize() 0 20 2
A saveTables() 0 6 2
A collectDrivers() 0 8 3
A beginTransaction() 0 7 2
A commitTransaction() 0 7 2
A rollbackTransaction() 0 7 2
1
<?php
2
/**
3
 * Spiral Framework.
4
 *
5
 * @license   MIT
6
 * @author    Anton Titov (Wolfy-J)
7
 */
8
9
namespace Spiral\Database\Entities;
10
11
use Spiral\Core\Component;
12
use Spiral\Database\Entities\Schemas\AbstractTable;
13
use Spiral\Debug\Traits\LoggerTrait;
14
15
/**
16
 * Saves multiple linked tables at once but treating their cross dependency.
17
 */
18
class SynchronizationBus extends Component
19
{
20
    /**
21
     * Logging.
22
     */
23
    use LoggerTrait;
24
25
    /**
26
     * @var AbstractTable[]
27
     */
28
    protected $tables = [];
29
30
    /**
31
     * @var Driver[]
32
     */
33
    protected $drivers = [];
34
35
    /**
36
     * @param AbstractTable[] $tables
37
     */
38
    public function __construct(array $tables)
39
    {
40
        $this->tables = $tables;
41
        $this->collectDrivers();
42
    }
43
44
    /**
45
     * @return AbstractTable[]
46
     */
47
    public function getTables()
48
    {
49
        return $this->tables;
50
    }
51
52
    /**
53
     * List of tables sorted in order of cross dependency.
54
     *
55
     * @return AbstractTable[]
56
     */
57
    public function sortedTables()
58
    {
59
        $tables = $this->tables;
60
        uasort($tables, function (AbstractTable $tableA, AbstractTable $tableB) {
61
            if (in_array($tableA->getName(), $tableB->getDependencies())) {
62
                return true;
63
            }
64
65
            return count($tableB->getDependencies()) > count($tableA->getDependencies());
66
        });
67
68
        return array_reverse($tables);
69
    }
70
71
    /**
72
     * Syncronize table schemas.
73
     *
74
     * @throws \Exception
75
     */
76
    public function syncronize()
77
    {
78
        $this->beginTransaction();
79
80
        try {
81
            //Dropping non declared foreign keys
82
            $this->saveTables(false, false, true);
83
84
            //Dropping non declared indexes
85
            $this->saveTables(false, true, true);
86
87
            //Dropping non declared columns
88
            $this->saveTables(true, true, true);
89
        } catch (\Exception $exception) {
90
            $this->rollbackTransaction();
91
            throw $exception;
92
        }
93
94
        $this->commitTransaction();
95
    }
96
97
    /**
98
     * @param bool $forgetColumns
99
     * @param bool $forgetIndexes
100
     * @param bool $forgetForeigns
101
     */
102
    protected function saveTables($forgetColumns, $forgetIndexes, $forgetForeigns)
103
    {
104
        foreach ($this->sortedTables() as $table) {
105
            $table->save($forgetColumns, $forgetIndexes, $forgetForeigns);
106
        }
107
    }
108
109
    /**
110
     * Collecting all involved drivers.
111
     */
112
    protected function collectDrivers()
113
    {
114
        foreach ($this->tables as $table) {
115
            if (!in_array($table->driver(), $this->drivers, true)) {
116
                $this->drivers[] = $table->driver();
117
            }
118
        }
119
    }
120
121
    /**
122
     * Begin mass transaction.
123
     */
124
    protected function beginTransaction()
125
    {
126
        $this->logger()->debug("Begin transaction");
127
        foreach ($this->drivers as $driver) {
128
            $driver->beginTransaction();
129
        }
130
    }
131
132
    /**
133
     * Commit mass transaction.
134
     */
135
    protected function commitTransaction()
136
    {
137
        $this->logger()->debug("Commit transaction");
138
        foreach ($this->drivers as $driver) {
139
            $driver->commitTransaction();
140
        }
141
    }
142
143
    /**
144
     * Roll back mass transaction.
145
     */
146
    protected function rollbackTransaction()
147
    {
148
        $this->logger()->warning("Roll back transaction");
149
        foreach ($this->drivers as $driver) {
150
            $driver->rollbackTransaction();
151
        }
152
    }
153
}