Completed
Push — master ( b7d034...3d835d )
by P.R.
03:58
created

Table::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 19
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 1

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 19
ccs 11
cts 11
cp 1
rs 9.4285
cc 1
eloc 17
nc 1
nop 8
crap 1

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
//----------------------------------------------------------------------------------------------------------------------
3
namespace SetBased\Audit\MySql\Table;
4
5
use SetBased\Audit\MySql\DataLayer;
6
use SetBased\Stratum\Style\StratumStyle;
7
8
//--------------------------------------------------------------------------------------------------------------------
9
/**
10
 * Class for metadata of tables.
11
 */
12
class Table
13
{
14
  //--------------------------------------------------------------------------------------------------------------------
15
  /**
16
   * The unique alias for this data table.
17
   *
18
   * @var string
19
   */
20
  private $alias;
21
22
  /**
23
   * The metadata (additional) audit columns (as stored in the config file).
24
   *
25
   * @var Columns
26
   */
27
  private $auditColumns;
28
29
  /**
30
   * The name of the schema with the audit tables.
31
   *
32
   * @var string
33
   */
34
  private $auditSchemaName;
35
36
  /**
37
   * The name of the schema with the data tables.
38
   *
39
   * @var string
40
   */
41
  private $dataSchemaName;
42
43
  /**
44
   * The metadata of the columns of the data table as stored in the config file.
45
   *
46
   * @var Columns
47
   */
48
  private $dataTableColumnsConfig;
49
50
  /**
51
   * The metadata of the columns of the data table retrieved from information_schema.
52
   *
53
   * @var Columns
54
   */
55
  private $dataTableColumnsDatabase;
56
57
  /**
58
   * The output decorator
59
   *
60
   * @var StratumStyle
61
   */
62
  private $io;
63
64
  /**
65
   * The skip variable for triggers.
66
   *
67
   * @var string
68
   */
69
  private $skipVariable;
70
71
  /**
72
   * The name of this data table.
73
   *
74
   * @var string
75
   */
76
  private $tableName;
77
78
  //--------------------------------------------------------------------------------------------------------------------
79
  /**
80
   * Object constructor.
81
   *
82
   * @param StratumStyle $io                    The output for log messages.
83
   * @param string       $tableName             The table name.
84
   * @param string       $dataSchema            The name of the schema with data tables.
85
   * @param string       $auditSchema           The name of the schema with audit tables.
86
   * @param array[]      $configColumnsMetadata The columns of the data table as stored in the config file.
87
   * @param array[]      $auditColumnsMetadata  The columns of the audit table as stored in the config file.
88
   * @param string       $alias                 An unique alias for this table.
89
   * @param string       $skipVariable          The skip variable
90
   */
91 4
  public function __construct($io,
92
                              $tableName,
93
                              $dataSchema,
94
                              $auditSchema,
95
                              $configColumnsMetadata,
96
                              $auditColumnsMetadata,
97
                              $alias,
98
                              $skipVariable)
99
  {
100 4
    $this->io                       = $io;
101 4
    $this->tableName                = $tableName;
102 4
    $this->dataTableColumnsConfig   = new Columns($configColumnsMetadata);
103 4
    $this->dataSchemaName           = $dataSchema;
104 4
    $this->auditSchemaName          = $auditSchema;
105 4
    $this->dataTableColumnsDatabase = new Columns($this->getColumnsFromInformationSchema());
106 4
    $this->auditColumns             = new Columns($auditColumnsMetadata);
107 4
    $this->alias                    = $alias;
108 4
    $this->skipVariable             = $skipVariable;
109 4
  }
110
111
  //--------------------------------------------------------------------------------------------------------------------
112
  /**
113
   * Returns a random alias for this table.
114
   *
115
   * @return string
116
   */
117
  public static function getRandomAlias()
118
  {
119
    return uniqid();
120
  }
121
122
  //--------------------------------------------------------------------------------------------------------------------
123
  /**
124
   * Creates missing audit table for this table.
125
   */
126 3
  public function createMissingAuditTable()
127
  {
128 3
    $this->io->logInfo('Creating audit table <dbo>%s.%s<dbo>', $this->auditSchemaName, $this->tableName);
129
130 3
    $columns = Columns::combine($this->auditColumns, $this->dataTableColumnsDatabase);
131 3
    DataLayer::createAuditTable($this->dataSchemaName, $this->auditSchemaName, $this->tableName, $columns);
132 3
  }
133
134
  //--------------------------------------------------------------------------------------------------------------------
135
  /**
136
   * Creates audit triggers on this table.
137
   *
138
   * @param string[] $additionalSql Additional SQL statements to be include in triggers.
139
   */
140 4
  public function createTriggers($additionalSql)
141
  {
142
    // Lock the table to prevent insert, updates, or deletes between dropping and creating triggers.
143 4
    $this->lockTable($this->tableName);
144
145
    // Drop all triggers, if any.
146 4
    $this->dropTriggers();
147
148
    // Create or recreate the audit triggers.
149 4
    $this->createTableTrigger('INSERT', $this->skipVariable, $additionalSql);
150 4
    $this->createTableTrigger('UPDATE', $this->skipVariable, $additionalSql);
151 4
    $this->createTableTrigger('DELETE', $this->skipVariable, $additionalSql);
152
153
    // Insert, updates, and deletes are no audited again. So, release lock on the table.
154 4
    $this->unlockTables();
155 4
  }
156
157
  //--------------------------------------------------------------------------------------------------------------------
158
  /**
159
   * Returns the name of this table.
160
   *
161
   * @return string
162
   */
163 4
  public function getTableName()
164
  {
165 4
    return $this->tableName;
166
  }
167
168
  //--------------------------------------------------------------------------------------------------------------------
169
  /**
170
   * Main function for work with table.
171
   *
172
   * @param string[] $additionalSql Additional SQL statements to be include in triggers.
173
   *
174
   * @return \array[] Columns for config file
0 ignored issues
show
Documentation introduced by
Should the return type not be array<string,Columns>?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
175
   */
176 4
  public function main($additionalSql)
177
  {
178 4
    $comparedColumns = null;
179 4
    if (isset($this->dataTableColumnsConfig))
180 4
    {
181 4
      $comparedColumns = $this->getTableColumnInfo();
182 4
    }
183
184 4
    $newColumns      = $comparedColumns['new_columns']->getColumns();
185 4
    $obsoleteColumns = $comparedColumns['obsolete_columns']->getColumns();
186 4
    if (empty($newColumns) && empty($obsoleteColumns))
187 4
    {
188 4
      $alteredColumns = $comparedColumns['altered_columns']->getColumns();
189 4
      if (empty($alteredColumns))
190 4
      {
191 4
        $this->createTriggers($additionalSql);
192 4
      }
193 4
    }
194
195 4
    return $comparedColumns;
196
  }
197
198
  //--------------------------------------------------------------------------------------------------------------------
199
  /**
200
   * Adds new columns to audit table.
201
   *
202
   * @param Columns $columns Columns array
203
   */
204 4
  private function addNewColumns($columns)
205
  {
206 4
    DataLayer::addNewColumns($this->auditSchemaName, $this->tableName, $columns);
207 4
  }
208
209
  //--------------------------------------------------------------------------------------------------------------------
210
  /**
211
   * Creates a triggers for this table.
212
   *
213
   * @param string      $action      The trigger action (INSERT, DELETE, or UPDATE).
214
   * @param string|null $skipVariable
215
   * @param string[]    $additionSql The additional SQL statements to be included in triggers.
216
   */
217 4
  private function createTableTrigger($action, $skipVariable, $additionSql)
218
  {
219 4
    $triggerName = $this->getTriggerName($action);
220
221 4
    $this->io->logVerbose('Creating trigger <dbo>%s.%s</dbo> on table <dbo>%s.%s</dbo>',
222 4
                          $this->dataSchemaName,
223 4
                          $triggerName,
224 4
                          $this->dataSchemaName,
225 4
                          $this->tableName);
226
227 4
    DataLayer::createAuditTrigger($this->dataSchemaName,
228 4
                                  $this->auditSchemaName,
229 4
                                  $this->tableName,
230 4
                                  $triggerName,
231 4
                                  $action,
232 4
                                  $this->auditColumns,
233 4
                                  $this->dataTableColumnsDatabase,
234 4
                                  $skipVariable,
235 4
                                  $additionSql);
236 4
  }
237
238
  //--------------------------------------------------------------------------------------------------------------------
239
  /**
240
   * Drops all triggers from this table.
241
   */
242 4
  private function dropTriggers()
243
  {
244 4
    $triggers = DataLayer::getTableTriggers($this->dataSchemaName, $this->tableName);
245 4
    foreach ($triggers as $trigger)
246
    {
247 1
      $this->io->logVerbose('Dropping trigger <dbo>%s</dbo> on <dbo>%s.%s</dbo>',
248 1
                            $trigger['trigger_name'],
249 1
                            $this->dataSchemaName,
250 1
                            $this->tableName);
251
252 1
      DataLayer::dropTrigger($this->dataSchemaName, $trigger['trigger_name']);
253 4
    }
254 4
  }
255
256
  //--------------------------------------------------------------------------------------------------------------------
257
  /**
258
   * Compares columns types from table in data_schema with columns in config file.
259
   *
260
   * @return Columns
261
   */
262 4
  private function getAlteredColumns()
263
  {
264 4
    $alteredColumnsTypes = Columns::differentColumnTypes($this->dataTableColumnsDatabase,
265 4
                                                         $this->dataTableColumnsConfig);
266
267 4
    return $alteredColumnsTypes;
268
  }
269
270
  //--------------------------------------------------------------------------------------------------------------------
271
  /**
272
   * Selects and returns the metadata of the columns of this table from information_schema.
273
   *
274
   * @return array[]
0 ignored issues
show
Documentation introduced by
Should the return type not be \array[]?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
275
   */
276 4
  private function getColumnsFromInformationSchema()
277
  {
278 4
    $result = DataLayer::getTableColumns($this->dataSchemaName, $this->tableName);
279
280 4
    return $result;
281
  }
282
283
  //--------------------------------------------------------------------------------------------------------------------
284
  /**
285
   * Compare columns from table in data_schema with columns in config file.
286
   *
287
   * @return \array[]
0 ignored issues
show
Documentation introduced by
Should the return type not be array<string,Columns>?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
288
   */
289 4
  private function getTableColumnInfo()
290
  {
291 4
    $columnActual  = new Columns(DataLayer::getTableColumns($this->auditSchemaName, $this->tableName));
292 4
    $columnsConfig = Columns::combine($this->auditColumns, $this->dataTableColumnsConfig);
293 4
    $columnsTarget = Columns::combine($this->auditColumns, $this->dataTableColumnsDatabase);
294
295 4
    $newColumns      = Columns::notInOtherSet($columnsTarget, $columnActual);
296 4
    $obsoleteColumns = Columns::notInOtherSet($columnsConfig, $columnsTarget);
297 4
    $alteredColumns  = $this->getAlteredColumns();
298
299 4
    $this->loggingColumnInfo($newColumns, $obsoleteColumns, $alteredColumns);
300 4
    $this->addNewColumns($newColumns);
301
302 4
    return ['full_columns'     => $this->getTableColumnsFromConfig($newColumns, $obsoleteColumns),
303 4
            'new_columns'      => $newColumns,
304 4
            'obsolete_columns' => $obsoleteColumns,
305 4
            'altered_columns'  => $alteredColumns];
306
  }
307
308
  //--------------------------------------------------------------------------------------------------------------------
309
  /**
310
   * Check for know what columns array returns.
311
   *
312
   * @param Columns $newColumns
313
   * @param Columns $obsoleteColumns
314
   *
315
   * @return Columns
316
   */
317 4
  private function getTableColumnsFromConfig($newColumns, $obsoleteColumns)
318
  {
319 4
    $new      = $newColumns->getColumns();
320 4
    $obsolete = $obsoleteColumns->getColumns();
321 4
    if (!empty($new) && !empty($obsolete))
322 4
    {
323
      return $this->dataTableColumnsConfig;
324
    }
325
326 4
    return $this->dataTableColumnsDatabase;
327
  }
328
329
  //--------------------------------------------------------------------------------------------------------------------
330
  /**
331
   * Create and return trigger name.
332
   *
333
   * @param string $action Trigger on action (Insert, Update, Delete)
334
   *
335
   * @return string
336
   */
337 4
  private function getTriggerName($action)
338
  {
339 4
    return strtolower(sprintf('trg_%s_%s', $this->alias, $action));
340
  }
341
342
  //--------------------------------------------------------------------------------------------------------------------
343
  /**
344
   * Lock the table to prevent insert, updates, or deletes between dropping and creating triggers.
345
   *
346
   * @param string $tableName Name of table
347
   */
348 4
  private function lockTable($tableName)
349
  {
350 4
    DataLayer::lockTable($tableName);
351 4
  }
352
353
  //--------------------------------------------------------------------------------------------------------------------
354
  /**
355
   * Logging new and obsolete columns.
356
   *
357
   * @param Columns $newColumns
358
   * @param Columns $obsoleteColumns
359
   * @param Columns $alteredColumns
360
   */
361 4
  private function loggingColumnInfo($newColumns, $obsoleteColumns, $alteredColumns)
362
  {
363 4
    $new      = $newColumns->getColumns();
364 4
    $obsolete = $obsoleteColumns->getColumns();
365 4
    if (!empty($new) && !empty($obsolete))
366 4
    {
367
      $this->io->logInfo('Found both new and obsolete columns for table %s', $this->tableName);
368
      $this->io->logInfo('No action taken');
369
370
      /** @var ColumnType $column */
371
      foreach ($newColumns->getColumns() as $column)
372
      {
373
        $this->io->logInfo('New column %s', $column->getProperty('column_name'));
374
      }
375
      foreach ($obsoleteColumns->getColumns() as $column)
376
      {
377
        $this->io->logInfo('Obsolete column %s', $column->getProperty('column_name'));
378
      }
379
    }
380
381
    /** @var ColumnType $column */
382 4
    foreach ($obsoleteColumns->getColumns() as $column)
383
    {
384
      $this->io->logInfo('Obsolete column %s.%s', $this->tableName, $column->getProperty('column_name'));
385 4
    }
386
387
    /** @var ColumnType $column */
388 4
    foreach ($newColumns->getColumns() as $column)
389
    {
390
      $this->io->logInfo('New column %s.%s', $this->tableName, $column->getProperty('column_name'));
391 4
    }
392
393 4
    foreach ($alteredColumns->getColumns() as $column)
394
    {
395
      $this->io->logInfo('Type of <dbo>%s.%s</dbo> has been altered to <dbo>%s</dbo>',
396
                         $this->tableName,
397
                         $column['column_name'],
398
                         $column['column_type']);
399 4
    }
400 4
  }
401
402
  //--------------------------------------------------------------------------------------------------------------------
403
  /**
404
   * Releases all table locks.
405
   */
406 4
  private function unlockTables()
407
  {
408 4
    DataLayer::unlockTables();
409 4
  }
410
411
  //--------------------------------------------------------------------------------------------------------------------
412
}
413
414
//----------------------------------------------------------------------------------------------------------------------
415