Passed
Push — main ( c55460...a34099 )
by Aspirant
01:50
created

Revision   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 159
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 75
c 2
b 0
f 0
dl 0
loc 159
rs 10
wmc 27

18 Methods

Rating   Name   Duplication   Size   Complexity  
A restore() 0 13 3
A saveRevision() 0 13 1
A tableExists() 0 8 2
A setRecordUpdateTime() 0 3 1
A getMainTableData() 0 3 1
A setTableData() 0 9 2
A getI18nTableData() 0 3 1
A insertI18nTableData() 0 5 2
A getAllColumnNamesWithoutId() 0 4 1
A deleteOriginalI18nData() 0 3 1
A add() 0 6 1
A initRevisionData() 0 13 2
A ifRevisionMathOriginal() 0 3 2
A setMainTableData() 0 4 1
A __construct() 0 7 1
A setI18nTableData() 0 6 2
A i18nTableExists() 0 3 1
A updateMainTableData() 0 5 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace aspirantzhang\octopusRevision;
6
7
use think\facade\Db;
8
use think\Exception;
9
10
class Revision
11
{
12
    private $tableName;
13
    private $i18nTableName;
14
    private $originalId;
15
    private $revisionId;
16
    private $mainTableData;
17
    private $i18nTableData;
18
    private $recordUpdateTime;
19
20
    public function __construct(string $tableName, int $originalId)
21
    {
22
        $this->tableName = $tableName;
23
        $this->i18nTableName = $tableName . '_i18n';
24
        $this->originalId = (int)$originalId;
25
        $this->mainTableData = '[]';
26
        $this->i18nTableData = '[]';
27
    }
28
29
    private function setMainTableData(array $data)
30
    {
31
        unset($data['id']);
32
        $this->mainTableData = json_encode($data);
33
    }
34
35
    private function getMainTableData()
36
    {
37
        return json_decode($this->mainTableData, true);
38
    }
39
40
    private function setI18nTableData(array $data)
41
    {
42
        foreach ($data as &$singleI18nRecord) {
43
            unset($singleI18nRecord['_id']);
44
        }
45
        $this->i18nTableData = json_encode($data);
46
    }
47
48
    private function setRecordUpdateTime(string $time)
49
    {
50
        $this->recordUpdateTime = $time;
51
    }
52
53
    private function getI18nTableData()
54
    {
55
        return json_decode($this->i18nTableData, true);
56
    }
57
58
    private function i18nTableExists(): bool
59
    {
60
        return $this->tableExists($this->i18nTableName);
61
    }
62
63
    private function setTableData(): void
64
    {
65
        $record = Db::table($this->tableName)->where('id', $this->originalId)->find();
66
        $this->setMainTableData($record);
67
        $this->setRecordUpdateTime($record['update_time']);
68
69
        if ($this->i18nTableExists()) {
70
            $i18nRecord = Db::table($this->i18nTableName)->where('original_id', $this->originalId)->select()->toArray();
71
            $this->setI18nTableData($i18nRecord);
72
        }
73
    }
74
75
    private function saveRevision(string $title)
76
    {
77
        $currentTime = date('Y-m-d H:i:s');
78
        $data = [
79
            'table_name' => $this->tableName,
80
            'original_id' => $this->originalId,
81
            'title' => $title,
82
            'main_data' => $this->mainTableData,
83
            'i18n_data' => $this->i18nTableData,
84
            'create_time' => $this->recordUpdateTime,
85
            'update_time' => $currentTime
86
        ];
87
        return Db::name('revision')->insertGetId($data);
88
    }
89
90
    public function add(string $title)
91
    {
92
        // TODO: catch exception
93
        $this->setTableData();
94
        $revisionId = $this->saveRevision($title);
95
        return $revisionId;
96
    }
97
98
    private function initRevisionData()
99
    {
100
        $revision = Db::table('revision')->where('id', $this->revisionId)->find();
101
        if ($revision) {
102
            $this->mainTableData = $revision['main_data'];
103
            $this->i18nTableData = $revision['i18n_data'];
104
            return [
105
                'tableName' => $revision['table_name'],
106
                'originalId' => $revision['original_id'],
107
                'title' => $revision['title'],
108
            ];
109
        }
110
        return [];
111
    }
112
113
    private function ifRevisionMathOriginal(array $revisionData): bool
114
    {
115
        return ($revisionData['tableName'] === $this->tableName) && ($revisionData['originalId'] === $this->originalId);
116
    }
117
118
    private function updateMainTableData()
119
    {
120
        $effectRowsNumber = Db::name($this->tableName)->where('id', $this->originalId)->update($this->getMainTableData());
121
        if ($effectRowsNumber === 0) {
122
            throw new Exception(__('restore main table data failed'));
123
        }
124
    }
125
126
    private function deleteOriginalI18nData()
127
    {
128
        Db::table($this->i18nTableName)->where('original_id', $this->originalId)->delete();
129
    }
130
131
    private function insertI18nTableData()
132
    {
133
        $insertTotal = Db::name($this->i18nTableName)->insertAll($this->getI18nTableData());
134
        if ($insertTotal !== count($this->getI18nTableData())) {
135
            throw new Exception(__('restore i18n table data failed'));
136
        }
137
    }
138
139
    public function restore(int $revisionId)
140
    {
141
        try {
142
            $this->revisionId = $revisionId;
143
            $revisionData = $this->initRevisionData();
144
            if (false === $this->ifRevisionMathOriginal($revisionData)) {
145
                throw new Exception("The revision does not match the original record.");
146
            }
147
            $this->updateMainTableData();
148
            $this->deleteOriginalI18nData();
149
            $this->insertI18nTableData();
150
        } catch (Exception $e) {
151
            throw new Exception($e->getMessage());
152
        }
153
    }
154
155
    private function getAllColumnNamesWithoutId(array $record): array
0 ignored issues
show
Unused Code introduced by
The method getAllColumnNamesWithoutId() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
156
    {
157
        $names = array_keys($record);
158
        return array_diff($names, ['id', '_id']);
159
    }
160
161
    private function tableExists(string $tableName): bool
162
    {
163
        try {
164
            Db::query("select 1 from `$tableName` LIMIT 1");
165
        } catch (Exception $e) {
166
            return false;
167
        }
168
        return true;
169
    }
170
}
171