Completed
Push — master ( 0ae374...bdde66 )
by P.R.
02:24
created

DiffCommand::addNotNull()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 19
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 19
rs 9.2
cc 4
eloc 10
nc 4
nop 1
1
<?php
2
//----------------------------------------------------------------------------------------------------------------------
3
namespace SetBased\Audit\Command;
4
5
use SetBased\Audit\Columns;
6
use SetBased\Audit\MySql\Command\AuditCommand;
7
use SetBased\Audit\MySql\DataLayer;
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\InputArgument;
13
use Symfony\Component\Console\Input\InputInterface;
14
use Symfony\Component\Console\Input\InputOption;
15
use Symfony\Component\Console\Output\OutputInterface;
16
17
//----------------------------------------------------------------------------------------------------------------------
18
/**
19
 * Command for comparing data tables with audit tables.
20
 */
21
class DiffCommand extends AuditCommand
22
{
23
  //--------------------------------------------------------------------------------------------------------------------
24
  /**
25
   * Array with columns for each table.
26
   * array [
27
   *    table_name [
28
   *            column [
29
   *                    data table type,
30
   *                    audit table type
31
   *                    ],
32
   *                      ...
33
   *               ]
34
   *       ]
35
   *
36
   * @var array[]
37
   */
38
  private $diffColumns;
39
40
  /**
41
   * If set all tables and columns are shown.
42
   *
43
   * @var string
44
   */
45
  private $full;
46
47
  //--------------------------------------------------------------------------------------------------------------------
48
  /**
49
   * Check full full and return array without new or obsolete columns if full not set.
50
   *
51
   * @param array[] $columns The metadata of the columns of a table.
52
   *
53
   * @return array[]
54
   */
55
  private static function removeMatchingColumns($columns)
56
  {
57
    $cleaned = [];
58
    foreach ($columns as $column)
59
    {
60
      if (($column['data_table_type']!=$column['audit_table_type'] && $column['audit_table_type']!=$column['config_type']) || ($column['audit_table_type']!=$column['config_type'] && !empty($column['config_type'])))
61
      {
62
        $cleaned[] = $column;
63
      }
64
    }
65
66
    return $cleaned;
67
  }
68
69
  //--------------------------------------------------------------------------------------------------------------------
70
  /**
71
   * {@inheritdoc}
72
   */
73
  protected function configure()
74
  {
75
    $this->setName('diff')
76
         ->setDescription('Compares data tables and audit tables')
77
         ->addArgument('config file', InputArgument::OPTIONAL, 'The audit configuration file', 'etc/audit.json')
78
         ->addOption('full', 'f', InputOption::VALUE_NONE, 'Show all columns');
79
  }
80
81
  //--------------------------------------------------------------------------------------------------------------------
82
  /**
83
   * {@inheritdoc}
84
   */
85
  protected function execute(InputInterface $input, OutputInterface $output)
86
  {
87
    $this->io = new StratumStyle($input, $output);
88
89
    // Style for column names with miss matched column types.
90
    $style = new OutputFormatterStyle(null, 'red');
91
    $output->getFormatter()->setStyle('mm_column', $style);
92
93
    // Style for column types of columns with miss matched column types.
94
    $style = new OutputFormatterStyle('yellow');
95
    $output->getFormatter()->setStyle('mm_type', $style);
96
97
    // Style for obsolete tables.
98
    $style = new OutputFormatterStyle('yellow');
99
    $output->getFormatter()->setStyle('obsolete_table', $style);
100
101
    // Style for missing tables.
102
    $style = new OutputFormatterStyle('red');
103
    $output->getFormatter()->setStyle('miss_table', $style);
104
105
    $this->configFileName = $input->getArgument('config file');
106
    $this->readConfigFile();
107
108
    $this->full = $input->getOption('full');
109
110
    $this->connect($this->config);
111
112
    $this->listOfTables();
113
114
    $this->getDiff();
115
    $this->printDiff($output);
116
  }
117
118
  //--------------------------------------------------------------------------------------------------------------------
119
  /**
120
   * Add highlighting to columns.
121
   *
122
   * @param array[] $columns The metadata of the columns.
123
   *
124
   * @return array[]
125
   */
126
  private function addHighlighting($columns)
127
  {
128
    $styledColumns = [];
129
    foreach ($columns as $column)
130
    {
131
      $styledColumn = $column;
132
      // Highlighting for data table column types and audit.
133
      if (!empty($column['data_table_type']))
134
      {
135
        if (isset($column['data_table_type']) && !isset($column['audit_table_type']))
136
        {
137
          $styledColumn['column_name']     = sprintf('<mm_column>%s</>', $styledColumn['column_name']);
138
          $styledColumn['data_table_type'] = sprintf('<mm_type>%s</>', $styledColumn['data_table_type']);
139
        }
140
        else if (!isset($column['data_table_type']) && isset($column['audit_table_type']))
141
        {
142
          $styledColumn['audit_table_type'] = sprintf('<mm_type>%s</>', $styledColumn['audit_table_type']);
143
        }
144 View Code Duplication
        else if (strcmp($column['data_table_type'], $column['audit_table_type']) && !isset($configType))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
145
        {
146
          $styledColumn['column_name']      = sprintf('<mm_column>%s</>', $styledColumn['column_name']);
147
          $styledColumn['data_table_type']  = sprintf('<mm_type>%s</>', $styledColumn['data_table_type']);
148
          $styledColumn['audit_table_type'] = sprintf('<mm_type>%s</>', $styledColumn['audit_table_type']);
149
        }
150
      }
151
      else
152
      {
153
        // Highlighting for audit table column types and audit_columns in config file.
154
        $searchColumn = StaticDataLayer::searchInRowSet('column_name', $styledColumn['column_name'], $this->config['audit_columns']);
155
        if (isset($searchColumn))
156
        {
157
          $configType = $this->config['audit_columns'][$searchColumn]['column_type'];
158
          if (isset($configType) && !isset($column['audit_table_type']))
159
          {
160
            $styledColumn['column_name'] = sprintf('<mm_column>%s</>', $styledColumn['column_name']);
161
            $styledColumn['config_type'] = sprintf('<mm_type>%s</>', $styledColumn['config_type']);
162
          }
163
          else if (!isset($configType) && isset($column['audit_table_type']))
164
          {
165
            $styledColumn['audit_table_type'] = sprintf('<mm_type>%s</>', $column['audit_table_type']);
166
          }
167 View Code Duplication
          else if (strcmp($configType, $column['audit_table_type']))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
168
          {
169
            $styledColumn['column_name']      = sprintf('<mm_column>%s</>', $styledColumn['column_name']);
170
            $styledColumn['audit_table_type'] = sprintf('<mm_type>%s</>', $column['audit_table_type']);
171
            $styledColumn['config_type']      = sprintf('<mm_type>%s</>', $styledColumn['config_type']);
172
          }
173
        }
174
      }
175
      $styledColumns[] = $styledColumn;
176
    }
177
178
    return $styledColumns;
179
  }
180
181
  //--------------------------------------------------------------------------------------------------------------------
182
  /**
183
   * Get the difference between data and audit tables.
184
   *
185
   * @param Columns $dataColumns  The table columns from data schema.
186
   * @param Columns $auditColumns The table columns from audit schema.
187
   *
188
   * @return array[]
189
   */
190
  private function createDiffArray($dataColumns, $auditColumns)
191
  {
192
193
    $diff = [];
194
195
    foreach ($this->config['audit_columns'] as $column)
196
    {
197
      $diff[$column['column_name']] = ['column_name'      => $column['column_name'],
198
                                       'data_table_type'  => null,
199
                                       'audit_table_type' => null,
200
                                       'config_type'      => $column['column_type']];
201
    }
202
203
    foreach ($auditColumns->getColumns() as $column)
204
    {
205
      $config_type = isset($diff[$column['column_name']]) ? $diff[$column['column_name']]['config_type'] : null;
206
207
      $diff[$column['column_name']] = ['column_name'      => $column['column_name'],
208
                                       'data_table_type'  => null,
209
                                       'audit_table_type' => $column['column_type'],
210
                                       'config_type'      => $config_type];
211
    }
212
213
    foreach ($dataColumns->getColumns() as $column)
214
    {
215
      $config_type      = isset($diff[$column['column_name']]) ? $diff[$column['column_name']]['config_type'] : null;
216
      $audit_table_type = isset($diff[$column['column_name']]) ? $diff[$column['column_name']]['audit_table_type'] : null;
217
218
      $diff[$column['column_name']] = ['column_name'      => $column['column_name'],
219
                                       'data_table_type'  => $column['column_type'],
220
                                       'audit_table_type' => $audit_table_type,
221
                                       'config_type'      => $config_type];
222
    }
223
224
    return $diff;
225
  }
226
227
  //--------------------------------------------------------------------------------------------------------------------
228
  /**
229
   * Computes the difference between data and audit tables.
230
   */
231
  private function getDiff()
232
  {
233
    foreach ($this->dataSchemaTables as $table)
234
    {
235
      if ($this->config['tables'][$table['table_name']]['audit'])
236
      {
237
        $res = StaticDataLayer::searchInRowSet('table_name', $table['table_name'], $this->auditSchemaTables);
238
        if (isset($res))
239
        {
240
          $dataColumns  = new Columns(DataLayer::getTableColumns($this->config['database']['data_schema'], $table['table_name']));
241
          $auditColumns = DataLayer::getTableColumns($this->config['database']['audit_schema'], $table['table_name']);
242
          $auditColumns = $this->addNotNull($auditColumns);
243
          $auditColumns = new Columns($auditColumns);
244
245
          $this->diffColumns[$table['table_name']] = $this->createDiffArray($dataColumns, $auditColumns);
246
        }
247
      }
248
    }
249
  }
250
251
  //--------------------------------------------------------------------------------------------------------------------
252
  /**
253
   * Add not null to audit columns if it not nullable.
254
   *
255
   * @param array $theColumns Audit columns.
256
   *
257
   * @return array
258
   */
259
  private function addNotNull($theColumns)
260
  {
261
    $modifiedColumns = [];
262
    foreach ($theColumns as $column)
263
    {
264
      $modifiedColumn = $column;
265
      $auditColumn    = StaticDataLayer::searchInRowSet('column_name', $modifiedColumn['column_name'], $this->config['audit_columns']);
266
      if (isset($auditColumn))
267
      {
268
        if ($modifiedColumn['is_nullable']==='NO')
269
        {
270
          $modifiedColumn['column_type'] = sprintf('%s not null', $modifiedColumn['column_type']);
271
        }
272
      }
273
      $modifiedColumns[] = $modifiedColumn;
274
    }
275
276
    return $modifiedColumns;
277
  }
278
279
  //--------------------------------------------------------------------------------------------------------------------
280
  /**
281
   * Writes the difference between the audit tables and metadata tables to the output.
282
   *
283
   * @param OutputInterface $output The output.
284
   */
285
  private function diffTables($output)
286
  {
287
    foreach ($this->config['tables'] as $tableName => $table)
288
    {
289
      $res = StaticDataLayer::searchInRowSet('table_name', $tableName, $this->auditSchemaTables);
290
      if ($table['audit'] && !isset($res))
291
      {
292
        $output->writeln(sprintf('<miss_table>%s</>', $tableName));
293
      }
294
      else if (!$table['audit'] && isset($res))
295
      {
296
        $output->writeln(sprintf('<obsolete_table>%s</>', $tableName));
297
      }
298
    }
299
  }
300
301
  //--------------------------------------------------------------------------------------------------------------------
302
  /**
303
   * Writes the difference between the audit and data tables to the output.
304
   *
305
   * @param OutputInterface $output The output.
306
   */
307
  private function printDiff($output)
308
  {
309
    $first = true;
310
    if (isset($this->diffColumns))
311
    {
312
      foreach ($this->diffColumns as $tableName => $columns)
313
      {
314
        // Remove matching columns unless the full option is used.
315
        if (!$this->full)
316
        {
317
          $columns = self::removeMatchingColumns($columns);
318
        }
319
320
        if (!empty($columns))
321
        {
322
          // Add an empty line between tables.
323
          if ($first)
324
          {
325
            $first = false;
326
          }
327
          else
328
          {
329
            $output->writeln('');
330
          }
331
332
          // Write table name.
333
          $output->writeln($tableName);
334
335
          // Write table with columns.
336
          $columns = $this->addHighlighting($columns);
337
          $table   = new Table($output);
338
          $table->setHeaders(['column', 'data table', 'audit table', 'config'])
339
                ->setRows($columns);
340
          $table->render();
341
        }
342
      }
343
    }
344
    $this->diffTables($output);
345
  }
346
347
  //--------------------------------------------------------------------------------------------------------------------
348
}
349
350
//----------------------------------------------------------------------------------------------------------------------
351