MigrateHelper   B
last analyzed

Complexity

Total Complexity 45

Size/Duplication

Total Lines 268
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 136
c 1
b 0
f 0
dl 0
loc 268
rs 8.8
wmc 45

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A getColumns() 0 26 5
A getTableName() 0 9 2
B getKey() 0 35 7
F createSchemaFromSqlfile() 0 122 28
A getOptions() 0 10 2

How to fix   Complexity   

Complex Class

Complex classes like MigrateHelper often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use MigrateHelper, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace XoopsModules\Wgfilemanager\Common;
4
5
/*
6
 You may not change or alter any portion of this comment or credits
7
 of supporting developers from this source code or any supporting source code
8
 which is considered copyrighted (c) material of the original comment or credit authors.
9
10
 This program is distributed in the hope that it will be useful,
11
 but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
 */
14
15
/**
16
 * Class to compare current DB table structure with sql/mysql.sql
17
 *
18
 * @category  Migrate Helper
19
 * @author    Goffy <[email protected]>
20
 * @copyright 2021 XOOPS Project (https://xoops.org)
21
 * @license   GNU GPL 2 or later (https://www.gnu.org/licenses/gpl-2.0.html)
22
 * @link      https://xoops.org
23
 */
24
25
class MigrateHelper
26
{
27
28
    /**
29
     * @var string
30
     */
31
    private $fileYaml;
32
33
    /**
34
     * @var string
35
     */
36
    private $fileSql;
37
38
39
    /**
40
     * @param string $fileSql
41
     * @param string $fileYaml
42
     */
43
    public function __construct(string $fileSql, string $fileYaml)
44
    {
45
        $this->fileSql = $fileSql;
46
        $this->fileYaml = $fileYaml;
47
    }
48
49
    /**
50
     * Create a yaml file based on a sql file
51
     *
52
     * @return bool
53
     */
54
    public function createSchemaFromSqlfile(): bool
55
    {
56
        if (!\file_exists($this->fileSql)) {
57
            \xoops_error('Error: Sql file not found!');
58
            return false;
59
        }
60
61
        $tables    = [];
62
        $schema    = [];
63
        $tableName = '';
64
65
        // read sql file
66
        $lines = \file($this->fileSql);
67
68
        // remove unnecessary lines
69
        foreach ($lines as $key => $value) {
70
            $line = \trim($value);
71
            // remove blank lines
72
            if ('' === $line) {
73
                unset($lines[$key]);
74
            }
75
            // remove comment lines
76
            if ('#' === \substr($line, 0, 1)) {
77
                unset($lines[$key]);
78
            }
79
        }
80
81
        $skip = true;
82
        $skipWords = ['CREATE DATABASE ', 'CREATE VIEW ', 'INSERT INTO ', 'SELECT ', 'DELETE ', 'UPDATE ', 'ALTER ', 'DROP '];
83
        $options = '';
84
        // read remaining lines line by line and create new schema
85
        foreach ($lines as $key => $value) {
86
            $line = \trim($value);
87
            foreach ($skipWords as $skipWord) {
88
                if ($skipWord === \mb_strtoupper(\substr($line, 0, \strlen($skipWord)))) {
89
                    $skip = true;
90
                }
91
            }
92
            if ('CREATE TABLE' === \mb_strtoupper(\substr($line, 0, 12))) {
93
                $skip = false;
94
                $options = '';
95
                // start table definition
96
                $tableName = $this->getTableName ($line);
97
                $tables[$tableName] = [];
98
                $tables[$tableName]['options'] = '';
99
                $tables[$tableName]['columns'] = [];
100
                $tables[$tableName]['keys'] = [];
101
            } else {
102
                if (!$skip) {
103
                    if (')' === \mb_strtoupper(\substr($line, 0, 1))) {
104
                        // end of table definition
105
                        // get options
106
                        $this->getOptions($line, $options);
107
                        $tables[$tableName]['options'] = $options;
108
                    } elseif ('ENGINE' === \mb_strtoupper(\substr($line, 0, 6))) {
109
                        $this->getOptions($line, $options);
110
                        $tables[$tableName]['options'] = $options;
111
                    } elseif ('DEFAULT CHARSET ' === \mb_strtoupper(\substr($line, 0, 16))) {
112
                        $this->getOptions($line, $options);
113
                        $tables[$tableName]['options'] = $options;
114
                    } else {
115
                        // get keys and fields
116
                        switch (\mb_strtoupper(\substr($line, 0, 3))) {
117
                            case 'KEY':
118
                            case 'PRI':
119
                            case 'UNI':
120
                                $tables[$tableName]['keys'][] = $this->getKey($line);
121
                                break;
122
                            case 'else':
123
                            default:
124
                                $columns = $this->getColumns($line);
125
                                $tables[$tableName]['columns'][] = $columns;
126
                                break;
127
                        }
128
                    }
129
                }
130
            }
131
        }
132
133
        // create array for new schema
134
        $level1 = \str_repeat(' ', 4);
135
        $level2 = \str_repeat(' ', 8);
136
        $level3 = \str_repeat(' ', 12);
137
138
        foreach ($tables as $tkey => $table) {
139
            $schema[] = "$tkey:\n";
140
            foreach ($table as $lkey => $line) {
141
                if ('keys' == $lkey) {
142
                    $schema[] = $level1 . "keys:\n";
143
                    foreach ($line as $kkey => $kvalue) {
144
                        foreach ($kvalue as $kkey2 => $kvalue2) {
145
                            $schema[] = $level2 . $kkey2 . ":\n";
146
                            $schema[] = $level3 . 'columns: ' . $kvalue2['columns'] . "\n";
147
                            $schema[] = $level3 . 'unique: ' . $kvalue2['unique'] . "\n";
148
                        }
149
                    }
150
                } elseif ('options' == $lkey) {
151
                    $schema[] = $level1 . 'options: ' . $line . "\n";
152
                } else {
153
                    $schema[] = $level1 . 'columns: ' . "\n";
154
                    foreach ($line as $kkey => $kvalue) {
155
                        $schema[] = $level2 . '-' . "\n";
156
                        foreach ($kvalue as $kkey2 => $kvalue2) {
157
                            $schema[] = $level3 . $kkey2 . ": " . $kvalue2 . "\n";
158
                        }
159
                    }
160
                }
161
            }
162
        }
163
164
        // create new file and write schema array into this file
165
        $myfile = \fopen($this->fileYaml, "w");
166
        if (!$myfile || \is_null($myfile)) {
0 ignored issues
show
introduced by
$myfile is of type resource, thus it always evaluated to false.
Loading history...
167
            \xoops_error('Error: Unable to open sql file!');
168
            return false;
169
        }
170
        foreach ($schema as $line) {
171
            \fwrite($myfile, $line);
172
        }
173
        \fclose($myfile);
174
175
        return true;
176
177
    }
178
179
    /**
180
     * Extract table name from given line
181
     *
182
     * @param  string $line
183
     * @return string|bool
184
     */
185
    private function getTableName (string $line)
186
    {
187
188
        $arrLine = \explode( '`', $line);
189
        if (\count($arrLine) > 0) {
190
            return $arrLine[1];
191
        }
192
193
        return false;
194
195
    }
196
197
    /**
198
     * Extract columns/fields of table from given line
199
     *
200
     * @param string $line
201
     * @return array|bool
202
     */
203
    private function getColumns (string $line)
204
    {
205
206
        $columns = [];
207
208
        $arrCol = \explode( ' ', \trim($line));
209
        if (\count($arrCol) > 0) {
210
            $name = \str_replace(['`'], '', $arrCol[0]);
211
        } else {
212
            return false;
213
        }
214
215
        $attributes = \trim(\str_replace([$name, '`'], '', $line));
216
        if (',' == \substr($attributes, - 1)) {
217
            $attributes = substr($attributes, 0, strlen($attributes) - 1);
218
        }
219
        $columns['name'] = $name;
220
        // update quotes
221
        if (\strpos($attributes, "''") > 0) {
222
            $attributes = \trim(\str_replace("''", "''''''''" , $attributes));
223
        } elseif (\strpos($attributes, "'") > 0) {
224
            $attributes = \trim(\str_replace("'", "''" , $attributes));
225
        }
226
        $columns['attributes'] = "' " . $attributes . " '";
227
228
        return $columns;
229
230
    }
231
232
    /**
233
     * Extract options of table from given line
234
     *
235
     * @param string $line
236
     * @param string $options
237
     * @return void
238
     */
239
    private function getOptions (string $line, string &$options): void
240
    {
241
242
        $lineText = \trim(\str_replace([')', ';'], '', $line));
243
        // remove all existing '
244
        $options = \str_replace("'", '', $options);
245
        if ('' != $options) {
246
            $options .= ' ';
247
        }
248
        $options = "'" . $options . $lineText . "'";
249
250
    }
251
252
    /**
253
     * Extract keys of table from given line
254
     *
255
     * @param string $line
256
     * @return array
257
     */
258
    private function getKey (string $line)
259
    {
260
261
        $key = [];
262
263
        if (\strpos($line, 'RIMARY') > 0) {
264
            $key['PRIMARY'] = [];
265
            $fields = \substr($line, 13, \strlen($line) - 13);
266
            $key['PRIMARY']['columns'] = \str_replace(['`', '),', ')'], '', $fields);
267
            $key['PRIMARY']['unique'] = 'true';
268
        } else {
269
            $unique = 'false';
270
            if (\strpos($line, 'NIQUE') > 0) {
271
                $unique = 'true';
272
            }
273
            $line = \trim(\str_replace(['UNIQUE KEY', 'KEY'], '', $line));
274
            $arrName = \explode('(', $line);
275
            if (\count($arrName) > 0) {
276
                $name = \str_replace(['`', ' '], '', $arrName[0]);
277
                $columns = \str_replace(['`', '),', ')'], '', $arrName[1]);
278
                if ('' == $name) {
279
                    $name = $columns;
280
                }
281
                if (\strpos($name,' ') > 0) {
282
                    $name = "'" . $name . "'";
283
                }
284
                $key[$name] = [];
285
                if (\strpos($columns,' ') > 0) {
286
                    $columns = "'" . $columns . "'";
287
                }
288
                $key[$name]['columns'] = $columns;
289
                $key[$name]['unique'] = $unique;
290
            }
291
        }
292
        return $key;
293
    }
294
}
295