AbstractDatabaseManipulator::setVersion()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
3
namespace yentu\manipulators;
4
5
use clearice\io\Io;
6
use ntentan\atiaa\DriverFactory;
7
use yentu\DatabaseAssertor;
8
use yentu\SchemaDescription;
9
use yentu\exceptions\DatabaseManipulatorException;
10
use yentu\Parameters;
11
12
abstract class AbstractDatabaseManipulator
13
{
14
    const CONVERT_TO_DRIVER = 'driver';
15
    const CONVERT_TO_YENTU = 'yentu';
16
17
    private $schemaDescription;
18
    private $assertor;
19
    private $connection;
20
    private $dumpQuery;
21
    private $disableQuery;
22
    protected $defaultSchema;
23
    private $io;
24
25
    /**
26
     * AbstractDatabaseManipulator constructor.
27
     * @param DriverFactory $driverFactory
28
     * @param Io $io
29
     */
30
    public function __construct(DriverFactory $driverFactory, Io $io)
31
    {
32
        $this->connection = $driverFactory->createDriver();
33
        $this->connection->connect();
34
        $this->io = $io;
35
    }
36
37
    public function __get($name)
38
    {
39
        if ($name === 'description') {
40
            return $this->getDescription();
41
        }
42
    }
43
44
    public function setDumpQuery($dumpQuery)
45
    {
46
        $this->dumpQuery = $dumpQuery;
47
    }
48
49
    public function setDisableQuery($disableQuery)
50
    {
51
        $this->disableQuery = $disableQuery;
52
    }
53
54
    public function __call($name, $arguments)
55
    {
56
        if (preg_match("/^(add|drop|change|executeQuery|reverseQuery)/", $name)) {
57
            $details = Parameters::wrap($arguments[0]);
58
            $this->description->$name($details);
0 ignored issues
show
Bug Best Practice introduced by
The property description does not exist on yentu\manipulators\AbstractDatabaseManipulator. Since you implemented __get, consider adding a @property annotation.
Loading history...
59
            $name = "_$name";
60
            new \ReflectionMethod($this, $name);
61
            return $this->$name($details);
62
        } else {
63
            throw new \Exception("Failed to execute method '$name'");
64
        }
65
    }
66
67
    public function query($query, $bind = [])
68
    {
69
        try {
70
            if ($this->dumpQuery) {
71
                echo "$query\n";
72
            }
73
74
            $this->io->output("\n    > Running Query [$query]", Io::OUTPUT_LEVEL_3);
75
76
            if ($this->disableQuery !== true) {
77
                return $this->connection->query($query, $bind);
78
            }
79
        } catch (\ntentan\atiaa\exceptions\DatabaseDriverException $e) {
80
            throw new DatabaseManipulatorException($e->getMessage());
81
        }
82
    }
83
84
    public function disconnect()
85
    {
86
        $this->connection->disconnect();
87
    }
88
89
    public function getDefaultSchema()
90
    {
91
        return $this->connection->getDefaultSchema();
92
    }
93
94
    public function getAssertor()
95
    {
96
        if (!is_object($this->assertor)) {
97
            $this->assertor = new DatabaseAssertor($this->description);
0 ignored issues
show
Bug Best Practice introduced by
The property description does not exist on yentu\manipulators\AbstractDatabaseManipulator. Since you implemented __get, consider adding a @property annotation.
Loading history...
98
        }
99
        return $this->assertor;
100
    }
101
    
102
    public function insertData(array $details)
103
    {
104
        $query = sprintf(
105
            "INSERT INTO %s (%s) VALUES (%s)",
106
            "{$this->quoteIdentifier($details['schema'])}.{$this->quoteIdentifier($details['table'])}",
107
            implode(", ", array_map(fn($x) => $this->quoteIdentifier($x), $details['columns'])),
108
            implode(", ", array_fill(0, count($details['columns']), "?"))                             
109
        );
110
        
111
        foreach($details['rows'] as $row) {
112
            $this->query($query, $row);
113
        }
114
    }
115
    
116
    public function deleteData(array $details)
117
    {
118
        $query = sprintf(
119
            "DELETE FROM %s WHERE %s",
120
            "{$this->quoteIdentifier($details['schema'])}.{$this->quoteIdentifier($details['table'])}",
121
            implode(" AND ", array_map(fn($x) => "{$this->quoteIdentifier($x)}=?", $details['columns']))                      
122
        );
123
        
124
        foreach($details['rows'] as $row) {
125
            $this->query($query, $row);
126
        }
127
    }
128
    
129
    abstract protected function quoteIdentifier(string $identifier): string;
130
131
    abstract protected function _addSchema($name);
132
133
    abstract protected function _dropSchema($name);
134
135
    abstract protected function _addTable($details);
136
137
    abstract protected function _dropTable($details);
138
139
    abstract protected function _changeTableName($details);
140
141
    abstract protected function _addColumn($details);
142
143
    abstract protected function _changeColumnNulls($details);
144
145
    abstract protected function _changeColumnName($details);
146
147
    abstract protected function _changeColumnDefault($details);
148
149
    abstract protected function _dropColumn($details);
150
151
    abstract protected function _addPrimaryKey($details);
152
153
    abstract protected function _dropPrimaryKey($details);
154
155
    abstract protected function _addUniqueKey($details);
156
157
    abstract protected function _dropUniqueKey($details);
158
159
    abstract protected function _addAutoPrimaryKey($details);
160
161
    abstract protected function _dropAutoPrimaryKey($details);
162
163
    abstract protected function _addForeignKey($details);
164
165
    abstract protected function _dropForeignKey($details);
166
167
    abstract protected function _addIndex($details);
168
169
    abstract protected function _dropIndex($details);
170
171
    abstract protected function _addView($details);
172
173
    abstract protected function _dropView($details);
174
175
    abstract protected function _changeViewDefinition($details);
176
177
    protected function _changeForeignKeyOnDelete($details)
178
    {
179
        $this->_dropForeignKey($details['from']);
180
        $this->_addForeignKey($details['to']);
181
    }
182
183
    protected function _changeForeignKeyOnUpdate($details)
184
    {
185
        $this->_dropForeignKey($details['from']);
186
        $this->_addForeignKey($details['to']);
187
    }
188
189
    protected function _executeQuery($details)
190
    {
191
        $this->query($details['query'], $details['bind'] ?? []);
192
    }
193
194
    protected function _reverseQuery($details)
195
    {
196
        if (isset($details['rollback_query'])) {
197
            $this->query($details['rollback_query'], $details['rollback_bind'] ?? []);   
198
        }
199
    }
200
201
    abstract public function convertTypes($type, $direction, $length);
202
203
    /**
204
     * 
205
     * @return SchemaDescription
206
     */
207
    public function getDescription()
208
    {
209
        if (!is_object($this->schemaDescription)) {
210
            $this->schemaDescription = SchemaDescription::wrap($this->connection->describe(), $this);
211
        }
212
        return $this->schemaDescription;
213
    }
214
215
    public function setVersion($version)
216
    {
217
        $this->query('INSERT INTO yentu_history(version) values (?)', array($version));
218
    }
219
220
    public function getVersion()
221
    {
222
        $version = $this->query("SELECT MAX(version) as version FROM yentu_history");
223
        return isset($version[0]) ? $version[0]['version'] : null;
224
    }
225
226
    public function getLastSession()
227
    {
228
        $session = $this->query("SELECT session FROM yentu_history ORDER BY id DESC LIMIT 1");
229
        return isset($session[0]['session']) ? $session[0]['session'] : null;
230
    }
231
232
    public function getSessionVersions($session)
233
    {
234
        $sessionVersions = array();
235
        $versions = $this->query(
236
            "SELECT DISTINCT version FROM yentu_history WHERE session = ?", array($session)
237
        );
238
239
        foreach ($versions as $version) {
240
            $sessionVersions[] = $version['version'];
241
        }
242
243
        return $sessionVersions;
244
    }
245
246
    public function createHistory()
247
    {
248
        try {
249
            $this->connection->describeTable('yentu_history');
250
        } catch (\ntentan\atiaa\exceptions\TableNotFoundException $e) {
251
            $defaultSchema = $this->connection->getDefaultSchema();
252
            $this->io->pushOutputLevel(Io::OUTPUT_LEVEL_0);
253
            $this->addTable(array('schema' => $defaultSchema, 'name' => 'yentu_history'));
0 ignored issues
show
Bug introduced by
The method addTable() does not exist on yentu\manipulators\AbstractDatabaseManipulator. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

253
            $this->/** @scrutinizer ignore-call */ 
254
                   addTable(array('schema' => $defaultSchema, 'name' => 'yentu_history'));
Loading history...
254
255
            $this->addColumn(array('default' => null, 'schema' => $defaultSchema, 'nulls' => true, 'length' => null, 'table' => 'yentu_history', 'name' => 'session', 'type' => 'string'));
0 ignored issues
show
Bug introduced by
The method addColumn() does not exist on yentu\manipulators\AbstractDatabaseManipulator. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

255
            $this->/** @scrutinizer ignore-call */ 
256
                   addColumn(array('default' => null, 'schema' => $defaultSchema, 'nulls' => true, 'length' => null, 'table' => 'yentu_history', 'name' => 'session', 'type' => 'string'));
Loading history...
256
            $this->addColumn(array('default' => null, 'schema' => $defaultSchema, 'nulls' => false, 'length' => null, 'table' => 'yentu_history', 'name' => 'version', 'type' => 'string'));
257
            $this->addColumn(array('default' => null, 'schema' => $defaultSchema, 'nulls' => true, 'length' => null, 'table' => 'yentu_history', 'name' => 'method', 'type' => 'string'));
258
            $this->addColumn(array('default' => null, 'schema' => $defaultSchema, 'nulls' => true, 'length' => null, 'table' => 'yentu_history', 'name' => 'arguments', 'type' => 'text'));
259
            $this->addColumn(array('default' => null, 'schema' => $defaultSchema, 'nulls' => true, 'length' => null, 'table' => 'yentu_history', 'name' => 'migration', 'type' => 'string'));
260
            $this->addColumn(array('default' => null, 'schema' => $defaultSchema, 'nulls' => true, 'length' => null, 'table' => 'yentu_history', 'name' => 'default_schema', 'type' => 'string'));
261
            $this->addColumn(array('default' => null, 'schema' => $defaultSchema, 'nulls' => true, 'length' => null, 'table' => 'yentu_history', 'name' => 'id', 'type' => 'integer'));
262
            $this->addPrimaryKey(array('schema' => $defaultSchema, 'table' => 'yentu_history', 'name' => 'yentu_history_pk', 'columns' => array('id')));
0 ignored issues
show
Bug introduced by
The method addPrimaryKey() does not exist on yentu\manipulators\AbstractDatabaseManipulator. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

262
            $this->/** @scrutinizer ignore-call */ 
263
                   addPrimaryKey(array('schema' => $defaultSchema, 'table' => 'yentu_history', 'name' => 'yentu_history_pk', 'columns' => array('id')));
Loading history...
263
            $this->addAutoPrimaryKey(array('schema' => $defaultSchema, 'table' => 'yentu_history', 'column' => 'id'));
0 ignored issues
show
Bug introduced by
The method addAutoPrimaryKey() does not exist on yentu\manipulators\AbstractDatabaseManipulator. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

263
            $this->/** @scrutinizer ignore-call */ 
264
                   addAutoPrimaryKey(array('schema' => $defaultSchema, 'table' => 'yentu_history', 'column' => 'id'));
Loading history...
264
            $this->io->popOutputLevel();
265
        }
266
    }
267
268
    public function __clone()
269
    {
270
        if (is_object($this->schemaDescription)) {
271
            $this->schemaDescription = clone $this->schemaDescription;
272
        }
273
    }
274
275
}
276