Test Failed
Push — master ( d02081...898276 )
by P.R.
04:01
created

AlterAuditTable::getTableList()   B

Complexity

Conditions 5
Paths 12

Size

Total Lines 26
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 13
nc 12
nop 0
dl 0
loc 26
rs 8.439
c 0
b 0
f 0
1
<?php
2
3
namespace SetBased\Audit\Audit;
4
5
use SetBased\Audit\Metadata\TableColumnsMetadata;
6
use SetBased\Audit\MySql\AlterTableCodeStore;
7
use SetBased\Audit\MySql\AuditDataLayer;
8
use SetBased\Audit\MySql\Metadata\TableMetadata;
9
use SetBased\Exception\FallenException;
10
11
/**
12
 * Class for generating alter audit table SQL statements for manual evaluation.
13
 */
14
class AlterAuditTable
15
{
16
  //--------------------------------------------------------------------------------------------------------------------
17
  /**
18
   * The metadata of the additional audit columns.
19
   *
20
   * @var \SetBased\Audit\Metadata\TableColumnsMetadata
21
   */
22
  private $additionalAuditColumns;
23
24
  /**
25
   * Code store for alter table statement.
26
   *
27
   * @var \SetBased\Audit\MySql\AlterTableCodeStore
28
   */
29
  private $codeStore;
30
31
  /**
32
   * The content of the configuration file.
33
   *
34
   * @var array
35
   */
36
  private $config;
37
38
  //--------------------------------------------------------------------------------------------------------------------
39
  /**
40
   * Object constructor.
41
   *
42
   * @param array[] $config The content of the configuration file.
43
   */
44
  public function __construct(&$config)
45
  {
46
    $this->config    = &$config;
47
    $this->codeStore = new AlterTableCodeStore();
48
49
    $this->additionalAuditColumns =
50
      AuditDataLayer::resolveCanonicalAdditionalAuditColumns($this->config['database']['audit_schema'],
51
                                                             $this->config['audit_columns']);
52
  }
53
54
  //--------------------------------------------------------------------------------------------------------------------
55
  /**
56
   * The main method: executes the create alter table statement actions for tables.
57
   *
58
   * return string
59
   */
60
  public function main()
61
  {
62
    $tables = $this->getTableList();
63
    foreach ($tables as $table)
64
    {
65
      $this->compareTable($table);
66
    }
67
68
    return $this->codeStore->getCode();
69
  }
70
71
  //--------------------------------------------------------------------------------------------------------------------
72
  /**
73
   * Compares a table in the data schema and its counter part in the audit schema.
74
   *
75
   * @param string $tableName The name of the table.
76
   */
77
  private function compareTable($tableName)
78
  {
79
    $dataTable  = $this->getTableMetadata($this->config['database']['data_schema'], $tableName);
80
    $auditTable = $this->getTableMetadata($this->config['database']['audit_schema'], $tableName);
81
82
    // In the audit schema columns corresponding with the columns from the data table are always nullable.
83
    $dataTable->getColumns()->makeNullable();
84
    $dataTable->getColumns()->prependTableColumns($this->additionalAuditColumns);
85
86
    $this->compareTableOptions($dataTable, $auditTable);
87
    $this->compareTableColumns($dataTable, $auditTable);
88
  }
89
90
  //--------------------------------------------------------------------------------------------------------------------
91
  /**
92
   * Compares the columns of the data and audit tables and generates the appropriate alter table statement.
93
   *
94
   * @param TableMetadata $dataTable  The metadata of the data table.
95
   * @param TableMetadata $auditTable The metadata of the audit table.
96
   */
97
  private function compareTableColumns($dataTable, $auditTable)
98
  {
99
    $diff = TableColumnsMetadata::differentColumnTypes($dataTable->getColumns(), $auditTable->getColumns());
100
101
    if (!empty($diff->getColumns()))
102
    {
103
      $maxLength = $diff->getLongestColumnNameLength();
104
105
      $this->codeStore->append(sprintf('alter table `%s`.`%s`',
106
                                       $this->config['database']['audit_schema'],
107
                                       $auditTable->getTableName()));
108
109
      $first = true;
110
      foreach ($diff->getColumns() as $column)
111
      {
112
        $name   = $column->getName();
113
        $filler = str_repeat(' ', $maxLength - mb_strlen($name) + 1);
114
115
        if (!$first) $this->codeStore->appendToLastLine(',');
116
117
        $this->codeStore->append(sprintf('change column `%s`%s`%s`%s%s',
118
                                         $name,
119
                                         $filler,
120
                                         $name,
121
                                         $filler,
122
                                         $column->getColumnAuditDefinition()));
123
124
        $first = false;
125
      }
126
127
      $this->codeStore->append(';');
128
      $this->codeStore->append('');
129
    }
130
  }
131
132
  //--------------------------------------------------------------------------------------------------------------------
133
  /**
134
   * Compares the table options of the data and audit tables and generates the appropriate alter table statement.
135
   *
136
   * @param TableMetadata $dataTable  The metadata of the data table.
137
   * @param TableMetadata $auditTable The metadata of the audit table.
138
   */
139
  private function compareTableOptions($dataTable, $auditTable)
140
  {
141
    $options = TableMetadata::compareOptions($dataTable, $auditTable);
142
143
    if (!empty($options))
144
    {
145
      $parts = [];
146
      foreach ($options as $option)
147
      {
148
        switch ($option)
149
        {
150
          case 'engine':
151
            $parts[] = 'engine '.$dataTable->getProperty('engine');
152
            break;
153
154
          case 'character_set_name':
155
            $parts[] = 'default character set '.$dataTable->getProperty('character_set_name');
156
            break;
157
158
          case 'table_collation':
159
            $parts[] = 'default collate '.$dataTable->getProperty('table_collation');
160
            break;
161
162
          default:
163
            throw new FallenException('option', $option);
164
        }
165
      }
166
167
      $this->codeStore->append(sprintf('alter table `%s`.`%s` %s;',
168
                                       $this->config['database']['audit_schema'],
169
                                       $auditTable->getTableName(),
170
                                       implode(' ', $parts)));
171
      $this->codeStore->append('');
172
    }
173
  }
174
175
  //--------------------------------------------------------------------------------------------------------------------
176
  /**
177
   * Returns the names of the tables that must be compared.
178
   *
179
   * @return string[]
180
   */
181
  private function getTableList()
182
  {
183
    $tables1 = [];
184
    foreach ($this->config['tables'] as $tableName => $config)
185
    {
186
      if ($config['audit'])
187
      {
188
        $tables1[] = $tableName;
189
      }
190
    }
191
192
    $tables  = AuditDataLayer::getTablesNames($this->config['database']['data_schema']);
193
    $tables2 = [];
194
    foreach ($tables as $table)
195
    {
196
      $tables2[] = $table['table_name'];
197
    }
198
199
    $tables  = AuditDataLayer::getTablesNames($this->config['database']['audit_schema']);
200
    $tables3 = [];
201
    foreach ($tables as $table)
202
    {
203
      $tables3[] = $table['table_name'];
204
    }
205
206
    return array_intersect($tables1, $tables2, $tables3);
207
  }
208
209
  //--------------------------------------------------------------------------------------------------------------------
210
  /**
211
   * Returns the metadata of a table.
212
   *
213
   * @param string $schemaName The name of the schema of the table.
214
   * @param string $tableName  The name of the table.
215
   *
216
   * @return TableMetadata
217
   */
218
  private function getTableMetadata($schemaName, $tableName)
219
  {
220
    $table   = AuditDataLayer::getTableOptions($schemaName, $tableName);
221
    $columns = AuditDataLayer::getTableColumns($schemaName, $tableName);
222
223
    return new TableMetadata($table, new TableColumnsMetadata($columns));
224
  }
225
226
  //--------------------------------------------------------------------------------------------------------------------
227
}
228
229
//----------------------------------------------------------------------------------------------------------------------
230