Skip to content

Commit e25b673

Browse files
Merge d0b81aa into 699cb2a
2 parents 699cb2a + d0b81aa commit e25b673

File tree

7 files changed

+369
-29
lines changed

7 files changed

+369
-29
lines changed

src/Application/AuditApplication.php

100644100755
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace SetBased\Audit\Application;
44

55
use SetBased\Audit\Command\AboutCommand;
6+
use SetBased\Audit\MySql\Command\AlterTableCommand;
67
use SetBased\Audit\MySql\Command\AuditCommand;
78
use SetBased\Audit\MySql\Command\DiffCommand;
89
use SetBased\Audit\MySql\Command\DropTriggersCommand;
@@ -38,6 +39,7 @@ protected function getDefaultCommands()
3839
$commands[] = new AuditCommand();
3940
$commands[] = new DiffCommand();
4041
$commands[] = new DropTriggersCommand();
42+
$commands[] = new AlterTableCommand();
4143

4244
return $commands;
4345
}

src/MySql/AuditAlter.php

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
<?php
2+
//----------------------------------------------------------------------------------------------------------------------
3+
namespace SetBased\Audit\MySql;
4+
5+
use SetBased\Audit\MySql\Helper\MySqlAlterTableCodeStore;
6+
use SetBased\Audit\MySql\Metadata\ColumnMetadata;
7+
use SetBased\Audit\MySql\Metadata\MultiSourceColumnMetadata;
8+
use SetBased\Audit\MySql\Metadata\TableColumnsMetadata;
9+
use SetBased\Stratum\MySql\StaticDataLayer;
10+
11+
//----------------------------------------------------------------------------------------------------------------------
12+
/**
13+
* Class for executing auditing actions for tables.
14+
*/
15+
class AuditAlter
16+
{
17+
//--------------------------------------------------------------------------------------------------------------------
18+
/**
19+
* The metadata (additional) audit columns (as stored in the config file).
20+
*
21+
* @var array[]
22+
*/
23+
private $auditColumnsMetadata;
24+
25+
/**
26+
* The names of all tables in audit schema.
27+
*
28+
* @var array
29+
*/
30+
private $auditSchemaTables;
31+
32+
/**
33+
* Code store for alter table statement.
34+
*
35+
* @var MySqlAlterTableCodeStore
36+
*/
37+
private $codeStore;
38+
39+
/**
40+
* The content of the configuration file.
41+
*
42+
* @var array
43+
*/
44+
private $config;
45+
46+
/**
47+
* Config metadata columns.
48+
*
49+
* @var array
50+
*/
51+
private $configMetadata;
52+
53+
/**
54+
* The names of all tables in data schema.
55+
*
56+
* @var array
57+
*/
58+
private $dataSchemaTables;
59+
60+
/**
61+
* Array with columns for each table.
62+
*
63+
* @var array<string,AuditDiffTable>
64+
*/
65+
private $diffColumns;
66+
67+
//--------------------------------------------------------------------------------------------------------------------
68+
/**
69+
* Object constructor.
70+
*
71+
* @param array[] $config The content of the configuration file.
72+
* @param array[] $configMetadata The content of the metadata file.
73+
*/
74+
public function __construct(&$config, $configMetadata)
75+
{
76+
$this->config = &$config;
77+
$this->configMetadata = $configMetadata;
78+
$this->codeStore = new MySqlAlterTableCodeStore();
79+
}
80+
81+
//--------------------------------------------------------------------------------------------------------------------
82+
/**
83+
* Create Sql statement for alter table.
84+
*
85+
* @param string $tableName The table name.
86+
* @param TableColumnsMetadata $columns Columns metadata for alter statement.
87+
*/
88+
public function createSqlStatement($tableName, $columns)
89+
{
90+
$editCharSet = false;
91+
$charSet = '';
92+
$this->codeStore->append(sprintf('ALTER TABLE %s CHANGE', $tableName));
93+
$countMax = $columns->getNumberOfColumns();
94+
$count = 1;
95+
/** @var MultiSourceColumnMetadata $rowMetadata */
96+
foreach ($columns->getColumns() as $columnName => $rowMetadata)
97+
{
98+
$columnProperties = $rowMetadata->getProperties();
99+
/** @var ColumnMetadata $data */
100+
$data = isset($columnProperties['data']) ? $columnProperties['data'] : null;
101+
/** @var ColumnMetadata $config */
102+
$config = isset($columnProperties['config']) ? $columnProperties['config'] : null;
103+
104+
$dataMetadata = isset($data) ? $data->getProperties() : null;
105+
$configMetadata = isset($config) ? $config->getProperties() : null;
106+
107+
if (!isset($dataMetadata))
108+
{
109+
if (isset($configMetadata['character_set_name']))
110+
{
111+
$editCharSet = true;
112+
$charSet = $configMetadata['character_set_name'];
113+
}
114+
$line = sprintf('%s %s %s', $columnName, $columnName, $configMetadata['column_type']);
115+
if ($count!=$countMax) $line .= ',';
116+
$this->codeStore->append($line);
117+
}
118+
else
119+
{
120+
if (isset($dataMetadata['character_set_name']))
121+
{
122+
$editCharSet = true;
123+
$charSet = $dataMetadata['character_set_name'];
124+
}
125+
$line = sprintf('%s %s %s', $columnName, $columnName, $dataMetadata['column_type']);
126+
if ($count!=$countMax) $line .= ',';
127+
$this->codeStore->append($line);
128+
}
129+
$count++;
130+
}
131+
$this->codeStore->append(';');
132+
if ($editCharSet)
133+
{
134+
$this->codeStore->append(sprintf('ALTER TABLE %s DEFAULT CHARACTER SET %s;', $tableName, $charSet));
135+
}
136+
}
137+
138+
139+
140+
//--------------------------------------------------------------------------------------------------------------------
141+
/**
142+
* The main method: executes the create alter table statement actions for tables.
143+
*
144+
* return string
145+
*/
146+
public function main()
147+
{
148+
$this->processData();
149+
150+
return $this->codeStore->getCode();
151+
}
152+
153+
//--------------------------------------------------------------------------------------------------------------------
154+
/**
155+
* Computes the difference between data and audit tables.
156+
*/
157+
private function getDiff()
158+
{
159+
foreach ($this->dataSchemaTables as $table)
160+
{
161+
if ($this->config['tables'][$table['table_name']]['audit'])
162+
{
163+
$res = StaticDataLayer::searchInRowSet('table_name', $table['table_name'], $this->auditSchemaTables);
164+
if (isset($res))
165+
{
166+
$this->diffColumns[$table['table_name']] = new AuditDiffTable($this->config['database']['data_schema'],
167+
$this->config['database']['audit_schema'],
168+
$table['table_name'],
169+
$this->auditColumnsMetadata,
170+
$this->configMetadata[$table['table_name']]);
171+
}
172+
}
173+
}
174+
}
175+
176+
//--------------------------------------------------------------------------------------------------------------------
177+
/**
178+
* Getting list of all tables from information_schema of database from config file.
179+
*/
180+
private function listOfTables()
181+
{
182+
$this->dataSchemaTables = AuditDataLayer::getTablesNames($this->config['database']['data_schema']);
183+
184+
$this->auditSchemaTables = AuditDataLayer::getTablesNames($this->config['database']['audit_schema']);
185+
}
186+
187+
//--------------------------------------------------------------------------------------------------------------------
188+
/**
189+
* Work on data for each table.
190+
*/
191+
private function processData()
192+
{
193+
$this->resolveCanonicalAuditColumns();
194+
195+
$this->listOfTables();
196+
197+
$this->getDiff();
198+
199+
/** @var AuditDiffTable $diffTable */
200+
foreach ($this->diffColumns as $tableName => $diffTable)
201+
{
202+
// Remove matching columns.
203+
$columns = $diffTable->removeMatchingColumns(true);
204+
205+
$this->createSqlStatement($tableName, $columns);
206+
}
207+
}
208+
209+
//--------------------------------------------------------------------------------------------------------------------
210+
/**
211+
* Resolves the canonical column types of the audit table columns.
212+
*/
213+
private function resolveCanonicalAuditColumns()
214+
{
215+
if (empty($this->config['audit_columns']))
216+
{
217+
$this->auditColumnsMetadata = [];
218+
}
219+
else
220+
{
221+
$schema = $this->config['database']['audit_schema'];
222+
$tableName = '_TMP_'.uniqid();
223+
AuditDataLayer::createTemporaryTable($schema, $tableName, $this->config['audit_columns']);
224+
$columns = AuditDataLayer::getTableColumns($schema, $tableName);
225+
AuditDataLayer::dropTemporaryTable($schema, $tableName);
226+
227+
foreach ($this->config['audit_columns'] as $audit_column)
228+
{
229+
$key = StaticDataLayer::searchInRowSet('column_name', $audit_column['column_name'], $columns);
230+
231+
if ($columns[$key]['is_nullable']==='NO')
232+
{
233+
$columns[$key]['column_type'] = sprintf('%s not null', $columns[$key]['column_type']);
234+
}
235+
if (isset($audit_column['value_type']))
236+
{
237+
$columns[$key]['value_type'] = $audit_column['value_type'];
238+
}
239+
if (isset($audit_column['expression']))
240+
{
241+
$columns[$key]['expression'] = $audit_column['expression'];
242+
}
243+
}
244+
245+
$this->auditColumnsMetadata = $columns;
246+
}
247+
}
248+
249+
//--------------------------------------------------------------------------------------------------------------------
250+
}
251+
252+
//----------------------------------------------------------------------------------------------------------------------

