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