Completed
Push — master ( efd012...704f4c )
by P.R.
03:36
created

AlterAuditTable::getTableMetadata()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

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