MigrateHelper   B
last analyzed

Complexity

Total Complexity 43

Size/Duplication

Total Lines 269
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 131
c 1
b 0
f 0
dl 0
loc 269
rs 8.96
wmc 43

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
B getKey() 0 35 7
A getColumns() 0 28 3
A getTableName() 0 9 2
A getOptions() 0 11 2
F createSchemaFromSqlfile() 0 120 28

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\Wgevents\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
            } elseif (!$skip) {
102
                if (')' === \mb_strtoupper(\substr($line, 0, 1))) {
103
                    // end of table definition
104
                    // get options
105
                    $this->getOptions($line, $options);
106
                    $tables[$tableName]['options'] = $options;
107
                } elseif ('ENGINE' === \mb_strtoupper(\substr($line, 0, 6))) {
108
                    $this->getOptions($line, $options);
109
                    $tables[$tableName]['options'] = $options;
110
                } elseif ('DEFAULT CHARSET ' === \mb_strtoupper(\substr($line, 0, 16))) {
111
                    $this->getOptions($line, $options);
112
                    $tables[$tableName]['options'] = $options;
113
                } else {
114
                    // get keys and fields
115
                    switch (\mb_strtoupper(\substr($line, 0, 3))) {
116
                        case 'KEY':
117
                        case 'PRI':
118
                        case 'UNI':
119
                            $tables[$tableName]['keys'][] = $this->getKey($line);
120
                            break;
121
                        case 'else':
122
                        default:
123
                            $columns = $this->getColumns($line);
124
                            $tables[$tableName]['columns'][] = $columns;
125
                            break;
126
                    }
127
                }
128
            }
129
        }
130
131
        // create array for new schema
132
        $level1 = \str_repeat(' ', 4);
133
        $level2 = \str_repeat(' ', 8);
134
        $level3 = \str_repeat(' ', 12);
135
136
        foreach ($tables as $tkey => $table) {
137
            $schema[] = "$tkey:\n";
138
            foreach ($table as $lkey => $line) {
139
                if ('keys' === (string)$lkey) {
140
                    $schema[] = $level1 . "keys:\n";
141
                    foreach ($line as $kkey => $kvalue) {
142
                        foreach ($kvalue as $kkey2 => $kvalue2) {
143
                            $schema[] = $level2 . $kkey2 . ":\n";
144
                            $schema[] = $level3 . 'columns: ' . $kvalue2['columns'] . "\n";
145
                            $schema[] = $level3 . 'unique: ' . $kvalue2['unique'] . "\n";
146
                        }
147
                    }
148
                } elseif ('options' === (string)$lkey) {
149
                    $schema[] = $level1 . 'options: ' . $line . "\n";
150
                } else {
151
                    $schema[] = $level1 . 'columns: ' . "\n";
152
                    foreach ($line as $kkey => $kvalue) {
153
                        $schema[] = $level2 . '-' . "\n";
154
                        foreach ($kvalue as $kkey2 => $kvalue2) {
155
                            $schema[] = $level3 . $kkey2 . ': ' . $kvalue2 . "\n";
156
                        }
157
                    }
158
                }
159
            }
160
        }
161
162
        // create new file and write schema array into this file
163
        $myfile = \fopen($this->fileYaml, 'w');
164
        if (!$myfile || \is_null($myfile)) {
0 ignored issues
show
introduced by
$myfile is of type resource, thus it always evaluated to false.
Loading history...
165
            \xoops_error('Error: Unable to open sql file!');
166
            return false;
167
        }
168
        foreach ($schema as $line) {
169
            \fwrite($myfile, $line);
170
        }
171
        \fclose($myfile);
172
173
        return true;
174
175
    }
176
177
    /**
178
     * Extract table name from given line
179
     *
180
     * @param  string $line
181
     * @return string|bool
182
     */
183
    private function getTableName (string $line)
184
    {
185
186
        $arrLine = \explode( '`', $line);
187
        if (\count($arrLine) > 0) {
188
            return $arrLine[1];
189
        }
190
191
        return false;
192
193
    }
194
195
    /**
196
     * Extract columns/fields of table from given line
197
     *
198
     * @param string $line
199
     * @return array|bool
200
     */
201
    private function getColumns (string $line)
202
    {
203
204
        $columns = [];
205
206
        $arrCol = \explode( ' ', \trim($line));
207
        if (\count($arrCol) > 0) {
208
            $name = \str_replace(['`'], '', $arrCol[0]);
209
        } else {
210
            return false;
211
        }
212
213
        $attributes = \trim(\str_replace([$name, '`'], '', $line));
214
        if (',' === \substr($attributes, - 1)) {
215
            $attributes = substr($attributes, 0, strlen($attributes) - 1);
216
        }
217
        $columns['name'] = $name;
218
        /*
219
        // update quotes
220
        if (\strpos($attributes, "''") > 0) {
221
            $attributes = \trim(\str_replace("''", "''''''''" , $attributes));
222
        } elseif (\strpos($attributes, "'") > 0) {
223
            $attributes = \trim(\str_replace("'", "''" , $attributes));
224
        }
225
        $columns['attributes'] = "' " . $attributes . " '";
226
        */
227
        $columns['attributes'] = '" ' . $attributes . ' "';
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
        $options = '"' . $options . $lineText . '"';
250
251
    }
252
253
    /**
254
     * Extract keys of table from given line
255
     *
256
     * @param string $line
257
     * @return array
258
     */
259
    private function getKey (string $line)
260
    {
261
262
        $key = [];
263
264
        if (\strpos($line, 'RIMARY') > 0) {
265
            $key['PRIMARY'] = [];
266
            $fields = \substr($line, 13, \strlen($line) - 13);
267
            $key['PRIMARY']['columns'] = \str_replace(['`', '),', ')'], '', $fields);
268
            $key['PRIMARY']['unique'] = 'true';
269
        } else {
270
            $unique = 'false';
271
            if (\strpos($line, 'NIQUE') > 0) {
272
                $unique = 'true';
273
            }
274
            $line = \trim(\str_replace(['UNIQUE KEY', 'KEY'], '', $line));
275
            $arrName = \explode('(', $line);
276
            if (\count($arrName) > 0) {
277
                $name = \str_replace(['`', ' '], '', $arrName[0]);
278
                $columns = \str_replace(['`', '),', ')'], '', $arrName[1]);
279
                if ('' === (string)$name) {
280
                    $name = $columns;
281
                }
282
                if (\strpos($name,' ') > 0) {
283
                    $name = "'" . $name . "'";
284
                }
285
                $key[$name] = [];
286
                if (\strpos($columns,' ') > 0) {
287
                    $columns = "'" . $columns . "'";
288
                }
289
                $key[$name]['columns'] = $columns;
290
                $key[$name]['unique'] = $unique;
291
            }
292
        }
293
        return $key;
294
    }
295
}
296