Passed
Push — main ( 263507...cf95a9 )
by Thierry
01:46
created

TableDumpTrait::dumpTruncateTableQuery()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 3
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 5
rs 10
1
<?php
2
3
namespace Lagdo\DbAdmin\DbAdmin\Traits;
4
5
use Lagdo\DbAdmin\Driver\Db\StatementInterface;
6
use Lagdo\DbAdmin\Driver\Entity\TableFieldEntity;
7
8
use function count;
9
use function strlen;
10
use function preg_match;
11
use function str_replace;
12
use function implode;
13
use function is_numeric;
14
use function array_keys;
15
use function array_map;
16
17
trait TableDumpTrait
18
{
19
    /**
20
     * The dump options
21
     *
22
     * @var array
23
     */
24
    private $options;
25
26
    /**
27
     * The queries generated by the dump
28
     *
29
     * @var array
30
     */
31
    private $queries = [];
32
33
    // Temp vars for data dumps
34
    private $insert = '';
35
    private $buffer = '';
36
    private $suffix = '';
37
    private $views = [];
38
    private $fkeys = [];
39
40
    /**
41
     * Print CSV row
42
     *
43
     * @param array  $row
44
     *
45
     * @return void
46
     */
47
    private function dumpCsv(array $row)
48
    {
49
        // From functions.inc.php
50
        foreach ($row as $key => $val) {
51
            if (preg_match('~["\n,;\t]|^0|\.\d*0$~', $val) || $val === '') {
52
                $row[$key] = '"' . str_replace('"', '""', $val) . '"';
53
            }
54
        }
55
        $separator = $this->options['format'] === 'csv' ? ',' :
56
            ($this->options['format'] === 'tsv' ? "\t" : ';');
57
        $this->queries[] = implode($separator, $row);
58
    }
59
60
    /**
61
     * Convert a value to string
62
     *
63
     * @param mixed  $value
64
     * @param TableFieldEntity $field
65
     *
66
     * @return string
67
     */
68
    private function convertToString($value, TableFieldEntity $field): string
69
    {
70
        // From functions.inc.php
71
        if ($value === null) {
72
            return 'NULL';
73
        }
74
        if (!preg_match($this->driver->numberRegex(), $field->type) ||
75
            preg_match('~\[~', $field->fullType) && is_numeric($value)) {
76
            $value = $this->driver->quote(($value === false ? 0 : $value));
77
        }
78
        return $this->driver->unconvertField($field, $value);
79
    }
80
81
    /**
82
     * @param string $table
83
     * @param string $style
84
     * @param int $tableType
85
     *
86
     * @return string
87
     */
88
    private function getCreateTableQuery(string $table, string $style, int $tableType): string
89
    {
90
        if ($tableType !== 2) {
91
            return $this->driver->sqlForCreateTable($table, $this->options['autoIncrement'], $style);
92
        }
93
        $fields = [];
94
        foreach ($this->driver->fields($table) as $name => $field) {
95
            $fields[] = $this->driver->escapeId($name) . ' ' . $field->fullType;
96
        }
97
        return 'CREATE TABLE ' . $this->driver->table($table) . ' (' . implode(', ', $fields) . ')';
98
    }
99
100
    /**
101
     * Export table structure
102
     *
103
     * @param string $table
104
     * @param string $style
105
     * @param int    $tableType       0 table, 1 view, 2 temporary view table
106
     *
107
     * @return void
108
     */
109
    private function addCreateTableQuery(string $table, string $style, int $tableType)
110
    {
111
        $create = $this->getCreateTableQuery($table, $style, $tableType);
112
        $this->driver->setUtf8mb4($create);
113
        if (!$create) {
114
            return;
115
        }
116
        if ($style === 'DROP+CREATE' || $tableType === 1) {
117
            $this->queries[] = 'DROP ' . ($tableType === 2 ? 'VIEW' : 'TABLE') .
118
                ' IF EXISTS ' . $this->driver->table($table) . ';';
119
        }
120
        if ($tableType === 1) {
121
            $create = $this->admin->removeDefiner($create);
122
        }
123
        $this->queries[] = $create . ';';
124
    }
125
126
    /**
127
     * Export table structure
128
     *
129
     * @param string $table
130
     * @param string $style
131
     * @param int    $tableType       0 table, 1 view, 2 temporary view table
132
     *
133
     * @return void
134
     */
135
    private function dumpTableOrView(string $table, string $style, int $tableType = 0)
136
    {
137
        // From adminer.inc.php
138
        if ($this->options['format'] !== 'sql') {
139
            $this->queries[] = "\xef\xbb\xbf"; // UTF-8 byte order mark
140
            if ($style) {
141
                $this->dumpCsv(array_keys($this->driver->fields($table)));
142
            }
143
            return;
144
        }
145
        if (!$style) {
146
            return;
147
        }
148
149
        $this->addCreateTableQuery($table, $style, $tableType);
150
    }
151
152
    /**
153
     * @param array $row
154
     * @param StatementInterface $statement
155
     *
156
     * @return array
157
     */
158
    private function getDataRowKeys(array $row, StatementInterface $statement): array
159
    {
160
        $values = [];
161
        $keys = [];
162
        // For is preferred to foreach because the values are not used.
163
        // foreach ($row as $val) {
164
        // }
165
        for ($i = 0; $i < count($row); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
166
            $field = $statement->fetchField();
167
            $keys[] = $field->name();
168
            $key = $this->driver->escapeId($field->name());
169
            $values[] = "$key = VALUES($key)";
170
        }
171
        $this->suffix = ";\n";
172
        if ($this->options['data_style'] === 'INSERT+UPDATE') {
173
            $this->suffix = "\nON DUPLICATE KEY UPDATE " . implode(', ', $values) . ";\n";
174
        }
175
        return $keys;
176
    }
177
178
    /**
179
     * @param array $row
180
     *
181
     * @return void
182
     */
183
    private function saveRowInBuffer(array $row)
184
    {
185
        $max_packet = ($this->driver->jush() === 'sqlite' ? 0 : 1048576); // default, minimum is 1024
186
        $s = ($max_packet ? "\n" : ' ') . '(' . implode(",\t", $row) . ')';
187
        if (!$this->buffer) {
188
            $this->buffer = $this->insert . $s;
189
            return;
190
        }
191
        if (strlen($this->buffer) + 4 + strlen($s) + strlen($this->suffix) < $max_packet) { // 4 - length specification
192
            $this->buffer .= ",$s";
193
            return;
194
        }
195
        $this->queries[] = $this->buffer . $this->suffix;
196
        $this->buffer = $this->insert . $s;
197
    }
198
199
    /**
200
     * @param string $table
201
     * @param array $fields
202
     * @param array $row
203
     * @param array $keys
204
     *
205
     * @return void
206
     */
207
    private function dumpRow(string $table, array $fields, array $row, array $keys)
208
    {
209
        if ($this->options['format'] !== 'sql') {
210
            if ($this->options['data_style'] === 'table') {
211
                $this->dumpCsv($keys);
212
                $this->options['data_style'] = 'INSERT';
213
            }
214
            $this->dumpCsv($row);
215
            return;
216
        }
217
        if (!$this->insert) {
218
            $this->insert = 'INSERT INTO ' . $this->driver->table($table) . ' (' .
219
                implode(', ', array_map(function ($key) {
220
                    return $this->driver->escapeId($key);
221
                }, $keys)) . ') VALUES';
222
        }
223
        foreach ($row as $key => $val) {
224
            $field = $fields[$key];
225
            $row[$key] = $this->convertToString($val, $field);
226
        }
227
        $this->saveRowInBuffer($row);
228
    }
229
230
    /**
231
     * @param string $table
232
     *
233
     * @return void
234
     */
235
    private function dumpTruncateTableQuery(string $table)
236
    {
237
        if ($this->options['format'] === 'sql' &&
238
            $this->options['data_style'] === 'TRUNCATE+INSERT') {
239
            $this->queries[] = $this->driver->sqlForTruncateTable($table) . ";\n";
240
        }
241
    }
242
243
    /**
244
     * @param string $table
245
     * @param StatementInterface $statement
246
     *
247
     * @return void
248
     */
249
    private function dumpRows(string $table, StatementInterface $statement)
250
    {
251
        $fields = $this->options['format'] !== 'sql' ? [] : $this->driver->fields($table);
252
        $keys = [];
253
        $fetch_function = ($table !== '' ? 'fetchAssoc' : 'fetchRow');
254
        while ($row = $statement->$fetch_function()) {
255
            if (empty($keys)) {
256
                $keys = $this->getDataRowKeys($row, $statement);
257
            }
258
            $this->dumpRow($table, $fields, $row, $keys);
259
        }
260
    }
261
262
    /** Export table data
263
     *
264
     * @param string $table
265
     * @param string $query
266
     *
267
     * @return void
268
     */
269
    private function dumpData(string $table, string $query)
270
    {
271
        if (!$this->options['data_style']) {
272
            return;
273
        }
274
        $statement = $this->driver->query($query); // 1 - MYSQLI_USE_RESULT //! enum and set as numbers
275
        if (!$statement) {
276
            if ($this->options['format'] === 'sql') {
277
                $this->queries[] = '-- ' . str_replace("\n", ' ', $this->driver->error()) . "\n";
278
            }
279
            return;
280
        }
281
282
        $this->insert = '';
283
        $this->buffer = '';
284
        $this->suffix = '';
285
        $this->dumpTruncateTableQuery($table);
286
        $this->dumpRows($table, $statement);
287
        if (!empty($this->buffer)) {
288
            $this->queries[] = $this->buffer . $this->suffix;
289
        }
290
    }
291
}
292