Completed
Pull Request — master (#55)
by Dima
03:18
created

AuditDiff::getDiff()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 4

Importance

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

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
325
    }
326 4
  }
327
328
  //--------------------------------------------------------------------------------------------------------------------
329
}
330
331
//----------------------------------------------------------------------------------------------------------------------
332