Completed
Push — master ( d10df0...c2fd32 )
by P.R.
07:30
created

AuditDiff::listOfTables()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 6
ccs 4
cts 4
cp 1
rs 9.4285
cc 1
eloc 3
nc 1
nop 0
crap 1
1
<?php
2
3
namespace SetBased\Audit\MySql;
4
5
use SetBased\Audit\MySql\Helper\DiffTableHelper;
6
use SetBased\Exception\FallenException;
7
use SetBased\Stratum\Style\StratumStyle;
8
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
9
use Symfony\Component\Console\Helper\Table;
10
use Symfony\Component\Console\Input\InputInterface;
11
use Symfony\Component\Console\Output\OutputInterface;
12
13
/**
14
 * Class for executing auditing actions for tables.
15
 */
16
class AuditDiff
17
{
18
  //--------------------------------------------------------------------------------------------------------------------
19
  /**
20
   * The metadata (additional) audit columns (as stored in the config file).
21
   *
22
   * @var array<integer,object<array>>
23
   */
24
  private $auditColumnsMetadata;
25
26
  /**
27
   * The names of all tables in audit schema.
28
   *
29
   * @var array
30
   */
31
  private $auditSchemaTables;
32
33
  /**
34
   * The content of the configuration file.
35
   *
36
   * @var array
37
   */
38
  private $config;
39
40
  /**
41
   * Config metadata columns.
42
   *
43
   * @var array
44
   */
45
  private $configMetadata;
46
47
  /**
48
   * The names of all tables in data schema.
49
   *
50
   * @var array
51
   */
52
  private $dataSchemaTables;
53
54
  /**
55
   * Array with columns for each table.
56
   *
57
   * @var array<string,AuditDiffTable>
58
   */
59
  private $diffColumns;
60
61
  /**
62
   * If set all tables and columns are shown.
63
   *
64
   * @var boolean
65
   */
66
  private $full;
67
68
  /**
69
   * The Input interface.
70
   *
71
   * @var InputInterface
72
   */
73
  private $input;
74
75
  /**
76
   * The Output decorator.
77
   *
78
   * @var StratumStyle
79
   */
80
  private $io;
81
82
  /**
83
   * The Output interface.
84
   *
85
   * @var OutputInterface
86
   */
87
  private $output;
88
89
  //--------------------------------------------------------------------------------------------------------------------
90
  /**
91
   * Object constructor.
92
   *
93
   * @param array[]         $config         The content of the configuration file.
94
   * @param array[]         $configMetadata The content of the metadata file.
95
   * @param StratumStyle    $io             The Output decorator.
96
   * @param InputInterface  $input
97
   * @param OutputInterface $output
98
   */
99 4
  public function __construct(&$config, $configMetadata, $io, $input, $output)
100
  {
101 4
    $this->io             = $io;
102 4
    $this->config         = &$config;
103 4
    $this->configMetadata = $configMetadata;
104 4
    $this->input          = $input;
105 4
    $this->output         = $output;
106 4
  }
107
108
  //--------------------------------------------------------------------------------------------------------------------
109
  /**
110
   * The main method: executes the auditing actions for tables.
111
   */
112 4
  public function main()
113
  {
114
    // Style for column names with miss matched column types.
115 4
    $style = new OutputFormatterStyle(null, 'red');
116 4
    $this->output->getFormatter()->setStyle('mm_column', $style);
117
118
    // Style for column types of columns with miss matched column types.
119 4
    $style = new OutputFormatterStyle('yellow');
120 4
    $this->output->getFormatter()->setStyle('mm_type', $style);
121
122
    // Style for obsolete tables.
123 4
    $style = new OutputFormatterStyle('yellow');
124 4
    $this->output->getFormatter()->setStyle('obsolete_table', $style);
125
126
    // Style for missing tables.
127 4
    $style = new OutputFormatterStyle('red');
128 4
    $this->output->getFormatter()->setStyle('miss_table', $style);
129
130 4
    $this->full = $this->input->getOption('full');
131
132 4
    $this->resolveCanonicalAuditColumns();
133
134 4
    $this->listOfTables();
135
136 4
    $this->getDiff();
137
138 4
    $this->printDiff();
139 4
  }
140
141
  //--------------------------------------------------------------------------------------------------------------------
142
  /**
143
   * Writes the difference between the audit tables and metadata tables to the output.
144
   */
145 4
  private function diffTables()
146
  {
147 4
    $missTables     = [];
148 4
    $obsoleteTables = [];
149 4
    foreach ($this->config['tables'] as $tableName => $table)
150
    {
151 4
      $res = AuditDataLayer::searchInRowSet('table_name', $tableName, $this->auditSchemaTables);
152 4
      if ($table['audit'] && !isset($res))
153
      {
154
        $missTables[] = $tableName;
155
      }
156 4
      else if (!$table['audit'] && isset($res))
157
      {
158 4
        $obsoleteTables[] = $tableName;
159
      }
160
    }
161 4
    $this->printMissObsoleteTables('missing', $missTables);
162 4
    $this->printMissObsoleteTables('obsolete', $obsoleteTables);
163 4
  }
164
165
  //--------------------------------------------------------------------------------------------------------------------
166
  /**
167
   * Computes the difference between data and audit tables.
168
   */
169 4
  private function getDiff()
170
  {
171 4
    foreach ($this->dataSchemaTables as $table)
172
    {
173 4
      if ($this->config['tables'][$table['table_name']]['audit'])
174
      {
175 4
        $res = AuditDataLayer::searchInRowSet('table_name', $table['table_name'], $this->auditSchemaTables);
176 4
        if (isset($res))
177
        {
178 4
          $this->diffColumns[$table['table_name']] = new AuditDiffTable($this->config['database']['data_schema'],
179 4
                                                                        $this->config['database']['audit_schema'],
180 4
                                                                        $table['table_name'],
181 4
                                                                        $this->auditColumnsMetadata,
182 4
                                                                        $this->configMetadata[$table['table_name']]);
183
        }
184
      }
185
    }
186 4
  }
187
188
  //--------------------------------------------------------------------------------------------------------------------
189
  /**
190
   * Getting list of all tables from information_schema of database from config file.
191
   */
192 4
  private function listOfTables()
193
  {
194 4
    $this->dataSchemaTables = AuditDataLayer::getTablesNames($this->config['database']['data_schema']);
195
196 4
    $this->auditSchemaTables = AuditDataLayer::getTablesNames($this->config['database']['audit_schema']);
197 4
  }
198
199
  //--------------------------------------------------------------------------------------------------------------------
200
  /**
201
   * Writes the difference between the audit and data tables to the output.
202
   */
203 4
  private function printDiff()
204
  {
205 4
    $first = true;
206 4
    if (isset($this->diffColumns))
207
    {
208
      /** @var AuditDiffTable $diffTable */
209 4
      foreach ($this->diffColumns as $tableName => $diffTable)
210
      {
211 4
        $columns = $diffTable->getDiffColumns();
212
        // Remove matching columns unless the full option is used.
213 4
        if (!$this->full)
214
        {
215 4
          $columns = $diffTable->removeMatchingColumns(false);
216
        }
217
218 4
        if ($columns->getNumberOfColumns()>0)
219
        {
220
          // Add an empty line between tables.
221 4
          if ($first)
222
          {
223 4
            $first = false;
224
          }
225
          else
226
          {
227
            $this->output->writeln('');
228
          }
229
230
          // Write table name.
231 4
          $this->output->writeln($tableName);
232
233
          // Write table with columns.
234 4
          $rows = new DiffTableHelper($this->config['database']['data_schema'],
235 4
                                      $this->config['database']['audit_schema'],
236 4
                                      $tableName,
237 4
                                      $this->auditColumnsMetadata,
238 4
                                      $this->full);
239 4
          $rows->appendRows($columns);
240 4
          $rows->addHighlighting();
241 4
          $table = new Table($this->output);
242 4
          $table->setHeaders(['column', 'data table', 'audit table', 'config'])
243 4
                ->setRows($rows->getRows());
244 4
          $table->render();
245
        }
246
      }
247 4
      $this->diffTables();
248
    }
249 4
  }
250
251
  //--------------------------------------------------------------------------------------------------------------------
252
  /**
253
   * Print missing or obsolete tables;
254
   *
255
   * @param string  $tableType Missing or obsolete.
256
   * @param array[] $tables    Table names array.
257
   */
258 4
  private function printMissObsoleteTables($tableType, $tables)
259
  {
260 4
    if (!empty($tables))
261
    {
262
      switch ($tableType)
263
      {
264
        case 'missing':
265
          $tag = 'miss_table';
266
          $this->output->writeln('<miss_table>Missing Tables:</>');
267
          break;
268
269
        case 'obsolete':
270
          $tag = 'obsolete_table';
271
          $this->output->writeln('<obsolete_table>Obsolete Tables:</>');
272
          break;
273
274
        default:
275
          throw new FallenException('table type', $tableType);
276
      }
277
278
      foreach ($tables as $tableName)
279
      {
280
        $this->output->writeln(sprintf('<%s>%s</>', $tag, $tableName));
281
      }
282
    }
283 4
  }
284
285
  //--------------------------------------------------------------------------------------------------------------------
286
  /**
287
   * Resolves the canonical column types of the audit table columns.
288
   */
289 4
  private function resolveCanonicalAuditColumns()
290
  {
291 4
    if (empty($this->config['audit_columns']))
292
    {
293 4
      $this->auditColumnsMetadata = [];
294
    }
295
    else
296
    {
297
      $schema    = $this->config['database']['audit_schema'];
298
      $tableName = '_TMP_'.uniqid();
299
      AuditDataLayer::createTemporaryTable($schema, $tableName, $this->config['audit_columns']);
300
      $columns = AuditDataLayer::getTableColumns($schema, $tableName);
301
      AuditDataLayer::dropTemporaryTable($schema, $tableName);
302
303
      foreach ($this->config['audit_columns'] as $audit_column)
304
      {
305
        $key = AuditDataLayer::searchInRowSet('column_name', $audit_column['column_name'], $columns);
306
307
        if ($columns[$key]['is_nullable']==='NO')
308
        {
309
          $columns[$key]['column_type'] = sprintf('%s not null', $columns[$key]['column_type']);
310
        }
311
        if (isset($audit_column['value_type']))
312
        {
313
          $columns[$key]['value_type'] = $audit_column['value_type'];
314
        }
315
        if (isset($audit_column['expression']))
316
        {
317
          $columns[$key]['expression'] = $audit_column['expression'];
318
        }
319
      }
320
321
      $this->auditColumnsMetadata = $columns;
322
    }
323 4
  }
324
325
  //--------------------------------------------------------------------------------------------------------------------
326
}
327
328
//----------------------------------------------------------------------------------------------------------------------
329