Completed
Push — master ( 5d62cd...a400a0 )
by P.R.
04:25
created

Table::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 19
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 19
rs 9.4285
cc 1
eloc 17
nc 1
nop 8

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
  public function __construct($io,
92
                              $tableName,
93
                              $dataSchema,
94
                              $auditSchema,
95
                              $configColumnsMetadata,
96
                              $auditColumnsMetadata,
97
                              $alias,
98
                              $skipVariable)
99
  {
100
    $this->io                       = $io;
101
    $this->tableName                = $tableName;
102
    $this->dataTableColumnsConfig   = new Columns($configColumnsMetadata);
103
    $this->dataSchemaName           = $dataSchema;
104
    $this->auditSchemaName          = $auditSchema;
105
    $this->dataTableColumnsDatabase = new Columns($this->getColumnsFromInformationSchema());
106
    $this->auditColumns             = new Columns($auditColumnsMetadata);
107
    $this->alias                    = $alias;
108
    $this->skipVariable             = $skipVariable;
109
  }
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
  public function createMissingAuditTable()
127
  {
128
    $this->io->logInfo('Creating audit table <dbo>%s.%s<dbo>', $this->auditSchemaName, $this->tableName);
129
130
    $columns = Columns::combine($this->auditColumns, $this->dataTableColumnsDatabase);
131
    DataLayer::createAuditTable($this->dataSchemaName, $this->auditSchemaName, $this->tableName, $columns);
132
  }
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
  public function createTriggers($additionalSql)
141
  {
142
    // Lock the table to prevent insert, updates, or deletes between dropping and creating triggers.
143
    $this->lockTable($this->tableName);
144
145
    // Drop all triggers, if any.
146
    $this->dropTriggers();
147
148
    // Create or recreate the audit triggers.
149
    $this->createTableTrigger('INSERT', $this->skipVariable, $additionalSql);
150
    $this->createTableTrigger('UPDATE', $this->skipVariable, $additionalSql);
151
    $this->createTableTrigger('DELETE', $this->skipVariable, $additionalSql);
152
153
    // Insert, updates, and deletes are no audited again. So, release lock on the table.
154
    $this->unlockTables();
155
  }
156
157
  //--------------------------------------------------------------------------------------------------------------------
158
  /**
159
   * Returns the name of this table.
160
   *
161
   * @return string
162
   */
163
  public function getTableName()
