Passed
Branch main (217991)
by Thierry
02:18
created

Database::alterTable()   F

Complexity

Conditions 14
Paths 1224

Size

Total Lines 33
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 14
eloc 24
c 1
b 0
f 0
nc 1224
nop 9
dl 0
loc 33
rs 2.1

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\MySql\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
        $alter = [];
24
        foreach ($fields as $field) {
25
            $alter[] = ($field[1] ? ($table != "" ? ($field[0] != "" ? "CHANGE " .
26
                $this->driver->escapeId($field[0]) : "ADD") : " ") . " " .
27
                implode($field[1]) . ($table != "" ? $field[2] : "") :
28
                "DROP " . $this->driver->escapeId($field[0])
29
            );
30
        }
31
        $alter = array_merge($alter, $foreign);
32
        $status = " COMMENT=" . $this->driver->quote($comment) .
33
            ($engine ? " ENGINE=" . $this->driver->quote($engine) : "") .
34
            ($collation ? " COLLATE " . $this->driver->quote($collation) : "") .
35
            ($autoIncrement != "" ? " AUTO_INCREMENT=$autoIncrement" : "");
36
        if ($table == "") {
37
            $result = $this->driver->execute("CREATE TABLE " . $this->driver->table($name) .
38
                " (\n" . implode(",\n", $alter) . "\n)$status$partitioning");
39
            return $result !== false;
40
        }
41
        if ($table != $name) {
42
            $alter[] = "RENAME TO " . $this->driver->table($name);
43
        }
44
        if ($status) {
45
            $alter[] = ltrim($status);
46
        }
47
        if (!$alter && !$partitioning) {
48
            return true;
49
        }
50
        $result = $this->driver->execute("ALTER TABLE " . $this->driver->table($table) . "\n" .
51
            implode(",\n", $alter) . $partitioning);
52
        return $result !== false;
53
    }
54
55
    /**
56
     * @inheritDoc
57
     */
58
    public function alterIndexes(string $table, array $alter)
59
    {
60
        foreach ($alter as $key => $val) {
61
            $alter[$key] = (
62
                $val[2] == "DROP"
63
                ? "\nDROP INDEX " . $this->driver->escapeId($val[1])
64
                : "\nADD $val[0] " . ($val[0] == "PRIMARY" ? "KEY " : "") . ($val[1] != "" ? $this->driver->escapeId($val[1]) . " " : "") . "(" . implode(", ", $val[2]) . ")"
65
            );
66
        }
67
        $result = $this->driver->execute("ALTER TABLE " . $this->driver->table($table) . implode(",", $alter));
68
        return $result !== false;
69
    }
70
71
    /**
72
     * @inheritDoc
73
     */
74
    public function tables()
75
    {
76
        return $this->driver->keyValues($this->driver->minVersion(5) ?
77
            "SELECT TABLE_NAME, TABLE_TYPE FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() ORDER BY TABLE_NAME" :
78
            "SHOW TABLES");
79
    }
80
81
    /**
82
     * @inheritDoc
83
     */
84
    public function countTables(array $databases)
85
    {
86
        $counts = [];
87
        foreach ($databases as $database) {
88
            $counts[$database] = count($this->driver->values("SHOW TABLES IN " . $this->driver->escapeId($database)));
89
        }
90
        return $counts;
91
    }
92
93
    /**
94
     * @inheritDoc
95
     */
96
    public function dropViews(array $views)
97
    {
98
        $this->driver->execute("DROP VIEW " . implode(", ", array_map(function ($view) {
99
            return $this->driver->table($view);
100
        }, $views)));
101
        return true;
102
    }
103
104
    /**
105
     * @inheritDoc
106
     */
107
    public function dropTables(array $tables)
108
    {
109
        $this->driver->execute("DROP TABLE " . implode(", ", array_map(function ($table) {
110
            return $this->driver->table($table);
111
        }, $tables)));
112
        return true;
113
    }
114
115
    /**
116
     * @inheritDoc
117
     */
118
    public function truncateTables(array $tables)
119
    {
120
        return $this->driver->applyQueries("TRUNCATE TABLE", $tables);
121
    }
122
123
    /**
124
     * @inheritDoc
125
     */
126
    public function moveTables(array $tables, array $views, string $target)
127
    {
128
        $rename = [];
129
        foreach ($tables as $table) {
130
            $rename[] = $this->driver->table($table) . " TO " . $this->driver->escapeId($target) . "." . $this->driver->table($table);
131
        }
132
        if (!$rename || $this->driver->execute("RENAME TABLE " . implode(", ", $rename))) {
133
            $definitions = [];
134
            foreach ($views as $table) {
135
                $definitions[$this->driver->table($table)] = $this->driver->view($table);
136
            }
137
            $this->connection->open($target);
138
            $database = $this->driver->escapeId($this->driver->database());
139
            foreach ($definitions as $name => $view) {
140
                if (!$this->driver->execute("CREATE VIEW $name AS " . str_replace(" $database.", " ", $view["select"])) || !$this->driver->execute("DROP VIEW $database.$name")) {
141
                    return false;
142
                }
143
            }
144
            return true;
145
        }
146
        //! move triggers
147
        return false;
148
    }
149
150
    /**
151
     * @inheritDoc
152
     */
153
    public function copyTables(array $tables, array $views, string $target)
