Passed
Branch main (2a1ad3)
by Thierry
06:07 queued 03:57
created

Database::alterTable()   F

Complexity

Conditions 18
Paths 324

Size

Total Lines 44
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 18
eloc 30
c 1
b 0
f 0
nc 324
nop 9
dl 0
loc 44
rs 2.4833

How to fix   Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
namespace Lagdo\DbAdmin\Driver\Sqlite\Db;
4
5
use Lagdo\DbAdmin\Driver\Entity\TableFieldEntity;
6
use Lagdo\DbAdmin\Driver\Entity\TableEntity;
7
use Lagdo\DbAdmin\Driver\Entity\IndexEntity;
8
use Lagdo\DbAdmin\Driver\Entity\ForeignKeyEntity;
9
use Lagdo\DbAdmin\Driver\Entity\TriggerEntity;
10
11
use Lagdo\DbAdmin\Driver\Db\ConnectionInterface;
12
13
use Lagdo\DbAdmin\Driver\Db\Database as AbstractDatabase;
14
15
class Database extends AbstractDatabase
16
{
17
    /**
18
     * @inheritDoc
19
     */
20
    public function alterTable(string $table, string $name, array $fields, array $foreign,
21
        string $comment, string $engine, string $collation, int $autoIncrement, string $partitioning)
22
    {
23
        $use_all_fields = ($table == "" || !empty($foreign));
24
        foreach ($fields as $field) {
25
            if ($field[0] != "" || !$field[1] || $field[2]) {
26
                $use_all_fields = true;
27
                break;
28
            }
29
        }
30
        $alter = [];
31
        $originals = [];
32
        foreach ($fields as $field) {
33
            if ($field[1]) {
34
                $alter[] = ($use_all_fields ? $field[1] : "ADD " . implode($field[1]));
35
                if ($field[0] != "") {
36
                    $originals[$field[0]] = $field[1][0];
37
                }
38
            }
39
        }
40
        if (!$use_all_fields) {
41
            foreach ($alter as $val) {
42
                if (!$this->driver->execute("ALTER TABLE " . $this->driver->table($table) . " $val")) {
43
                    return false;
44
                }
45
            }
46
            if ($table != $name && !$this->driver->execute("ALTER TABLE " .
47
                $this->driver->table($table) . " RENAME TO " . $this->driver->table($name))) {
48
                return false;
49
            }
50
        } elseif (!$this->recreateTable($table, $name, $alter, $originals, $foreign, $autoIncrement)) {
51
            return false;
52
        }
53
        if ($autoIncrement) {
54
            $this->driver->execute("BEGIN");
55
            $this->driver->execute("UPDATE sqlite_sequence SET seq = $autoIncrement WHERE name = " .
56
                $this->driver->quote($name)); // ignores error
57
            if (!$this->driver->affectedRows()) {
58
                $this->driver->execute("INSERT INTO sqlite_sequence (name, seq) VALUES (" .
59
                    $this->driver->quote($name) . ", $autoIncrement)");
60
            }
61
            $this->driver->execute("COMMIT");
62
        }
63
        return true;
64
    }
65
66
    /**
67
     * Recreate a table
68
     *
69
     * @param string $table
70
     * @param string $name
71
     * @param array $fields
72
     * @param array $originals
73
     * @param array $foreign
74
     * @param integer $autoIncrement
75
     * @param array $indexes
76
     *
77
     * @return bool
78
     */
79
    protected function recreateTable(string $table, string $name, array $fields, array $originals,
80
        array $foreign, int $autoIncrement, array $indexes = [])
81
    {
82
        if ($table != "") {
83
            if (empty($fields)) {
84
                foreach ($this->driver->fields($table) as $key => $field) {
85
                    if (!empty($indexes)) {
86
                        $field->autoIncrement = 0;
87
                    }
88
                    $fields[] = $this->util->processField($field, $field);
89
                    $originals[$key] = $this->driver->escapeId($key);
90
                }
91
            }
92
            $primary_key = false;
93
            foreach ($fields as $field) {
94
                if ($field[6]) {
95
                    $primary_key = true;
96
                }
97
            }
98
            $drop_indexes = [];
99
            foreach ($indexes as $key => $val) {
100
                if ($val[2] == "DROP") {
101
                    $drop_indexes[$val[1]] = true;
102
                    unset($indexes[$key]);
103
                }
104
            }
105
            foreach ($this->driver->indexes($table) as $key_name => $index) {
106
                $columns = [];
107
                foreach ($index->columns as $key => $column) {
108
                    if (!$originals[$column]) {
109
                        continue 2;
110
                    }
111
                    $columns[] = $originals[$column] . ($index->descs[$key] ? " DESC" : "");
112
                }
113
                if (!$drop_indexes[$key_name]) {
114
                    if ($index->type != "PRIMARY" || !$primary_key) {
115
                        $indexes[] = [$index->type, $key_name, $columns];
116
                    }
117
                }
118
            }
119
            foreach ($indexes as $key => $val) {
120
                if ($val[0] == "PRIMARY") {
121
                    unset($indexes[$key]);
122
                    $foreign[] = "  PRIMARY KEY (" . implode(", ", $val[2]) . ")";
123
                }
124
            }
125
            foreach ($this->driver->foreignKeys($table) as $key_name => $foreignKey) {
126
                foreach ($foreignKey->source as $key => $column) {
127
                    if (!$originals[$column]) {
128
                        continue 2;
129
                    }
130
                    $foreignKey->source[$key] = $this->driver->unescapeId($originals[$column]);
131
                }
132
                if (!isset($foreign[" $key_name"])) {
133
                    $foreign[] = " " . $this->driver->formatForeignKey($foreignKey);
134
                }
135
            }
136
            $this->driver->execute("BEGIN");
137
        }
138
        foreach ($fields as $key => $field) {
139
            $fields[$key] = "  " . implode($field);
140
        }
141
        $fields = array_merge($fields, array_filter($foreign));
142
        $tempName = ($table == $name ? "adminer_$name" : $name);
143
        if (!$this->driver->execute("CREATE TABLE " . $this->driver->table($tempName) .
144
            " (\n" . implode(",\n", $fields) . "\n)")) {
145
            // implicit ROLLBACK to not overwrite $this->driver->error()
146
            return false;
147
        }
148
        if ($table != "") {
149
            if ($originals && !$this->driver->execute("INSERT INTO " . $this->driver->table($tempName) .
150
                " (" . implode(", ", $originals) . ") SELECT " . implode(
151
                    ", ",
152
                    array_map(function ($key) {
153
                   return $this->driver->escapeId($key);
154
               }, array_keys($originals))
155
                ) . " FROM " . $this->driver->table($table))) {
156
                return false;
157
            }
158
            $triggers = [];
159
            foreach ($this->driver->triggers($table) as $trigger_name => $timing_event) {
160
                $trigger = $this->trigger($trigger_name);
0 ignored issues
show
Bug introduced by
The method trigger() does not exist on Lagdo\DbAdmin\Driver\Sqlite\Db\Database. ( Ignorable by Annotation )

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

160
                /** @scrutinizer ignore-call */ 
161
                $trigger = $this->trigger($trigger_name);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
161
                $triggers[] = "CREATE TRIGGER " . $this->driver->escapeId($trigger_name) . " " .
162
                    implode(" ", $timing_event) . " ON " . $this->driver->table($name) . "\n$trigger[Statement]";
163
            }
164
            $autoIncrement = $autoIncrement ? 0 :
165
                $this->connection->result("SELECT seq FROM sqlite_sequence WHERE name = " .
166
                $this->driver->quote($table)); // if $autoIncrement is set then it will be updated later
167
            // drop before creating indexes and triggers to allow using old names
168
            if (!$this->driver->execute("DROP TABLE " . $this->driver->table($table)) ||
169
                ($table == $name && !$this->driver->execute("ALTER TABLE " . $this->driver->table($tempName) .
170
                " RENAME TO " . $this->driver->table($name))) || !$this->alterIndexes($name, $indexes)
171
            ) {
172
                return false;
173
            }
174
            if ($autoIncrement) {
175
                $this->driver->execute("UPDATE sqlite_sequence SET seq = $autoIncrement WHERE name = " . $this->driver->quote($name)); // ignores error
176
            }
177
            foreach ($triggers as $trigger) {
178
                if (!$this->driver->execute($trigger)) {
179
                    return false;
180
                }
181
            }
182
            $this->driver->execute("COMMIT");
183
        }
184
        return true;
185
    }
186
187
    /**
188
     * @inheritDoc
189
     */
190
    public function alterIndexes(string $table, array $alter)
191
    {
192
        foreach ($alter as $primary) {
193
            if ($primary[0] == "PRIMARY") {
194
                return $this->recreateTable($table, $table, [], [], [], 0, $alter);
195
            }
196
        }
197
        foreach (array_reverse($alter) as $val) {
198
            if (!$this->driver->execute($val[2] == "DROP" ?
199
                "DROP INDEX " . $this->driver->escapeId($val[1]) :
200
                $this->driver->sqlForCreateIndex($table, $val[0], $val[1], "(" . implode(", ", $val[2]) . ")")
201
            )) {
202
                return false;
203
            }
204
        }
205
        return true;
206
    }
207
208
    /**
209
     * @inheritDoc
210
     */
211
    public function tables()
212
    {
213
        return $this->driver->keyValues("SELECT name, type FROM sqlite_master " .
214
            "WHERE type IN ('table', 'view') ORDER BY (name = 'sqlite_sequence'), name");
215
    }
216
217
    /**
218
     * @inheritDoc
219
     */
220
    public function countTables(array $databases)
221
    {
222
        $connection = $this->driver->createConnection(); // New connection
223
        $counts = [];
224
        $query = "SELECT count(*) FROM sqlite_master WHERE type IN ('table', 'view')";
225
        foreach ($databases as $database) {
226
            $counts[$database] = 0;
227
            $connection->open($database);
228
            $statement = $connection->query($query);
229
            if (is_object($statement) && ($row = $statement->fetchRow())) {
230
                $counts[$database] = intval($row[0]);
231
            }
232
        }
233
        return $counts;
234
    }
235
236
    /**
237
     * @inheritDoc
238
     */
239
    public function dropViews(array $views)
240
    {
241
        return $this->driver->applyQueries("DROP VIEW", $views);
242
    }
243
244
    /**
245
     * @inheritDoc
246
     */
247
    public function dropTables(array $tables)
248
    {
249
        return $this->driver->applyQueries("DROP TABLE", $tables);
250
    }
251
252
    /**
253
     * @inheritDoc
254
     */
255
    public function moveTables(array $tables, array $views, string $target)
256
    {
257
        return false;
258
    }
259
260
    /**
261
     * @inheritDoc
262
     */
263
    public function truncateTables(array $tables)
264
    {
265
        return $this->driver->applyQueries("DELETE FROM", $tables);
266
    }
267
}
268