Passed
Push — develop ( d3c53a...e28085 )
by nguereza
14:20
created

MySQLDump::dumpTable()   C

Complexity

Conditions 15
Paths 18

Size

Total Lines 72
Code Lines 49

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 15
eloc 49
c 1
b 0
f 0
nc 18
nop 3
dl 0
loc 72
rs 5.9166

How to fix   Long Method    Complexity   

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:

1
<?php
2
3
/**
4
 * Platine Framework
5
 *
6
 * Platine Framework is a lightweight, high-performance, simple and elegant
7
 * PHP Web framework
8
 *
9
 * This content is released under the MIT License (MIT)
10
 *
11
 * Copyright (c) 2020 Platine Framework
12
 *
13
 * Permission is hereby granted, free of charge, to any person obtaining a copy
14
 * of this software and associated documentation files (the "Software"), to deal
15
 * in the Software without restriction, including without limitation the rights
16
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
 * copies of the Software, and to permit persons to whom the Software is
18
 * furnished to do so, subject to the following conditions:
19
 *
20
 * The above copyright notice and this permission notice shall be included in all
21
 * copies or substantial portions of the Software.
22
 *
23
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
 * SOFTWARE.
30
 */
31
32
declare(strict_types=1);
33
34
namespace Platine\Framework\Tool\Database;
35
36
use Exception;
37
use Platine\Database\Connection;
38
use Platine\Framework\Helper\NumberHelper;
39
use Platine\Stdlib\Helper\Str;
40
use RuntimeException;
41
42
/**
43
 * @class MySQLDump
44
 * @package Platine\Framework\Tool\Database
45
 */
