DeleteAllObsoleteFieldsAndTables   A
last analyzed

Complexity

Total Complexity 25

Size/Duplication

Total Lines 139
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 25
eloc 55
c 2
b 0
f 0
dl 0
loc 139
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A log() 0 3 1
B run() 0 33 7
B deleteFieldsAndIndexes() 0 24 9
A execute() 0 12 2
A getTables() 0 23 6
1
<?php
2
3
namespace Sunnysideup\MigrateData\Tasks;
4
5
use SilverStripe\Dev\BuildTask;
6
use SilverStripe\ORM\DB;
7
use Sunnysideup\Flush\FlushNow;
8
use Sunnysideup\Flush\FlushNowImplementor;
9
10
/**
11
 * SOURCE: https://gist.github.com/halkyon/ec08493c2906c1539a49
12
 * Remove old tables, columns, and indexes from a SilverStripe database.
13
 *
14
 * Define your obsolete tables, columns and indexes in {@link $deleted_tables},
15
 * {@link deleted_columns} and {@link deleted_indexes} and these will be deleted
16
 * from the database.
17
 *
18
 * In addition to that, it will automatically remove any tables and columns prefixed with "_obsolete".
19
 */
20
21
/**
22
 * Update all systems.
23
 *
24
 * Class UpdateSystemsWithProductCodeVariantKeywords
25
 */
26
class DeleteAllObsoleteFieldsAndTables extends BuildTask
27
{
28
    protected $title = 'Delete all obsolete tables and fields';
29
30
    protected $description = 'Remove all tables and fields with the words _obsolete, _copy, or _backup in it. Set forreal=1 to run it for real';
31
32
    /**
33
     * If any of these tables are found in the database, they will be removed.
34
     *
35
     * @var array
36
     */
37
    private static $deleted_tables = [
38
        // 'SomeOldTable'
39
    ];
40
41
    /**
42
     * These columns should be deleted. * key indicates any table with columns listed in the array
43
     * value should be removed. If the key is a specific table, only columns listed in the array
44
     * for that table will be removed.
45
     *
46
     * @var array
47
     */
48
    private static $deleted_columns = [
49
        // '*' => array('SomeOldColumn'),
50
        // 'SomeOldTable' => array('Status', 'Version')
51
    ];
52
53
    /**
54
     * If any of these indexes are found in any tables, they will be removed.
55
     *
56
     * @var array
57
     */
58
    private static $deleted_indexes = [
59
        // 'SomeOldIndex'
60
    ];
61
62
    public function run($request)
63
    {
64
        if (empty($_REQUEST['forreal'])) {
65
            FlushNowImplementor::do_flush('=== Running in dry run mode. Add GET variable forreal to run for real. SQL will be displayed, but not executed ===');
66
        }
67
68
        if (empty($_REQUEST['flush'])) {
69
            FlushNowImplementor::do_flush('ERROR: Please run flush=1 to ensure manifest is up to date');
70
71
            return;
72
        }
73
74
        foreach ($this->config()->deleted_tables as $tableName) {
75
            if ('' === DB::query(sprintf("SHOW TABLES LIKE '%s'", $tableName))->value()) {
76
                FlushNowImplementor::do_flush(sprintf('INFO: Table %s was not found ', $tableName));
77
78
                continue;
79
            }
80
81
            $this->execute(sprintf('DROP TABLE "%s"', $tableName));
82
        }
83
84
        $obsoleteTables = $this->getTables(true);
85
86
        foreach ($obsoleteTables as $tableName) {
87
            $this->execute(sprintf('DROP TABLE "%s"', $tableName));
88
        }
89
90
        foreach ($this->getTables() as $tableName) {
91
            $this->deleteFieldsAndIndexes($tableName);
92
        }
93
94
        FlushNowImplementor::do_flush('Done');
95
    }
96
97
    protected function log($message)
98
    {
99
        FlushNowImplementor::do_flush($message);
100
    }
101
102
    protected function execute($sql)
103
    {
104
        if (empty($_REQUEST['forreal'])) {
105
            FlushNowImplementor::do_flush(sprintf('DRY RUN: Not running query: %s', $sql));
106
107
            return true;
108
        }
109
110
        DB::query($sql);
111
        FlushNowImplementor::do_flush(sprintf('INFO: Successfully executed SQL: %s', $sql));
112
113
        return true;
114
    }
115
116
    protected function getTables(?bool $obsoleteOnly = false)
117
    {
118
        $tables = [];
119
        $rows = DB::query('SHOW TABLES ');
120
        foreach ($rows as $row) {
121
            $table = array_pop($row);
122
            $in = true;
123
            if ($obsoleteOnly) {
124
                $in = false;
125
                foreach (['obsolete', 'copy', 'backup'] as $string) {
126
                    $haystack = strtolower($table);
127
                    $needle = '_' . $string;
128
                    if (false !== strpos($haystack, $needle)) {
129
                        $in = true;
130
                    }
131
                }
132
            }
133
            if ($in) {
134
                $tables[$table] = $table;
135
            }
136
        }
137
138
        return $tables;
139
    }
140
141
    protected function deleteFieldsAndIndexes(string $tableName)
142
    {
143
        // search through indexes, remove indexes marked for deletion
144
        foreach (DB::query(sprintf('SHOW INDEXES FROM "%s"', $tableName)) as $index) {
145
            if (in_array($index['Key_name'], $this->config()->deleted_indexes, true)) {
146
                $this->execute(sprintf('DROP INDEX "%s" ON "%s"', $index['Key_name'], $tableName));
147
            }
148
        }
149
150
        // remove obsolete prefixed columns
151
        foreach (DB::query(sprintf('SHOW COLUMNS FROM "%s" WHERE "Field" LIKE \'_obsolete%%\'', $tableName)) as $column) {
152
            $this->execute(sprintf('ALTER TABLE "%s" DROP COLUMN "%s"', $tableName, $column['Field']));
153
        }
154
155
        // remove columns marked for deletion
156
        foreach ($this->config()->deleted_columns as $key => $columnNameArr) {
157
            // if the definitions were for a specific table that we're currently not processing
158
            if ('*' !== $key && $key !== $tableName) {
159
                continue;
160
            }
161
162
            foreach ($columnNameArr as $columnName) {
163
                foreach (DB::query(sprintf('SHOW COLUMNS FROM "%s" WHERE "Field" = \'%s\'', $tableName, $columnName)) as $column) {
164
                    $this->execute(sprintf('ALTER TABLE "%s" DROP COLUMN "%s"', $tableName, $column['Field']));
165
                }
166
            }
167
        }
168
    }
169
}
170