src/MySql/AuditDiff.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ private function printDiff()
215215
// Remove matching columns unless the full option is used.
216216
if (!$this->full)
217217
{
218-
$columns = $diffTable->removeMatchingColumns();
218+
$columns = $diffTable->removeMatchingColumns(false);
219219
}
220220

221221
if ($columns->getNumberOfColumns()>0)

src/MySql/AuditDiffTable.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,11 @@ public function getDiffColumns()
9797
/**
9898
* Check full and return array without new or obsolete columns if full not set.
9999
*
100+
* @param bool $skipObsoleteNew Flag for skipping obsolete and new columns.
101+
*
100102
* @return TableColumnsMetadata
101103
*/
102-
public function removeMatchingColumns()
104+
public function removeMatchingColumns($skipObsoleteNew)
103105
{
104106
$metadata = $this->diffColumns->getColumns();
105107
/** @var MultiSourceColumnMetadata $column */
@@ -126,6 +128,10 @@ public function removeMatchingColumns()
126128
}
127129
}
128130
}
131+
elseif ($skipObsoleteNew)
132+
{
133+
$metadata->removeColumn($columnName);
134+
}
129135
}
130136
else
131137
{
@@ -137,6 +143,10 @@ public function removeMatchingColumns()
137143
$metadata->removeColumn($columnName);
138144
}
139145
}
146+
elseif ($skipObsoleteNew)
147+
{
148+
$metadata->removeColumn($columnName);
149+
}
140150
}
141151
}
142152

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
//----------------------------------------------------------------------------------------------------------------------
3+
namespace SetBased\Audit\MySql\Command;
4+
5+
use SetBased\Audit\MySql\AuditAlter;
6+
use SetBased\Stratum\Style\StratumStyle;
7+
use Symfony\Component\Console\Input\InputArgument;
8+
use Symfony\Component\Console\Input\InputInterface;
9+
use Symfony\Component\Console\Output\OutputInterface;
10+
11+
//----------------------------------------------------------------------------------------------------------------------
12+
/**
13+
* Command for comparing data tables with audit tables.
14+
*/
15+
class AlterTableCommand extends AuditCommand
16+
{
17+
//--------------------------------------------------------------------------------------------------------------------
18+
/**
19+
* Check full full and return array without new or obsolete columns if full not set.
20+
*
21+
* @param array[] $columns The metadata of the columns of a table.
22+
*
23+
* @var StratumStyle
24+
*/
25+
protected $io;
26+
27+
//--------------------------------------------------------------------------------------------------------------------
28+
/**
29+
* {@inheritdoc}
30+
*/
31+
protected function configure()
32+
{
33+
$this->setName('alter-table-sql')
34+
->setDescription('Create alter table SQL commands for audit tables columns that are different from the config columns or from columns data tables')
35+
->addArgument('config file', InputArgument::OPTIONAL, 'The audit configuration file', 'etc/audit.json')
36+
->addArgument('result sql file', InputArgument::OPTIONAL, 'The result file for SQL statement', 'etc/alter-table-sql-result.sql');
37+
}
38+
39+
//--------------------------------------------------------------------------------------------------------------------
40+
/**
41+
* {@inheritdoc}
42+
*/
43+
protected function execute(InputInterface $input, OutputInterface $output)
44+
{
45+
$this->io = new StratumStyle($input, $output);
46+
47+
$resultSqlFile = $input->getArgument('result sql file');
48+
49+
$this->configFileName = $input->getArgument('config file');
50+
$this->readConfigFile();
51+
52+
$this->connect($this->config);
53+
54+
$alter = new AuditAlter($this->config, $this->configMetadata);
55+
$content = $alter->main();
56+
57+
$this->writeTwoPhases($resultSqlFile, $content);
58+
}
59+
60+
//--------------------------------------------------------------------------------------------------------------------
61+
62+
}
63+
64+
//----------------------------------------------------------------------------------------------------------------------

0 commit comments

Comments
 (0)