46
class MySQLDump implements DumpDriverInterface
47
{
48
    /**
49
     * {@inheritdoc}
50
     */
51
    public function __construct(protected Connection $connection)
52
    {
53
    }
54
55
    /**
56
     * {@inheritdoc}
57
     */
58
    public function startBackup(string $dbName, array $tables, array $views): string
59
    {
60
61
        // Disable MySQL strict mode
62
        $this->connection->exec('SET SQL_MODE=""');
63
64
        $segments = [...$tables, ...$views];
65
        if (count($segments) === 0) {
66
            return '';
67
        }
68
69
        $this->connection->exec('LOCK TABLES `' . implode('` READ, `', $segments) . '` READ');
70
71
        $str = '-- Created at ' . date('r') . ' Platine Framework Dump tool' . "\n";
72
        $str .= '-- Author: Platine Team' . "\n";
73
        $str .= '-- Database: ' . $dbName . "\n";
74
        $str .= "\n";
75
        $str .= 'SET NAMES utf8;' . "\n";
76
        $str .= 'SET SQL_MODE=\'NO_AUTO_VALUE_ON_ZERO\';' . "\n";
77
        $str .= 'SET FOREIGN_KEY_CHECKS=0;' . "\n";
78
        $str .= 'SET UNIQUE_CHECKS=0;' . "\n";
79
        $str .= 'SET AUTOCOMMIT=0;' . "\n";
80
        $str .= "\n\n";
81
        $str .= sprintf('DROP DATABASE IF EXISTS %s;', $dbName) . "\n";
82
        $str .= sprintf('CREATE DATABASE IF NOT EXISTS %s;', $dbName) . "\n";
83
        $str .= sprintf('USE %s;', $dbName) . "\n";
84
        $str .= "\n\n";
85
86
        return $str;
87
    }
88
89
    /**
90
     * {@inheritdoc}
91
     */
92
    public function endBackup(string $dbName): string
93
    {
94
        $str = 'COMMIT;' . "\n";
95
        $str .= sprintf('-- THE END [%s]', date('r')) . "\n";
96
97
        $this->connection->exec('UNLOCK TABLES');
98
99
        return $str;
100
    }
101
102
    /**
103
     * {@inheritdoc}
104
     */
105
    public function dumpTable(string $name, int $mode, bool $isView = false): string
106
    {
107
        $quotedTable = $this->quoteName($name);
108
        $query = $this->connection->query(sprintf('SHOW CREATE TABLE %s', $quotedTable));
109
        $row = $query->fetchAssoc()->get();
110
111
        $result = '-- --------------------------------------------------------' . "\n\n";
112
        if ($mode & DatabaseDump::DROP) {
113
            $result .= sprintf('DROP %s IF EXISTS %s;', $isView ? 'VIEW' : 'TABLE', $quotedTable) . "\n\n";
114
        }
115
116
        if ($mode & DatabaseDump::CREATE) {
117
            $result .= ($row[$isView ? 'Create View' : 'Create Table']) . ";\n\n";
118
        }
119
120
        if ($isView === false && ($mode & DatabaseDump::DATA)) {
121
            $result .= sprintf('ALTER TABLE %s DISABLE KEYS;', $quotedTable) . "\n\n";
122
            $numerics = [];
123
            $query = $this->connection->query(sprintf('SHOW COLUMNS FROM %s', $quotedTable));
124
125
            $queryResult = $query->fetchAssoc()->all();
126
            $columns = [];
127
            foreach ($queryResult as $res) {
128
                $column = $res['Field'];
129
                $columns[] = $this->quoteName($column);
130
                $numerics[$column] = (bool) preg_match(
131
                    '#^[^(]*(BYTE|COUNTER|SERIAL|INT|LONG$|CURRENCY|REAL|MONEY|FLOAT|DOUBLE|DECIMAL|NUMERIC|NUMBER)#i',
132
                    $res['Type']
133
                );
134
            }
135
136
            $columns = '(' . implode(', ', $columns) . ')';
137
            $size = 0;
138
            $queryData = $this->connection->query(sprintf('SELECT * FROM %s', $quotedTable));
139
            $rows = $queryData->fetchAssoc()->all();
140
            foreach ($rows as $row) {
141
                $str = '(';
142
                foreach ($row as $key => $value) {
143
                    if ($value === null) {
144
                        $str .= "NULL,\t";
145
                    } elseif ($numerics[$key]) {
146
                        $str .= NumberHelper::numberToString($value) . ",\t";
147
                    } else {
148
                        $str .= $this->connection->getDriver()->quote($value) . ",\t";
149
                    }
150
                }
151
152
                if ($size === 0) {
153
                    $str = sprintf("INSERT INTO %s %s VALUES\n%s", $quotedTable, $columns, $str);
154
                } else {
155
                    $str = ',' . "\n" . $str;
156
                }
157
158
                $length = strlen($str) - 1;
159
                $str[$length - 1] = ')';
160
161
                $result .= $str;
162
                $size += $length;
163
                if ($size > DatabaseDump::MAX_SQL_SIZE) {
164
                    $result .= ";\n";
165
                    $size = 0;
166
                }
167
            }
168
169
            if ($size > 0) {
170
                $result .= ";\n\n";
171
            }
172
            $result .= sprintf('ALTER TABLE %s ENABLE KEYS;', $quotedTable) . "\n\n";
173
            $result .= "\n";
174
        }
175
176
        return $result;
177
    }
178
179
    /**
180
     * {@inheritdoc}
181
     */
182
    public function restore(
183
        string $filename,
184
        string $content,
185
        ?callable $onProgress = null,
186
        bool $compress = false
187
    ): void {
188
        $sql = '';
189
        $delimiter = ';';
190
        $count = 0;
191
        $lines = (array) explode("\n", $content);
192
        $total = count($lines);
193
194
195
        foreach ($lines as $str) {
196
            if (substr($str, 0, 2) === '--') { // This is comment
197
                continue;
198
            }
199
200
            if (Str::upper(substr($str, 0, 10)) === 'DELIMITER ') {
201
                $delimiter = trim(substr($str, 10));
202
            } elseif (substr($ts = rtrim($str), -Str::length($delimiter)) === $delimiter) {
203
                $sql .= substr($ts, 0, -Str::length($delimiter));
204
205
                try {
206
                    $this->connection->exec($sql);
207
                } catch (Exception $ex) {
208
                    throw new RuntimeException(sprintf(
209
                        'Error when execute the SQL [%s], error [%s]',
210
                        $sql,
211
                        $ex->getMessage()
212
                    ));
213
                }
214
                $sql = '';
215
                $count++;
216
                if ($onProgress !== null) {
217
                    call_user_func(
218
                        $onProgress,
219
                        $count,
220
                        $count * 100 / $total
221
                    );
222
                }
223
            } else {
224
                $sql .= $str;
225
            }
226
        }
227
    }
228
229
    /**
230
     * Do quote of the given name
231
     * @param string $name
232
     * @return string
233
     */
234
    protected function quoteName(string $name): string
235
    {
236
        return $this->connection->getDriver()->quoteIdentifier($name);
237
    }
238
}
239