|
1
|
|
|
<?php |
|
2
|
|
|
//---------------------------------------------------------------------------------------------------------------------- |
|
3
|
|
|
namespace SetBased\Audit\MySql; |
|
4
|
|
|
|
|
5
|
|
|
use SetBased\Audit\MySql\Metadata\TableColumnsMetadata; |
|
6
|
|
|
use SetBased\Audit\MySql\Metadata\TableMetadata; |
|
7
|
|
|
use SetBased\Stratum\MySql\StaticDataLayer; |
|
8
|
|
|
use SetBased\Stratum\Style\StratumStyle; |
|
9
|
|
|
|
|
10
|
|
|
//---------------------------------------------------------------------------------------------------------------------- |
|
11
|
|
|
/** |
|
12
|
|
|
* Class for executing auditing actions for tables. |
|
13
|
|
|
*/ |
|
14
|
|
|
class Audit |
|
15
|
|
|
{ |
|
16
|
|
|
//-------------------------------------------------------------------------------------------------------------------- |
|
17
|
|
|
/** |
|
18
|
|
|
* The metadata (additional) audit columns (as stored in the config file). |
|
19
|
|
|
* |
|
20
|
|
|
* @var TableColumnsMetadata |
|
21
|
|
|
*/ |
|
22
|
|
|
private $auditColumnsMetadata; |
|
23
|
|
|
|
|
24
|
|
|
/** |
|
25
|
|
|
* The names of all tables in audit schema. |
|
26
|
|
|
* |
|
27
|
|
|
* @var array |
|
28
|
|
|
*/ |
|
29
|
|
|
private $auditSchemaTables; |
|
30
|
|
|
|
|
31
|
|
|
/** |
|
32
|
|
|
* The content of the configuration file. |
|
33
|
|
|
* |
|
34
|
|
|
* @var array |
|
35
|
|
|
*/ |
|
36
|
|
|
private $config; |
|
37
|
|
|
|
|
38
|
|
|
/** |
|
39
|
|
|
* Tables metadata from config file. |
|
40
|
|
|
* |
|
41
|
|
|
* @var array |
|
42
|
|
|
*/ |
|
43
|
|
|
private $configMetadata; |
|
44
|
|
|
|
|
45
|
|
|
/** |
|
46
|
|
|
* The names of all tables in data schema. |
|
47
|
|
|
* |
|
48
|
|
|
* @var array |
|
49
|
|
|
*/ |
|
50
|
|
|
private $dataSchemaTables; |
|
51
|
|
|
|
|
52
|
|
|
/** |
|
53
|
|
|
* The Output decorator. |
|
54
|
|
|
* |
|
55
|
|
|
* @var StratumStyle |
|
56
|
|
|
*/ |
|
57
|
|
|
private $io; |
|
58
|
|
|
|
|
59
|
|
|
/** |
|
60
|
|
|
* If true remove all column information from config file. |
|
61
|
|
|
* |
|
62
|
|
|
* @var boolean |
|
63
|
|
|
*/ |
|
64
|
|
|
private $pruneOption; |
|
65
|
|
|
|
|
66
|
|
|
//-------------------------------------------------------------------------------------------------------------------- |
|
67
|
|
|
/** |
|
68
|
|
|
* Object constructor. |
|
69
|
|
|
* |
|
70
|
|
|
* @param array[] $config The content of the configuration file. |
|
71
|
|
|
* @param array[] $configMetadata The content of the metadata file. |
|
72
|
|
|
* @param StratumStyle $io The Output decorator. |
|
73
|
|
|
*/ |
|
74
|
13 |
|
public function __construct(&$config, &$configMetadata, $io) |
|
75
|
|
|
{ |
|
76
|
13 |
|
$this->config = &$config; |
|
77
|
13 |
|
$this->configMetadata = &$configMetadata; |
|
78
|
13 |
|
$this->io = $io; |
|
79
|
13 |
|
} |
|
80
|
|
|
|
|
81
|
|
|
//-------------------------------------------------------------------------------------------------------------------- |
|
82
|
|
|
/** |
|
83
|
|
|
* Getting list of all tables from information_schema of database from config file. |
|
84
|
|
|
*/ |
|
85
|
13 |
|
public function listOfTables() |
|
86
|
|
|
{ |
|
87
|
13 |
|
$this->dataSchemaTables = AuditDataLayer::getTablesNames($this->config['database']['data_schema']); |
|
88
|
|
|
|
|
89
|
13 |
|
$this->auditSchemaTables = AuditDataLayer::getTablesNames($this->config['database']['audit_schema']); |
|
90
|
13 |
|
} |
|
91
|
|
|
|
|
92
|
|
|
//-------------------------------------------------------------------------------------------------------------------- |
|
93
|
|
|
/** |
|
94
|
|
|
* The main method: executes the auditing actions for tables. |
|
95
|
|
|
* |
|
96
|
|
|
* @return int The exit status. |
|
97
|
|
|
*/ |
|
98
|
13 |
|
public function main() |
|
99
|
|
|
{ |
|
100
|
13 |
|
if ($this->pruneOption) |
|
101
|
13 |
|
{ |
|
102
|
|
|
$this->configMetadata['table_columns'] = []; |
|
103
|
|
|
} |
|
104
|
|
|
|
|
105
|
13 |
|
$this->resolveCanonicalAuditColumns(); |
|
106
|
|
|
|
|
107
|
13 |
|
$this->listOfTables(); |
|
108
|
|
|
|
|
109
|
13 |
|
$this->unknownTables(); |
|
110
|
|
|
|
|
111
|
13 |
|
$status = $this->knownTables(); |
|
112
|
|
|
|
|
113
|
13 |
|
return $status; |
|
114
|
|
|
} |
|
115
|
|
|
|
|
116
|
|
|
//-------------------------------------------------------------------------------------------------------------------- |
|
117
|
|
|
/** |
|
118
|
|
|
* Sets the columns metadata of a table in the configuration file. |
|
119
|
|
|
* |
|
120
|
|
|
* @param string $tableName The name of table. |
|
121
|
|
|
* @param TableColumnsMetadata $columns The metadata of the table columns. |
|
122
|
|
|
*/ |
|
123
|
12 |
|
public function setConfigTableColumns($tableName, $columns) |
|
124
|
|
|
{ |
|
125
|
12 |
|
$newColumns = []; |
|
126
|
12 |
|
foreach ($columns->getColumns() as $column) |
|
127
|
|
|
{ |
|
128
|
12 |
|
$newColumns[] = $column->getProperties(); |
|
129
|
12 |
|
} |
|
130
|
12 |
|
$this->configMetadata['table_columns'][$tableName] = $newColumns; |
|
131
|
12 |
|
} |
|
132
|
|
|
|
|
133
|
|
|
//-------------------------------------------------------------------------------------------------------------------- |
|
134
|
|
|
/** |
|
135
|
|
|
* Compares the tables listed in the config file and the tables found in the data schema. |
|
136
|
|
|
*/ |
|
137
|
13 |
|
public function unknownTables() |
|
138
|
|
|
{ |
|
139
|
13 |
|
foreach ($this->dataSchemaTables as $table) |
|
140
|
|
|
{ |
|
141
|
12 |
|
if (isset($this->config['tables'][$table['table_name']])) |
|
142
|
12 |
|
{ |
|
143
|
12 |
|
if (!isset($this->config['tables'][$table['table_name']]['audit'])) |
|
144
|
12 |
|
{ |
|
145
|
|
|
$this->io->writeln(sprintf('<info>audit is not set for table %s</info>', $table['table_name'])); |
|
146
|
|
|
} |
|
147
|
|
|
else |
|
148
|
|
|
{ |
|
149
|
12 |
|
if ($this->config['tables'][$table['table_name']]['audit']) |
|
150
|
12 |
|
{ |
|
151
|
12 |
|
if (!isset($this->config['tables'][$table['table_name']]['alias'])) |
|
152
|
12 |
|
{ |
|
153
|
|
|
$this->config['tables'][$table['table_name']]['alias'] = AuditTable::getRandomAlias(); |
|
154
|
|
|
} |
|
155
|
12 |
|
} |
|
156
|
|
|
} |
|
157
|
12 |
|
} |
|
158
|
|
|
else |
|
159
|
|
|
{ |
|
160
|
|
|
$this->io->writeln(sprintf('<info>Found new table %s</info>', $table['table_name'])); |
|
161
|
|
|
$this->config['tables'][$table['table_name']] = ['audit' => false, |
|
162
|
|
|
'alias' => null, |
|
163
|
|
|
'skip' => null]; |
|
164
|
|
|
} |
|
165
|
13 |
|
} |
|
166
|
13 |
|
} |
|
167
|
|
|
|
|
168
|
|
|
//-------------------------------------------------------------------------------------------------------------------- |
|
169
|
|
|
/** |
|
170
|
|
|
* Resolves the canonical column types of the audit table columns. |
|
171
|
|
|
*/ |
|
172
|
13 |
View Code Duplication |
protected function resolveCanonicalAuditColumns() |
|
|
|
|
|
|
173
|
|
|
{ |
|
174
|
13 |
|
if (empty($this->config['audit_columns'])) |
|
175
|
13 |
|
{ |
|
176
|
4 |
|
$this->auditColumnsMetadata = new TableColumnsMetadata(); |
|
177
|
4 |
|
} |
|
178
|
|
|
else |
|
179
|
|
|
{ |
|
180
|
9 |
|
$schema = $this->config['database']['audit_schema']; |
|
181
|
9 |
|
$tableName = '_TMP_'.uniqid(); |
|
182
|
9 |
|
AuditDataLayer::createTemporaryTable($schema, $tableName, $this->config['audit_columns']); |
|
183
|
9 |
|
$columns = AuditDataLayer::getTableColumns($schema, $tableName); |
|
184
|
9 |
|
AuditDataLayer::dropTemporaryTable($schema, $tableName); |
|
185
|
|
|
|
|
186
|
9 |
|
foreach ($this->config['audit_columns'] as $audit_column) |
|
187
|
|
|
{ |
|
188
|
9 |
|
$key = StaticDataLayer::searchInRowSet('column_name', $audit_column['column_name'], $columns); |
|
189
|
9 |
|
if (isset($audit_column['value_type'])) |
|
190
|
9 |
|
{ |
|
191
|
9 |
|
$columns[$key]['value_type'] = $audit_column['value_type']; |
|
192
|
9 |
|
} |
|
193
|
9 |
|
if (isset($audit_column['expression'])) |
|
194
|
9 |
|
{ |
|
195
|
2 |
|
$columns[$key]['expression'] = $audit_column['expression']; |
|
196
|
2 |
|
} |
|
197
|
9 |
|
} |
|
198
|
|
|
|
|
199
|
9 |
|
$this->auditColumnsMetadata = new TableColumnsMetadata($columns, 'AuditColumnMetadata'); |
|
200
|
|
|
} |
|
201
|
13 |
|
} |
|
202
|
|
|
|
|
203
|
|
|
//-------------------------------------------------------------------------------------------------------------------- |
|
204
|
|
|
/** |
|
205
|
|
|
* Processed known tables. |
|
206
|
|
|
* |
|
207
|
|
|
* @return int The exit status. |
|
208
|
|
|
*/ |
|
209
|
13 |
|
private function knownTables() |
|
210
|
|
|
{ |
|
211
|
13 |
|
$status = 0; |
|
212
|
|
|
|
|
213
|
13 |
|
foreach ($this->dataSchemaTables as $table) |
|
214
|
|
|
{ |
|
215
|
12 |
|
if ($this->config['tables'][$table['table_name']]['audit']) |
|
216
|
12 |
|
{ |
|
217
|
12 |
|
if (isset($this->configMetadata['table_columns'][$table['table_name']])) |
|
218
|
12 |
|
{ |
|
219
|
1 |
|
$tableColumns = $this->configMetadata['table_columns'][$table['table_name']]; |
|
220
|
1 |
|
} |
|
221
|
|
|
else |
|
222
|
|
|
{ |
|
223
|
11 |
|
$tableColumns = []; |
|
224
|
|
|
} |
|
225
|
12 |
|
$configTable = new TableMetadata($table['table_name'], |
|
226
|
12 |
|
$this->config['database']['data_schema'], |
|
227
|
12 |
|
$tableColumns); |
|
228
|
|
|
|
|
229
|
12 |
|
$currentTable = new AuditTable($this->io, |
|
230
|
12 |
|
$configTable, |
|
231
|
12 |
|
$this->config['database']['audit_schema'], |
|
232
|
12 |
|
$this->auditColumnsMetadata, |
|
233
|
12 |
|
$this->config['tables'][$table['table_name']]['alias'], |
|
234
|
12 |
|
$this->config['tables'][$table['table_name']]['skip']); |
|
235
|
|
|
|
|
236
|
|
|
// Ensure an audit table exists. |
|
237
|
12 |
|
if (StaticDataLayer::searchInRowSet('table_name', $table['table_name'], $this->auditSchemaTables)===null) |
|
238
|
12 |
|
{ |
|
239
|
9 |
|
$currentTable->createAuditTable(); |
|
240
|
9 |
|
} |
|
241
|
|
|
|
|
242
|
|
|
// Drop and create audit triggers and add new columns to the audit table. |
|
243
|
12 |
|
$ok = $currentTable->main($this->config['additional_sql']); |
|
244
|
|
|
if ($ok) |
|
245
|
12 |
|
{ |
|
246
|
12 |
|
$columns = new TableColumnsMetadata(AuditDataLayer::getTableColumns($this->config['database']['data_schema'], |
|
247
|
12 |
|
$table['table_name'])); |
|
248
|
12 |
|
$this->setConfigTableColumns($table['table_name'], $columns); |
|
249
|
12 |
|
} |
|
250
|
|
|
else |
|
251
|
|
|
{ |
|
252
|
1 |
|
$status += 1; |
|
253
|
|
|
} |
|
254
|
12 |
|
} |
|
255
|
13 |
|
} |
|
256
|
|
|
|
|
257
|
13 |
|
return $status; |
|
258
|
|
|
} |
|
259
|
|
|
|
|
260
|
|
|
//-------------------------------------------------------------------------------------------------------------------- |
|
261
|
|
|
} |
|
262
|
|
|
|
|
263
|
|
|
//---------------------------------------------------------------------------------------------------------------------- |
|
264
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.