Issues (48)

src/Tasks/DraftVsLive.php (2 issues)

1
<?php
2
3
namespace Sunnysideup\MigrateData\Tasks;
4
5
use SilverStripe\ORM\DB;
6
7
class DraftVsLive extends MigrateDataTaskBase
8
{
9
    protected $title = 'Compare Drafts vs Live';
10
11
    protected $description = 'Go through every table and compare DRAFT vs Live';
12
13
    protected $enabled = true;
14
15
    protected $selectedTables = [];
16
17
    protected $missingColumns = [];
18
19
    protected $deleteLiveOnlyRecords = false;
20
21
    protected function performMigration()
22
    {
23
        //get tables in DB
24
        $dbTablesPresent = [];
25
        if (empty($this->selectedTables)) {
26
            $rows = DB::query('SHOW tables');
27
            foreach ($rows as $row) {
28
                $table = array_pop($row);
29
                $dbTablesPresent[$table] = $table;
30
            }
31
        } else {
32
            $dbTablesPresent = $this->selectedTables;
33
        }
34
        foreach ($dbTablesPresent as $table) {
35
            $this->missingColumns[$table] = [];
36
            $liveTable = $table . '_Live';
37
            if ($this->tableExists($liveTable)) {
38
                if ($this->deleteLiveOnlyRecords) {
39
                    $this->deleteLiveOnlyRecords($table, $liveTable);
40
                }
41
                //check count
42
                $draftCount = (int) DB::query('SELECT COUNT(ID) FROM ' . $table . ' ORDER BY ID;')->value();
43
                $liveCount = (int) DB::query('SELECT COUNT(ID) FROM ' . $liveTable . ' ORDER BY ID;')->value();
44
                if ((int) $draftCount !== (int) $liveCount) {
45
                    $this->flushNow(
46
                        'TABLE ' . $table . ' count (' . $draftCount . ')
47
                        is not the same as count for ' . $liveTable . ' (' . $liveCount . '),
48
                        DIFFERENCE: ' . ($draftCount - $liveCount) . ' more entries on DRAFT.',
49
                        'deleted'
50
                    );
51
                } else {
52
                    $this->flushNow('TABLE ' . $table . ' DRAFT and LIVE count is identical ...', 'created');
53
                }
54
55
                //check columns
56
                $this->compareColumnsOuter($table, $liveTable);
57
                $allOk = true;
58
                $draftRows = DB::query('SELECT * FROM ' . $table . ' ORDER BY ID;');
59
60
                //check rows
61
                foreach ($draftRows as $draftRow) {
62
                    $allOk = $this->compareOneRow($draftRow, $table, $liveTable);
63
                }
64
                if ($allOk) {
65
                    $this->flushNow('... For matching rows, DRAFT and LIVE are identical.');
66
                }
67
            } else {
68
                $this->flushNow('No Live version for ' . $table);
69
            }
70
        }
71
    }
72
73
    protected function compareOneRow($draftRow, $table, $liveTable)
74
    {
75
        $allOk = true;
76
        $liveRows = DB::query('SELECT * FROM ' . $liveTable . ' WHERE ID = ' . $draftRow['ID'] . ';');
77
        foreach ($liveRows as $liveRow) {
78
            $results = array_diff($draftRow, $liveRow) + array_diff($liveRow, $draftRow);
79
            foreach (array_keys($results) as $key) {
80
                if (! isset($draftRow[$key])) {
81
                    $draftRow[$key] = '???';
82
                }
83
                if (! isset($liveRow[$key])) {
84
                    $liveRow[$key] = '???';
85
                }
86
                $allOk = false;
87
                $this->flushNow(
88
                    '... ... DRAFT !== LIVE for <strong>' . $table . '</strong>, ' .
89
                    'ID <strong>' . $draftRow['ID'] . '</strong>, ' .
90
                    'FIELD: <strong>' . $key . '</strong>:
91
                    <span style="color: purple">' . strip_tags(substr(print_r($draftRow[$key], 1), 0, 100)) . '</span> !==
0 ignored issues
show
It seems like print_r($draftRow[$key], 1) can also be of type true; however, parameter $string of substr() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

91
                    <span style="color: purple">' . strip_tags(substr(/** @scrutinizer ignore-type */ print_r($draftRow[$key], 1), 0, 100)) . '</span> !==
Loading history...
92
                    <span style="color: orange">' . strip_tags(substr(print_r($liveRow[$key], 1), 0, 100)) . '</span>  ',
93
                    'deleted'
94
                );
95
            }
96
        }
97
98
        return $allOk;
99
    }
100
101
    protected function compareColumnsOuter($table, $liveTable, $backwards = false)
0 ignored issues
show
The parameter $backwards is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

101
    protected function compareColumnsOuter($table, $liveTable, /** @scrutinizer ignore-unused */ $backwards = false)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
102
    {
103
        $draftRows1 = DB::query('SELECT * FROM ' . $table . ' ORDER BY ID LIMIT 1;');
104
        $LiveRows1 = DB::query('SELECT * FROM ' . $liveTable . ' ORDER BY ID LIMIT 1;');
105
        foreach ($draftRows1 as $draftRow) {
106
            foreach ($LiveRows1 as $liveRow) {
107
                $this->compareColumnsInner($draftRow, $liveRow, $table);
108
            }
109
        }
110
    }
111
112
    protected function compareColumnsInner($rowA, $rowB, $table, $backwards = false)
113
    {
114
        $tableA = 'DRAFT';
115
        $tableB = 'LIVE';
116
        if ($backwards) {
117
            $tableB = 'DRAFT';
118
            $tableA = 'LIVE';
119
        }
120
        $result = array_diff_key($rowA, $rowB);
121
        foreach (array_keys($result) as $key) {
122
            $this->missingColumns[$table][$key] = $key;
123
            $this->flushNow(
124
                '... Found a column in the ' . $tableA . ' table that did not match the ' . $tableB . ' table: ' . $key,
125
                'deleted'
126
            );
127
        }
128
        if (! $backwards) {
129
            $this->compareColumnsInner($rowB, $rowA, $table, true);
130
        }
131
    }
132
133
    protected function deleteLiveOnlyRecords(string $tableNameDraft, string $tableNameLive)
134
    {
135
        $rows = DB::query('
136
            SELECT "' . $tableNameLive . '"."ID"
137
            FROM "' . $tableNameLive . '"
138
            LEFT JOIN  "' . $tableNameDraft . '" ON "' . $tableNameLive . '"."ID" = "' . $tableNameDraft . '"."ID"
139
            WHERE "' . $tableNameDraft . '"."ID" IS NULL;
140
        ');
141
        foreach ($rows as $row) {
142
            $this->flushNow(
143
                'Deleting from ' . $tableNameLive . ' where ID = ' . $row['ID'],
144
                'deleted'
145
            );
146
            DB::query('
147
                DELETE FROM "' . $tableNameLive . '" WHERE ID = ' . $row['ID'] . ';
148
            ');
149
        }
150
    }
151
}
152