Completed
Push — master ( fc1e57...c0b43d )
by P.R.
06:54
created

Audit::setConfigTableColumns()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 9
ccs 7
cts 7
cp 1
rs 9.6666
cc 2
eloc 5
nc 2
nop 2
crap 2
1
<?php
2
//----------------------------------------------------------------------------------------------------------------------
3
namespace SetBased\Audit\MySql;
4
5
use SetBased\Audit\MySql\Metadata\TableColumnsMetadata;
6
use SetBased\Audit\MySql\Metadata\TableMetadata;
7
use SetBased\Stratum\MySql\StaticDataLayer;
8
use SetBased\Stratum\Style\StratumStyle;
9
10
//----------------------------------------------------------------------------------------------------------------------
11
/**
12
 * Class for executing auditing actions for tables.
13
 */
14
class Audit
15
{
16
  //--------------------------------------------------------------------------------------------------------------------
17
  /**
18
   * The metadata (additional) audit columns (as stored in the config file).
19
   *
20
   * @var TableColumnsMetadata
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
   * The content of the configuration file.
33
   *
34
   * @var array
35
   */
36
  private $config;
37
38
  /**
39
   * Tables metadata from config file.
40
   *
41
   * @var array
42
   */
43
  private $configMetadata;
44
45
  /**
46
   * The names of all tables in data schema.
47
   *
48
   * @var array
49
   */
50
  private $dataSchemaTables;
51
52
  /**
53
   * The Output decorator.
54
   *
55
   * @var StratumStyle
56
   */
57
  private $io;
58
59
  /**
60
   * If true remove all column information from config file.
61
   *
62
   * @var boolean
63
   */
64
  private $pruneOption;
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
   * @param StratumStyle $io             The Output decorator.
73
   */
74 13
  public function __construct(&$config, &$configMetadata, $io)
75
  {
76 13
    $this->config         = &$config;
77 13
    $this->configMetadata = &$configMetadata;
78 13
    $this->io             = $io;
79 13
  }
80
81
  //--------------------------------------------------------------------------------------------------------------------
82
  /**
83
   * Getting list of all tables from information_schema of database from config file.
84
   */
85 13
  public function listOfTables()
86
  {
87 13
    $this->dataSchemaTables = AuditDataLayer::getTablesNames($this->config['database']['data_schema']);
88
89 13
    $this->auditSchemaTables = AuditDataLayer::getTablesNames($this->config['database']['audit_schema']);
90 13
  }
91
92
  //--------------------------------------------------------------------------------------------------------------------
93
  /**
94
   * The main method: executes the auditing actions for tables.
95
   *
96
   * @return int The exit status.
97
   */
98 13
  public function main()
99
  {
100 13
    if ($this->pruneOption)
101 13
    {
102
      $this->configMetadata = [];
103
    }
104
105 13
    $this->resolveCanonicalAuditColumns();
106
107 13
    $this->listOfTables();
108
109 13
    $this->unknownTables();
110
111 13
    $status = $this->knownTables();
112
113 13
    return $status;
114
  }
115
116
  //--------------------------------------------------------------------------------------------------------------------
117
  /**
118
   * Sets the columns metadata of a table in the configuration file.
119
   *
120
   * @param string               $tableName The name of table.
121
   * @param TableColumnsMetadata $columns   The metadata of the table columns.
122
   */
123 12
  public function setConfigTableColumns($tableName, $columns)
124
  {
125 12
    $newColumns = [];
126 12
    foreach ($columns->getColumns() as $column)
127
    {
128 12
      $newColumns[] = $column->getProperties();
129 12
    }
130 12
    $this->configMetadata[$tableName] = $newColumns;
131 12
  }
132
133
  //--------------------------------------------------------------------------------------------------------------------
134
  /**
135
   * Compares the tables listed in the config file and the tables found in the data schema.
136
   */
137 13
  public function unknownTables()
138
  {
139 13
    foreach ($this->dataSchemaTables as $table)
140
    {
141 12
      if (isset($this->config['tables'][$table['table_name']]))
142 12
      {
143 12
        if (!isset($this->config['tables'][$table['table_name']]['audit']))
144 12
        {
145
          $this->io->writeln(sprintf('<info>Found new table %s</info>', $table['table_name']));
146
          $this->io->writeln(sprintf('<info>audit is not set for table %s</info>', $table['table_name']));
147
        }
148
        else
149
        {
150 12
          if ($this->config['tables'][$table['table_name']]['audit'])
151 12
          {
152 12
            if (!isset($this->config['tables'][$table['table_name']]['alias']))
153 12
            {
154
              $this->config['tables'][$table['table_name']]['alias'] = AuditTable::getRandomAlias();
155
            }
156 12
          }
157
        }
158 12
      }
159
      else
160
      {
161
        $this->io->writeln(sprintf('<info>Found new table %s</info>', $table['table_name']));
162
        $this->config['tables'][$table['table_name']] = ['audit' => false,
163
                                                                 'alias' => null,
164
                                                                 'skip'  => null];
165
      }
166 13
    }
167 13
  }
168
169
  //--------------------------------------------------------------------------------------------------------------------
170
  /**
171
   * Drop triggers from obsolete table.
172
   *
173
   * @param string $schemaName The schema name.
174
   * @param string $tableName  The table name.
175
   */
176
  protected function dropTriggersFromObsoleteTable($schemaName, $tableName)
177
  {
178
    $triggers = AuditDataLayer::getTableTriggers($schemaName, $tableName);
179
    foreach ($triggers as $trigger)
180
    {
181
      if (preg_match('/trg_audit_.*_(insert|update|delete)/', $trigger['trigger_name']))
182
      {
183
        $this->io->logInfo('Dropping trigger <dbo>%s</dbo> from obsolete table <dbo>%s</dbo>',
184
                           $trigger['trigger_name'],
185
                           $tableName);
186
187
        AuditDataLayer::dropTrigger($schemaName, $trigger['trigger_name']);
188
      }
189
    }
190
  }
191
192
  //--------------------------------------------------------------------------------------------------------------------
193
  /**
194
   * Resolves the canonical column types of the audit table columns.
195
   */
196 13
  protected function resolveCanonicalAuditColumns()
197
  {
198 13
    if (empty($this->config['audit_columns']))
199 13
    {
200 4
      $this->auditColumnsMetadata = new TableColumnsMetadata();
201 4
    }
202
    else
203
    {
204 9
      $schema    = $this->config['database']['audit_schema'];
205 9
      $tableName = '_TMP_'.uniqid();
206 9
      AuditDataLayer::createTemporaryTable($schema, $tableName, $this->config['audit_columns']);
207 9
      $columns = AuditDataLayer::getTableColumns($schema, $tableName);
208 9
      AuditDataLayer::dropTemporaryTable($schema, $tableName);
209
210 9
      foreach ($this->config['audit_columns'] as $audit_column)
211
      {
212 9
        $key = StaticDataLayer::searchInRowSet('column_name', $audit_column['column_name'], $columns);
213 9
        if (isset($audit_column['value_type']))
214 9
        {
215 9
          $columns[$key]['value_type'] = $audit_column['value_type'];
216 9
        }
217 9
        if (isset($audit_column['expression']))
218 9
        {
219 2
          $columns[$key]['expression'] = $audit_column['expression'];
220 2
        }
221 9
      }
222
223 9
      $this->auditColumnsMetadata = new TableColumnsMetadata($columns, 'AuditColumnMetadata');
224
    }
225 13
  }
226
227
  //--------------------------------------------------------------------------------------------------------------------
228
  /**
229
   * Processed known tables.
230
   *
231
   * @return int The exit status.
232
   */
233 13
  private function knownTables()
234
  {
235 13
    $status = 0;
236
237 13
    foreach ($this->dataSchemaTables as $table)
238
    {
239 12
      if ($this->config['tables'][$table['table_name']]['audit'])
240 12
      {
241 12
        if (isset($this->configMetadata[$table['table_name']]))
242 12
        {
243 1
          $tableColumns = $this->configMetadata[$table['table_name']];
244 1
        }
245
        else
246
        {
247 11
          $tableColumns = [];
248
        }
249 12
        $configTable = new TableMetadata($table['table_name'],
250 12
                                         $this->config['database']['data_schema'],
251 12
                                         $tableColumns);
252
253 12
        $currentTable = new AuditTable($this->io,
254 12
                                       $configTable,
255 12
                                       $this->config['database']['audit_schema'],
256 12
                                       $this->auditColumnsMetadata,
257 12
                                       $this->config['tables'][$table['table_name']]['alias'],
258 12
                                       $this->config['tables'][$table['table_name']]['skip']);
259
260
        // Ensure an audit table exists.
261 12
        if (StaticDataLayer::searchInRowSet('table_name', $table['table_name'], $this->auditSchemaTables)===null)
262 12
        {
263 9
          $currentTable->createAuditTable();
264 9
        }
265
266
        // Drop and create audit triggers and add new columns to the audit table.
267 12
        $ok = $currentTable->main($this->config['additional_sql']);
268
        if ($ok)
269 12
        {
270 12
          $columns = new TableColumnsMetadata(AuditDataLayer::getTableColumns($this->config['database']['data_schema'],
271 12
                                                                              $table['table_name']));
272 12
          $this->setConfigTableColumns($table['table_name'], $columns);
273 12
        }
274
        else
275
        {
276 1
          $status += 1;
277
        }
278 12
      }
279
      else
280
      {
281
        $this->dropTriggersFromObsoleteTable($this->config['database']['data_schema'], $table['table_name']);
282
      }
283 13
    }
284
285 13
    return $status;
286
  }
287
288
  //--------------------------------------------------------------------------------------------------------------------
289
}
290
291
//----------------------------------------------------------------------------------------------------------------------
292