Diff   A
last analyzed

Complexity

Total Complexity 17

Size/Duplication

Total Lines 215
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 74
c 1
b 0
f 0
dl 0
loc 215
ccs 71
cts 71
cp 1
rs 10
wmc 17

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 10 1
A currentAuditTable() 0 33 3
A getTableLists() 0 28 5
A main() 0 27 1
A currentAuditTables() 0 5 2
A obsoleteAuditTables() 0 9 3
A missingAuditTables() 0 9 2
1
<?php
2
declare(strict_types=1);
3
4
namespace SetBased\Audit\Audit;
5
6
use SetBased\Audit\DiffTable;
7
use SetBased\Audit\Metadata\TableColumnsMetadata;
8
use SetBased\Audit\MySql\AuditDataLayer;
9
use SetBased\Audit\MySql\Metadata\TableMetadata;
10
use SetBased\Audit\Style\AuditStyle;
11
use SetBased\Config\TypedConfig;
12
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
13
use Symfony\Component\Console\Input\InputInterface;
14
use Symfony\Component\Console\Output\OutputInterface;
15
16
/**
17
 * Class for executing auditing actions for tables.
18
 */
19
class Diff
20
{
21
  //--------------------------------------------------------------------------------------------------------------------
22
  /**
23
   * The metadata of the additional audit columns.
24
   *
25
   * @var TableColumnsMetadata
26
   */
27
  private TableColumnsMetadata $additionalAuditColumns;
28
29
  /**
30
   * The strong typed configuration reader and writer.
31
   *
32
   * @var TypedConfig
33
   */
34
  private TypedConfig $config;
35
36
  /**
37
   * The Input interface.
38
   *
39
   * @var InputInterface
40
   */
41
  private InputInterface $input;
42
43
  /**
44
   * The Output decorator.
45
   *
46
   * @var AuditStyle
47
   */
48
  private AuditStyle $io;
49
50
  /**
51
   * The Output interface.
52
   *
53
   * @var OutputInterface
54
   */
55
  private OutputInterface $output;
56
57
  //--------------------------------------------------------------------------------------------------------------------
58
  /**
59
   * Object constructor.
60
   *
61
   * @param TypedConfig     $config The strong typed configuration reader and writer.
62
   * @param AuditStyle      $io     The Output decorator.
63
   * @param InputInterface  $input
64
   * @param OutputInterface $output
65
   */
66 6
  public function __construct(TypedConfig $config, AuditStyle $io, InputInterface $input, OutputInterface $output)
67
  {
68 6
    $this->io     = $io;
69 6
    $this->config = $config;
70 6
    $this->input  = $input;
71 6
    $this->output = $output;
72
73 6
    $this->additionalAuditColumns =
74 6
      AuditDataLayer::$dl->resolveCanonicalAdditionalAuditColumns($this->config->getManString('database.audit_schema'),
75 6
                                                                  $this->config->getManArray('audit_columns'));
76 6
  }
77
78
  //--------------------------------------------------------------------------------------------------------------------
79
  /**
80
   * The main method: executes the auditing actions for tables.
81
   */
82 6
  public function main(): void
83
  {
84
    // Style for column names with miss matched column types.
85 6
    $style = new OutputFormatterStyle(null, 'red');
86 6
    $this->output->getFormatter()
87
                 ->setStyle('mm_column', $style);
88
89 6
    // Style for column types of columns with miss matched column types.
90 6
    $style = new OutputFormatterStyle('yellow');
91
    $this->output->getFormatter()
92
                 ->setStyle('mm_type', $style);
93 6
94 6
    // Style for obsolete tables.
95
    $style = new OutputFormatterStyle('yellow');
96
    $this->output->getFormatter()
97 6
                 ->setStyle('obsolete_table', $style);
98 6
99
    // Style for missing tables.
100 6
    $style = new OutputFormatterStyle('red');
101
    $this->output->getFormatter()
102 6
                 ->setStyle('miss_table', $style);
103
104 6
    $lists = $this->getTableLists();
105
106 6
    $this->currentAuditTables($lists['current']);
107 6
    $this->missingAuditTables($lists['missing']);
108
    $this->obsoleteAuditTables($lists['obsolete']);
109
  }
110
111
  //--------------------------------------------------------------------------------------------------------------------
112
  /**
113
   * Prints the difference between a data and its related audit table.
114
   *
115 6
   * @param string $tableName The table name.
116
   */
117 6
  private function currentAuditTable(string $tableName): void
118
  {
119 6
    $columns           = AuditDataLayer::$dl->getTableColumns($this->config->getManString('database.data_schema'),
120 6
                                                              $tableName);
121
    $dataTableColumns  = new TableColumnsMetadata($columns);
122 6
    $columns           = AuditDataLayer::$dl->getTableColumns($this->config->getManString('database.audit_schema'),
123
                                                              $tableName);
124
    $auditTableColumns = new TableColumnsMetadata($columns, 'AuditColumnMetadata');
125 6
126 6
    // In the audit table columns coming from the data table are always nullable.
127 6
    $dataTableColumns->makeNullable();
128
    $dataTableColumns->unsetDefaults();
129
    $dataTableColumns = TableColumnsMetadata::combine($this->additionalAuditColumns, $dataTableColumns);
130 6
131
    // In the audit table columns coming from the data table don't have defaults.
132 6
    foreach ($auditTableColumns->getColumns() as $column)
133
    {
134 6
      if (!in_array($column->getName(), $this->additionalAuditColumns->getColumnNames()))
135
      {
136
        $column->unsetDefault();
137
      }
138 6
    }
139
140 6
    $dataTableOptions  = AuditDataLayer::$dl->getTableOptions($this->config->getManString('database.data_schema'),
141
                                                              $tableName);
142
    $auditTableOptions = AuditDataLayer::$dl->getTableOptions($this->config->getManString('database.audit_schema'),
143 6
                                                              $tableName);
144 6
145
    $dataTable  = new TableMetadata($dataTableOptions, $dataTableColumns);
146 6
    $auditTable = new TableMetadata($auditTableOptions, $auditTableColumns);
147 6
148 6
    $helper = new DiffTable($dataTable, $auditTable);
149
    $helper->print($this->io, $this->input->getOption('full'));
150
  }
151
152
  //--------------------------------------------------------------------------------------------------------------------
153
  /**
154
   * Prints the difference between data and audit tables.
155
   *
156 6
   * @param string[] $tableNames The names of the current tables.
157
   */
158 6
  private function currentAuditTables(array $tableNames): void
159
  {
160 6
    foreach ($tableNames as $tableName)
161
    {
162 6
      $this->currentAuditTable($tableName);
163
    }
164
  }
165
166
  //--------------------------------------------------------------------------------------------------------------------
167
  /**
168
   * Returns the names of the tables that must be compared.
169
   *
170 6
   * @return array[]
171
   */
172 6
  private function getTableLists(): array
173 6
  {
174
    $tables1 = [];
175 6
    foreach ($this->config->getManArray('tables') as $tableName => $config)
176
    {
177 6
      if ($config['audit'])
178
      {
179
        $tables1[] = $tableName;
180
      }
181 6
    }
182 6
183 6
    $tables  = AuditDataLayer::$dl->getTablesNames($this->config->getManString('database.data_schema'));
184
    $tables2 = [];
185 6
    foreach ($tables as $table)
186
    {
187
      $tables2[] = $table['table_name'];
188 6
    }
189 6
190 6
    $tables  = AuditDataLayer::$dl->getTablesNames($this->config->getManString('database.audit_schema'));
191
    $tables3 = [];
192 6
    foreach ($tables as $table)
193
    {
194
      $tables3[] = $table['table_name'];
195 6
    }
196 6
197 6
    return ['current'  => array_intersect($tables1, $tables2, $tables3),
198
            'obsolete' => array_diff($tables3, $tables1),
199
            'missing'  => array_diff($tables1, $tables3)];
200
  }
201
202
  //--------------------------------------------------------------------------------------------------------------------
203
  /**
204
   * Prints the missing audit tables.
205
   *
206 6
   * @param string[] $tableNames The names of the obsolete tables.
207
   */
208 6
  private function missingAuditTables(array $tableNames): void
209
  {
210 1
    if (empty($tableNames))
211 1
    {
212 1
      return;
213
    }
214
215
    $this->io->title('Missing Audit Tables');
216
    $this->io->listing($tableNames);
217
  }
218
219
  //--------------------------------------------------------------------------------------------------------------------
220 6
  /**
221
   * Prints the obsolete audit tables.
222 6
   *
223
   * @param string[] $tableNames The names of the obsolete tables.
224 1
   */
225 1
  private function obsoleteAuditTables(array $tableNames): void
226 1
  {
227
    if (empty($tableNames) || !$this->input->getOption('full'))
228
    {
229
      return;
230
    }
231
232
    $this->io->title('Obsolete Audit Tables');
233
    $this->io->listing($tableNames);
234
  }
235
236
  //--------------------------------------------------------------------------------------------------------------------
237
}
238
239
//----------------------------------------------------------------------------------------------------------------------
240