154
    {
155
        $this->driver->execute("SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO'");
156
        $overwrite = $this->util->input()->getOverwrite();
157
        foreach ($tables as $table) {
158
            $name = ($target == $this->driver->database() ? $this->driver->table("copy_$table") : $this->driver->escapeId($target) . "." . $this->driver->table($table));
159
            if (($overwrite && !$this->driver->execute("\nDROP TABLE IF EXISTS $name"))
160
                || !$this->driver->execute("CREATE TABLE $name LIKE " . $this->driver->table($table))
161
                || !$this->driver->execute("INSERT INTO $name SELECT * FROM " . $this->driver->table($table))
162
            ) {
163
                return false;
164
            }
165
            foreach ($this->driver->rows("SHOW TRIGGERS LIKE " . $this->driver->quote(addcslashes($table, "%_\\"))) as $row) {
166
                $trigger = $row["Trigger"];
167
                if (!$this->driver->execute("CREATE TRIGGER " . ($target == $this->driver->database() ? $this->driver->escapeId("copy_$trigger") : $this->driver->escapeId($target) . "." . $this->driver->escapeId($trigger)) . " $row[Timing] $row[Event] ON $name FOR EACH ROW\n$row[Statement];")) {
168
                    return false;
169
                }
170
            }
171
        }
172
        foreach ($views as $table) {
173
            $name = ($target == $this->driver->database() ? $this->driver->table("copy_$table") : $this->driver->escapeId($target) . "." . $this->driver->table($table));
174
            $view = $this->driver->view($table);
175
            if (($overwrite && !$this->driver->execute("DROP VIEW IF EXISTS $name"))
176
                || !$this->driver->execute("CREATE VIEW $name AS $view[select]")) { //! USE to avoid db.table
177
                return false;
178
            }
179
        }
180
        return true;
181
    }
182
183
    /**
184
     * @inheritDoc
185
     */
186
    public function events()
187
    {
188
        return $this->driver->rows("SHOW EVENTS");
189
    }
190
191
    /**
192
     * @inheritDoc
193
     */
194
    public function routine(string $name, string $type)
195
    {
196
        $enumLength = $this->driver->enumLength();
197
        $aliases = ["bool", "boolean", "integer", "double precision", "real", "dec",
198
            "numeric", "fixed", "national char", "national varchar"];
199
        $space = "(?:\\s|/\\*[\s\S]*?\\*/|(?:#|-- )[^\n]*\n?|--\r?\n)";
200
        $type_pattern = "((" . implode("|", array_merge(array_keys($this->driver->types()), $aliases)) .
201
            ")\\b(?:\\s*\\(((?:[^'\")]|$enumLength)++)\\))?\\s*(zerofill\\s*)?(unsigned" .
202
            "(?:\\s+zerofill)?)?)(?:\\s*(?:CHARSET|CHARACTER\\s+SET)\\s*['\"]?([^'\"\\s,]+)['\"]?)?";
203
        $pattern = "$space*(" . ($type == "FUNCTION" ? "" : $this->driver->inout()) .
204
            ")?\\s*(?:`((?:[^`]|``)*)`\\s*|\\b(\\S+)\\s+)$type_pattern";
205
        $create = $this->connection->result("SHOW CREATE $type " . $this->driver->escapeId($name), 2);
206
        preg_match("~\\(((?:$pattern\\s*,?)*)\\)\\s*" .
207
            ($type == "FUNCTION" ? "RETURNS\\s+$type_pattern\\s+" : "") . "(.*)~is", $create, $match);
208
        $fields = [];
209
        preg_match_all("~$pattern\\s*,?~is", $match[1], $matches, PREG_SET_ORDER);
210
        foreach ($matches as $param) {
211
            $fields[] = [
212
                "field" => str_replace("``", "`", $param[2]) . $param[3],
213
                "type" => strtolower($param[5]),
214
                "length" => preg_replace_callback("~$enumLength~s", 'normalize_enum', $param[6]),
215
                "unsigned" => strtolower(preg_replace('~\s+~', ' ', trim("$param[8] $param[7]"))),
216
                "null" => 1,
217
                "full_type" => $param[4],
218
                "inout" => strtoupper($param[1]),
219
                "collation" => strtolower($param[9]),
220
            ];
221
        }
222
        if ($type != "FUNCTION") {
223
            return ["fields" => $fields, "definition" => $match[11]];
224
        }
225
        return [
226
            "fields" => $fields,
227
            "returns" => ["type" => $match[12], "length" => $match[13], "unsigned" => $match[15], "collation" => $match[16]],
228
            "definition" => $match[17],
229
            "language" => "SQL", // available in information_schema.ROUTINES.PARAMETER_STYLE
230
        ];
231
    }
232
233
    /**
234
     * @inheritDoc
235
     */
236
    public function routines()
237
    {
238
        $rows = $this->driver->rows("SELECT ROUTINE_NAME, ROUTINE_TYPE, DTD_IDENTIFIER " .
239
            "FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = " .
240
            $this->driver->quote($this->driver->database()));
241
        return array_map(function($row) {
242
            return new RoutineEntity($row['ROUTINE_NAME'], $row['ROUTINE_NAME'],
0 ignored issues
show
Bug introduced by
The type Lagdo\DbAdmin\Driver\MySql\Db\RoutineEntity was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
243
                $row['ROUTINE_TYPE'], $row['DTD_IDENTIFIER']);
244
        }, $rows);
245
    }
246
247
    /**
248
     * @inheritDoc
249
     */
250
    public function routineId(string $name, array $row)
251
    {
252
        return $this->driver->escapeId($name);
253
    }
254
}
255