164
  {
165
    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
  public function main($additionalSql)
177
  {
178
    $comparedColumns = null;
179
    if (isset($this->dataTableColumnsConfig))
180
    {
181
      $comparedColumns = $this->getTableColumnInfo();
182
    }
183
184
    $newColumns      = $comparedColumns['new_columns']->getColumns();
185
    $obsoleteColumns = $comparedColumns['obsolete_columns']->getColumns();
186
    if (empty($newColumns) && empty($obsoleteColumns))
187
    {
188
      $alteredColumns = $comparedColumns['altered_columns']->getColumns();
189
      if (empty($alteredColumns))
190
      {
191
        $this->createTriggers($additionalSql);
192
      }
193
    }
194
195
    return $comparedColumns;
196
  }
197
198
  //--------------------------------------------------------------------------------------------------------------------
199
  /**
200
   * Adds new columns to audit table.
201
   *
202
   * @param Columns $columns Columns array
203
   */
204
  private function addNewColumns($columns)
205
  {
206
    DataLayer::addNewColumns($this->auditSchemaName, $this->tableName, $columns);
207
  }
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
  private function createTableTrigger($action, $skipVariable, $additionSql)
218
  {
219
    $triggerName = $this->getTriggerName($action);
220
221
    $this->io->logVerbose('Creating trigger <dbo>%s.%s</dbo> on table <dbo>%s.%s</dbo>',
222
                          $this->dataSchemaName,
223
                          $triggerName,
224
                          $this->dataSchemaName,
225
                          $this->tableName);
226
227
    DataLayer::createAuditTrigger($this->dataSchemaName,
228
                                  $this->auditSchemaName,
229
                                  $this->tableName,
230
                                  $triggerName,
231
                                  $action,
232
                                  $this->auditColumns,
233
                                  $this->dataTableColumnsDatabase,
234
                                  $skipVariable,
235
                                  $additionSql);
236
  }
237
238
  //--------------------------------------------------------------------------------------------------------------------
239
  /**
240
   * Drops all triggers from this table.
241
   */
242
  private function dropTriggers()
243
  {
244
    $triggers = DataLayer::getTableTriggers($this->dataSchemaName, $this->tableName);
245
    foreach ($triggers as $trigger)
246
    {
247
      $this->io->logVerbose('Dropping trigger <dbo>%s</dbo> on <dbo>%s.%s</dbo>',
248
                            $trigger['trigger_name'],
249
                            $this->dataSchemaName,
250
                            $this->tableName);
251
252
      DataLayer::dropTrigger($this->dataSchemaName, $trigger['trigger_name']);
253
    }
254
  }
255
256
  //--------------------------------------------------------------------------------------------------------------------
257
  /**
258
   * Compares columns types from table in data_schema with columns in config file.
259
   *
260
   * @return Columns
261
   */
262
  private function getAlteredColumns()
263
  {
264
    $alteredColumnsTypes = Columns::differentColumnTypes($this->dataTableColumnsDatabase,
265
                                                         $this->dataTableColumnsConfig);
266
267
    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
  private function getColumnsFromInformationSchema()
277
  {
278
    $result = DataLayer::getTableColumns($this->dataSchemaName, $this->tableName);
279
280
    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
  private function getTableColumnInfo()
290
  {
291
    $columnActual  = new Columns(DataLayer::getTableColumns($this->auditSchemaName, $this->tableName));
292
    $columnsConfig = Columns::combine($this->auditColumns, $this->dataTableColumnsConfig);
293
    $columnsTarget = Columns::combine($this->auditColumns, $this->dataTableColumnsDatabase);
294
295
    $newColumns      = Columns::notInOtherSet($columnsTarget, $columnActual);
296
    $obsoleteColumns = Columns::notInOtherSet($columnsConfig, $columnsTarget);
297
    $alteredColumns  = $this->getAlteredColumns();
298
299
    $this->loggingColumnInfo($newColumns, $obsoleteColumns, $alteredColumns);
300
    $this->addNewColumns($newColumns);
301
302
    return ['full_columns'     => $this->getTableColumnsFromConfig($newColumns, $obsoleteColumns),
303
            'new_columns'      => $newColumns,
304
            'obsolete_columns' => $obsoleteColumns,
305
            '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
  private function getTableColumnsFromConfig($newColumns, $obsoleteColumns)
318
  {
319
    $new      = $newColumns->getColumns();
320
    $obsolete = $obsoleteColumns->getColumns();
321
    if (!empty($new) && !empty($obsolete))
322
    {
323
      return $this->dataTableColumnsConfig;
324
    }
325
326
    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
  private function getTriggerName($action)
338
  {
339
    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
  private function lockTable($tableName)
349
  {
350
    DataLayer::lockTable($tableName);
351
  }
352
353
  //--------------------------------------------------------------------------------------------------------------------
354
  /**
355
   * Logging new and obsolete columns.
356
   *
357
   * @param Columns $newColumns
358
   * @param Columns $obsoleteColumns
359
   * @param Columns $alteredColumns
360
   */
361
  private function loggingColumnInfo($newColumns, $obsoleteColumns, $alteredColumns)
362
  {
363
    $new      = $newColumns->getColumns();
364
    $obsolete = $obsoleteColumns->getColumns();
365
    if (!empty($new) && !empty($obsolete))
366
    {
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
    foreach ($obsoleteColumns->getColumns() as $column)
383
    {
384
      $this->io->logInfo('Obsolete column %s.%s', $this->tableName, $column->getProperty('column_name'));
385
    }
386
387
    /** @var ColumnType $column */
388
    foreach ($newColumns->getColumns() as $column)
389
    {
390
      $this->io->logInfo('New column %s.%s', $this->tableName, $column->getProperty('column_name'));
391
    }
392
393
    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
    }
400
  }
401
402
  //--------------------------------------------------------------------------------------------------------------------
403
  /**
404
   * Releases all table locks.
405
   */
406
  private function unlockTables()
407
  {
408
    DataLayer::unlockTables();
409
  }
410
411
  //--------------------------------------------------------------------------------------------------------------------
412
}
413
414
//----------------------------------------------------------------------------------------------------------------------
415