Completed
Pull Request — master (#60)
by Dima
08:03
created

AuditAlter::createSqlStatement()   D

Complexity

Conditions 9
Paths 65

Size

Total Lines 35
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 35
ccs 0
cts 25
cp 0
rs 4.909
cc 9
eloc 22
nc 65
nop 2
crap 90
1
<?php
2
//----------------------------------------------------------------------------------------------------------------------
3
namespace SetBased\Audit\MySql;
4
5
use SetBased\Audit\MySql\Helper\MySqlAlterTableCodeStore;
6
use SetBased\Audit\MySql\Metadata\ColumnMetadata;
7
use SetBased\Audit\MySql\Metadata\MultiSourceColumnMetadata;
8
use SetBased\Audit\MySql\Metadata\TableColumnsMetadata;
9
10
//----------------------------------------------------------------------------------------------------------------------
11
/**
12
 * Class for executing auditing actions for tables.
13
 */
14
class AuditAlter
15
{
16
  //--------------------------------------------------------------------------------------------------------------------
17
  /**
18
   * The metadata (additional) audit columns (as stored in the config file).
19
   *
20
   * @var \array[]
21
   */
22
  private $auditColumnsMetadata;
23
24
  /**
25
   * The names of all tables in audit schema.
26
   *
27
   * @var array
28
   */
29
  private $auditSchemaTables;
30
31
  /**
32
   * Code store for alter table statement.
33
   *
34
   * @var MySqlAlterTableCodeStore
35
   */
36
  private $codeStore;
37
38
  /**
39
   * The content of the configuration file.
40
   *
41
   * @var array
42
   */
43
  private $config;
44
45
  /**
46
   * Config metadata columns.
47
   *
48
   * @var array
49
   */
50
  private $configMetadata;
51
52
  /**
53
   * The names of all tables in data schema.
54
   *
55
   * @var array
56
   */
57
  private $dataSchemaTables;
58
59
  /**
60
   * Array with columns for each table.
61
   *
62
   * @var array<string,AuditDiffTable>
63
   */
64
  private $diffColumns;
65
66
  //--------------------------------------------------------------------------------------------------------------------
67
  /**
68
   * Object constructor.
69
   *
70
   * @param array[] $config         The content of the configuration file.
71
   * @param array[] $configMetadata The content of the metadata file.
72
   */
73
  public function __construct(&$config, $configMetadata)
74
  {
75
    $this->config         = &$config;
76
    $this->configMetadata = $configMetadata;
77
    $this->codeStore      = new MySqlAlterTableCodeStore();
78
  }
79
80
  //--------------------------------------------------------------------------------------------------------------------
81
  /**
82
   * Create Sql statement for alter table.
83
   *
84
   * @param string               $tableName The table name.
85
   * @param TableColumnsMetadata $columns   Columns metadata for alter statement.
86
   */
87
  public function createSqlStatement($tableName, $columns)
88
  {
89
    $this->codeStore->append(sprintf('ALTER TABLE %s CHANGE', $tableName));
90
    $countMax = $columns->getNumberOfColumns();
91
    $count    = 1;
92
    /** @var MultiSourceColumnMetadata $rowMetadata */
93
    foreach ($columns->getColumns() as $columnName => $rowMetadata)
94
    {
95
      $columnProperties = $rowMetadata->getProperties();
96
      /** @var ColumnMetadata $data */
97
      $data = isset($columnProperties['data']) ? $columnProperties['data'] : null;
98
      /** @var ColumnMetadata $config */
99
      $config = isset($columnProperties['config']) ? $columnProperties['config'] : null;
100
101
      $dataMetadata   = isset($data) ? $data->getProperties() : null;
102
      $configMetadata = isset($config) ? $config->getProperties() : null;
103
104
      if (!isset($dataMetadata))
105
      {
106
        $line = sprintf('%s %s %s', $columnName, $columnName, $configMetadata['column_type']);
107
        if ($count!=$countMax) $line .= ',';
108
        $this->codeStore->append($line);
109
      }
110
      else
111
      {
112
        $line = sprintf('%s %s %s', $columnName, $columnName, $dataMetadata['column_type']);
113
        if ($count!=$countMax) $line .= ',';
114
        $this->codeStore->append($line);
115
      }
116
      $count++;
117
    }
118
    $this->codeStore->append(';');
119
    $tableOptions = AuditDataLayer::getTableOptions($this->config['database']['data_schema'], $tableName);
120
    $this->codeStore->append(sprintf('ALTER TABLE %s DEFAULT CHARACTER SET %s;', $tableName, $tableOptions['character_set_name']));
121
  }
122
123
124
125
  //--------------------------------------------------------------------------------------------------------------------
126
  /**
127
   * The main method: executes the create alter table statement actions for tables.
128
   *
129
   * return string
130
   */
131
  public function main()
132
  {
133
    $this->processData();
134
135
    return $this->codeStore->getCode();
136
  }
137
138
  //--------------------------------------------------------------------------------------------------------------------
139
  /**
140
   * Computes the difference between data and audit tables.
141
   */
142
  private function getDiff()
143
  {
144
    foreach ($this->dataSchemaTables as $table)
145
    {
146
      if ($this->config['tables'][$table['table_name']]['audit'])
147
      {
148
        $res = AuditDataLayer::searchInRowSet('table_name', $table['table_name'], $this->auditSchemaTables);
149
        if (isset($res))
150
        {
151
          $this->diffColumns[$table['table_name']] = new AuditDiffTable($this->config['database']['data_schema'],
152
                                                                        $this->config['database']['audit_schema'],
153
                                                                        $table['table_name'],
154
                                                                        $this->auditColumnsMetadata,
155
                                                                        $this->configMetadata[$table['table_name']]);
156
        }
157
      }
158
    }
159
  }
160
161
  //--------------------------------------------------------------------------------------------------------------------
162
  /**
163
   * Getting list of all tables from information_schema of database from config file.
164
   */
165
  private function listOfTables()
166
  {
167
    $this->dataSchemaTables = AuditDataLayer::getTablesNames($this->config['database']['data_schema']);
168
169
    $this->auditSchemaTables = AuditDataLayer::getTablesNames($this->config['database']['audit_schema']);
170
  }
171
172
  //--------------------------------------------------------------------------------------------------------------------
173
  /**
174
   *  Work on data for each table.
175
   */
176
  private function processData()
177
  {
178
    $this->resolveCanonicalAuditColumns();
179
180
    $this->listOfTables();
181
182
    $this->getDiff();
183
184
    /** @var AuditDiffTable $diffTable */
185
    foreach ($this->diffColumns as $tableName => $diffTable)
186
    {
187
      // Remove matching columns.
188
      $columns = $diffTable->removeMatchingColumns(true);
189
190
      $this->createSqlStatement($tableName, $columns);
191
    }
192
  }
193
194
  //--------------------------------------------------------------------------------------------------------------------
195
  /**
196
   * Resolves the canonical column types of the audit table columns.
197
   */
198
  private function resolveCanonicalAuditColumns()
199
  {
200
    if (empty($this->config['audit_columns']))
201
    {
202
      $this->auditColumnsMetadata = [];
203
    }
204
    else
205
    {
206
      $schema    = $this->config['database']['audit_schema'];
207
      $tableName = '_TMP_'.uniqid();
208
      AuditDataLayer::createTemporaryTable($schema, $tableName, $this->config['audit_columns']);
209
      $columns = AuditDataLayer::getTableColumns($schema, $tableName);
210
      AuditDataLayer::dropTemporaryTable($schema, $tableName);
211
212
      foreach ($this->config['audit_columns'] as $audit_column)
213
      {
214
        $key = AuditDataLayer::searchInRowSet('column_name', $audit_column['column_name'], $columns);
215
216
        if ($columns[$key]['is_nullable']==='NO')
217
        {
218
          $columns[$key]['column_type'] = sprintf('%s not null', $columns[$key]['column_type']);
219
        }
220
        if (isset($audit_column['value_type']))
221
        {
222
          $columns[$key]['value_type'] = $audit_column['value_type'];
223
        }
224
        if (isset($audit_column['expression']))
225
        {
226
          $columns[$key]['expression'] = $audit_column['expression'];
227
        }
228
      }
229
230
      $this->auditColumnsMetadata = $columns;
231
    }
232
  }
233
234
  //--------------------------------------------------------------------------------------------------------------------
235
}
236
237
//----------------------------------------------------------------------------------------------------------------------
238