Completed
Push — master ( c95337...5e0152 )
by P.R.
04:34
created

AuditDiff::printDiff()   B

Complexity

Conditions 6
Paths 8

Size

Total Lines 47
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 24
CRAP Score 6.0023

Importance

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