Test Failed
Push — master ( d02081...898276 )
by P.R.
04:01
created

AuditDataLayer::addNewColumns()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 3
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
ccs 3
cts 3
cp 1
crap 1
1
<?php
2
3
namespace SetBased\Audit\MySql;
4
5
use SetBased\Audit\Metadata\TableColumnsMetadata;
6
use SetBased\Audit\MySql\Sql\AlterAuditTableAddColumns;
7
use SetBased\Audit\MySql\Sql\CreateAuditTable;
8
use SetBased\Audit\MySql\Sql\CreateAuditTrigger;
9
use SetBased\Helper\CodeStore\MySqlCompoundSyntaxCodeStore;
10
use SetBased\Stratum\MySql\StaticDataLayer;
11
use SetBased\Stratum\Style\StratumStyle;
12
13
/**
14
 * Class for executing SQL statements and retrieving metadata from MySQL.
15
 */
16
class AuditDataLayer extends StaticDataLayer
17
{
18
  //--------------------------------------------------------------------------------------------------------------------
19
  /**
20
   * The Output decorator.
21
   *
22
   * @var StratumStyle
23
   */
24
  private static $io;
25
26
  //--------------------------------------------------------------------------------------------------------------------
27
  /**
28
   * Adds new columns to an audit table.
29
   *
30
   * @param string                                        $auditSchemaName The name of audit schema.
31
   * @param string                                        $tableName       The name of the table.
32
   * @param \SetBased\Audit\Metadata\TableColumnsMetadata $columns         The metadata of the new columns.
33
   */
34
  public static function addNewColumns($auditSchemaName, $tableName, $columns)
35 1
  {
36
    $helper = new AlterAuditTableAddColumns($auditSchemaName, $tableName, $columns);
37 1
    $sql    = $helper->buildStatement();
38 1
39
    self::executeNone($sql);
40 1
  }
41 1
42
  //--------------------------------------------------------------------------------------------------------------------
43
  /**
44
   * Creates an audit table.
45
   *
46
   * @param string               $dataSchemaName  The name of the data schema.
47
   * @param string               $auditSchemaName The name of the audit schema.
48
   * @param string               $tableName       The name of the table.
49
   * @param TableColumnsMetadata $columns         The metadata of the columns of the audit table (i.e. the audit
50
   *                                              columns and columns of the data table).
51
   */
52
  public static function createAuditTable($dataSchemaName, $auditSchemaName, $tableName, $columns)
53 22
  {
54
    $helper = new CreateAuditTable($dataSchemaName, $auditSchemaName, $tableName, $columns);
55 22
    $sql    = $helper->buildStatement();
56 22
57
    self::executeNone($sql);
58 22
  }
59 22
60
  //--------------------------------------------------------------------------------------------------------------------
61
  /**
62
   * Creates a trigger on a table.
63
   *
64
   * @param string               $dataSchemaName         The name of the data schema.
65
   * @param string               $auditSchemaName        The name of the audit schema.
66
   * @param string               $tableName              The name of the table.
67
   * @param string               $triggerAction          The trigger action (i.e. INSERT, UPDATE, or DELETE).
68
   * @param string               $triggerName            The name of the trigger.
69
   * @param TableColumnsMetadata $additionalAuditColumns The metadata of the additional audit columns.
70
   * @param TableColumnsMetadata $tableColumns           The metadata of the data table columns.
71
   * @param string               $skipVariable           The skip variable.
72
   * @param string[]             $additionSql            Additional SQL statements.
73
   */
74
  public static function createAuditTrigger($dataSchemaName,
75 25
                                            $auditSchemaName,
76
                                            $tableName,
77
                                            $triggerName,
78
                                            $triggerAction,
79
                                            $additionalAuditColumns,
80
                                            $tableColumns,
81
                                            $skipVariable,
82
                                            $additionSql)
83
  {
84
    $helper = new CreateAuditTrigger($dataSchemaName,
85 25
                                     $auditSchemaName,
86 25
                                     $tableName,
87 25
                                     $triggerName,
88 25
                                     $triggerAction,
89 25
                                     $additionalAuditColumns,
90 25
                                     $tableColumns,
91 25
                                     $skipVariable,
92 25
                                     $additionSql);
93 25
    $sql    = $helper->buildStatement();
94 25
95
    self::executeNone($sql);
96 25
  }
97 25
98
  //--------------------------------------------------------------------------------------------------------------------
99
  /**
100
   * Create temp table for getting column type information for audit columns.
101
   *
102
   * @param string  $schemaName   The name of the table schema.
103
   * @param string  $tableName    The table name.
104
   * @param array[] $auditColumns Audit columns from config file.
105
   */
106
  public static function createTemporaryTable($schemaName, $tableName, $auditColumns)
107 18
  {
108
    $sql = new MySqlCompoundSyntaxCodeStore();
109 18
    $sql->append(sprintf('create table `%s`.`%s` (', $schemaName, $tableName));
110 18
    foreach ($auditColumns as $column)
111 18
    {
112
      $sql->append(sprintf('%s %s', $column['column_name'], $column['column_type']));
113 18
      if (end($auditColumns)!==$column)
114 18
      {
115
        $sql->appendToLastLine(',');
116 18
      }
117
    }
118
    $sql->append(')');
119 18
120
    self::executeNone($sql->getCode());
121 18
  }
122 18
123
  //--------------------------------------------------------------------------------------------------------------------
124
  /**
125
   * Drop table.
126
   *
127
   * @param string $schemaName The name of the table schema.
128
   * @param string $tableName  The name of the table.
129
   */
130
  public static function dropTemporaryTable($schemaName, $tableName)
131 18
  {
132
    $sql = sprintf('drop table `%s`.`%s`', $schemaName, $tableName);
133 18
134
    self::executeNone($sql);
135 18
  }
136 18
137
  //--------------------------------------------------------------------------------------------------------------------
138
  /**
139
   * Drops a trigger.
140
   *
141
   * @param string $triggerSchema The name of the trigger schema.
142
   * @param string $triggerName   The mame of trigger.
143
   */
144
  public static function dropTrigger($triggerSchema, $triggerName)
145 7
  {
146
    $sql = sprintf('drop trigger `%s`.`%s`', $triggerSchema, $triggerName);
147 7
148
    self::executeNone($sql);
149 7
  }
150 7
151
  //--------------------------------------------------------------------------------------------------------------------
152
  /**
153
   * @inheritdoc
154
   */
155
  public static function executeBulk($bulkHandler, $query)
156
  {
157
    self::logQuery($query);
158
159
    parent::executeBulk($bulkHandler, $query);
160
  }
161
162
  //--------------------------------------------------------------------------------------------------------------------
163
  /**
164
   * @inheritdoc
165
   */
166
  public static function executeNone($query)
167 25
  {
168
    self::logQuery($query);
169 25
170
    return parent::executeNone($query);
171 25
  }
172
173
  //--------------------------------------------------------------------------------------------------------------------
174
  /**
175
   * @inheritdoc
176
   */
177
  public static function executeRow0($query)
178
  {
179
    self::logQuery($query);
180
181
    return parent::executeRow0($query);
182
  }
183
184
  //--------------------------------------------------------------------------------------------------------------------
185
  /**
186
   * @inheritdoc
187
   */
188
  public static function executeRow1($query)
189 25
  {
190
    self::logQuery($query);
191 25
192
    return parent::executeRow1($query);
193 25
  }
194
195
  //--------------------------------------------------------------------------------------------------------------------
196
  /**
197
   * @inheritdoc
198
   */
199
  public static function executeRows($query)
200 26
  {
201
    self::logQuery($query);
202 26
203
    return parent::executeRows($query);
204 26
  }
205
206
  //--------------------------------------------------------------------------------------------------------------------
207
  /**
208
   * @inheritdoc
209
   */
210
  public static function executeSingleton0($query)
211
  {
212
    self::logQuery($query);
213
214
    return parent::executeSingleton0($query);
215
  }
216
217
  //--------------------------------------------------------------------------------------------------------------------
218
  /**
219
   * @inheritdoc
220
   */
221
  public static function executeSingleton1($query)
222
  {
223
    self::logQuery($query);
224
225
    return parent::executeSingleton1($query);
226
  }
227
228
  //--------------------------------------------------------------------------------------------------------------------
229
  /**
230
   * @inheritdoc
231
   */
232
  public static function executeTable($query)
233
  {
234
    self::logQuery($query);
235
236
    return parent::executeTable($query);
237
  }
238
239
  //--------------------------------------------------------------------------------------------------------------------
240
  /**
241
   * Selects metadata of all columns of table.
242
   *
243
   * @param string $schemaName The name of the table schema.
244
   * @param string $tableName  The name of the table.
245
   *
246
   * @return array[]
247
   */
248
  public static function getTableColumns($schemaName, $tableName)
249 25
  {
250
    // When a column has no default prior to MariaDB 10.2.7 column_default is null from MariaDB 10.2.7
251
    // column_default = 'NULL' (string(4)).
252
    $sql = sprintf("
253 25
select COLUMN_NAME                    as column_name
254
,      COLUMN_TYPE                    as column_type
255
,      ifnull(COLUMN_DEFAULT, 'NULL') as column_default 
256
,      IS_NULLABLE                    as is_nullable
257
,      CHARACTER_SET_NAME             as character_set_name
258
,      COLLATION_NAME                 as collation_name
259
from   information_schema.COLUMNS
260
where  TABLE_SCHEMA = %s
261
and    TABLE_NAME   = %s
262
order by ORDINAL_POSITION",
263
                   static::quoteString($schemaName),
264 25
                   static::quoteString($tableName));
265 25
266
    return self::executeRows($sql);
267 25
  }
268
269
  //--------------------------------------------------------------------------------------------------------------------
270
  /**
271
   * Selects table engine, character_set_name and table_collation.
272
   *
273
   * @param string $schemaName The name of the table schema.
274
   * @param string $tableName  The name of the table.
275
   *
276
   * @return array
277
   */
278
  public static function getTableOptions($schemaName, $tableName)
279 25
  {
280
    $sql = sprintf('
281 25
SELECT t1.TABLE_SCHEMA       as table_schema
282
,      t1.TABLE_NAME         as table_name
283
,      t1.TABLE_COLLATION    as table_collation
284
,      t1.ENGINE             as engine
285
,      t2.CHARACTER_SET_NAME as character_set_name
286
FROM       information_schema.TABLES                                t1
287
inner join information_schema.COLLATION_CHARACTER_SET_APPLICABILITY t2  on  t2.COLLATION_NAME = t1.TABLE_COLLATION
288
WHERE t1.TABLE_SCHEMA = %s
289
AND   t1.TABLE_NAME   = %s',
290
                   static::quoteString($schemaName),
291 25
                   static::quoteString($tableName));
292 25
293
    return self::executeRow1($sql);
294 25
  }
295
296
  //--------------------------------------------------------------------------------------------------------------------
297
  /**
298
   * Selects all triggers on a table.
299
   *
300
   * @param string $schemaName The name of the table schema.
301
   * @param string $tableName  The name of the table.
302
   *
303
   * @return array[]
304
   */
305
  public static function getTableTriggers($schemaName, $tableName)
306 25
  {
307
    $sql = sprintf('
308 25
select TRIGGER_NAME as trigger_name
309
from   information_schema.TRIGGERS
310
where  TRIGGER_SCHEMA     = %s
311
and    EVENT_OBJECT_TABLE = %s
312
order by Trigger_Name',
313
                   static::quoteString($schemaName),
314 25
                   static::quoteString($tableName));
315 25
316
    return self::executeRows($sql);
317 25
  }
318
319
  //--------------------------------------------------------------------------------------------------------------------
320
  /**
321
   * Selects all table names in a schema.
322
   *
323
   * @param string $schemaName The name of the schema.
324
   *
325
   * @return array[]
326
   */
327
  public static function getTablesNames($schemaName)
328 26
  {
329
    $sql = sprintf("
330 26
select TABLE_NAME as table_name
331
from   information_schema.TABLES
332
where  TABLE_SCHEMA = %s
333
and    TABLE_TYPE   = 'BASE TABLE'
334
order by TABLE_NAME", static::quoteString($schemaName));
335 26
336
    return self::executeRows($sql);
337 26
  }
338
339
  //--------------------------------------------------------------------------------------------------------------------
340
  /**
341
   * Selects all triggers in a schema
342
   *
343
   * @param string $schemaName The name of the table schema.
344
   *
345
   * @return array[]
346
   */
347
  public static function getTriggers($schemaName)
348
  {
349
    $sql = sprintf('
350
select EVENT_OBJECT_TABLE as table_name
351
,      TRIGGER_NAME       as trigger_name
352
from   information_schema.TRIGGERS
353
where  TRIGGER_SCHEMA     = %s
354
order by EVENT_OBJECT_TABLE
355
,        TRIGGER_NAME',
356
                   static::quoteString($schemaName));
357
358
    return self::executeRows($sql);
359
  }
360
361
  //--------------------------------------------------------------------------------------------------------------------
362
  /**
363
   * Acquires a write lock on a table.
364
   *
365
   * @param string $schemaName The schema of the table.
366
   * @param string $tableName  The table name.
367
   */
368 25
  public static function lockTable($schemaName, $tableName)
369
  {
370 25
    $sql = sprintf('lock tables `%s`.`%s` write', $schemaName, $tableName);
371
372 25
    self::executeNone($sql);
373 25
  }
374
375
  //--------------------------------------------------------------------------------------------------------------------
376
  /**
377
   * @inheritdoc
378
   */
379
  public static function multiQuery($queries)
380
  {
381
    self::logQuery($queries);
382
383
    return parent::multiQuery($queries);
384
  }
385
386
  //--------------------------------------------------------------------------------------------------------------------
387
  /**
388
   * @inheritdoc
389
   */
390
  public static function query($query)
391
  {
392
    self::logQuery($query);
393
394
    return parent::query($query);
395
  }
396
397
  //--------------------------------------------------------------------------------------------------------------------
398
  /**
399
   * Resolves the canonical column types of the additional audit columns.
400
   *
401
   * @param string  $auditSchema            The name of the audit schema.
402
   * @param array[] $additionalAuditColumns The metadata of the additional audit columns.
403 26
   *
404
   * @return TableColumnsMetadata
405 26
   */
406 26
  public static function resolveCanonicalAdditionalAuditColumns($auditSchema, $additionalAuditColumns)
407
  {
408
    if (empty($additionalAuditColumns))
409
    {
410
      return new TableColumnsMetadata([], 'AuditColumnMetadata');
411
    }
412
413
    $tableName = '_TMP_'.uniqid();
414
    static::createTemporaryTable($auditSchema, $tableName, $additionalAuditColumns);
415
    $columns = AuditDataLayer::getTableColumns($auditSchema, $tableName);
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
416
    static::dropTemporaryTable($auditSchema, $tableName);
417
418
    foreach ($additionalAuditColumns as $column)
419
    {
420
      $key = AuditDataLayer::searchInRowSet('column_name', $column['column_name'], $columns);
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
421
422
      if (isset($column['value_type']))
423
      {
424
        $columns[$key]['value_type'] = $column['value_type'];
425
      }
426
      if (isset($column['expression']))
427
      {
428 25
        $columns[$key]['expression'] = $column['expression'];
429
      }
430 25
    }
431
432 25
    return new TableColumnsMetadata($columns, 'AuditColumnMetadata');
433 25
  }
434
435
  //--------------------------------------------------------------------------------------------------------------------
436
  /**
437
   * Sets the Output decorator.
438
   *
439
   * @param StratumStyle $io The Output decorator.
440
   */
441
  public static function setIo($io)
442
  {
443
    self::$io = $io;
444
  }
445
446
  //--------------------------------------------------------------------------------------------------------------------
447
  /**
448
   * Drop table.
449
   *
450
   * @param string $schemaName The name of the table schema.
451
   * @param string $tableName  The name of the table.
452 26
   *
453
   * @return array[]
454 26
   */
455
  public static function showColumns($schemaName, $tableName)
456 26
  {
457
    $sql = sprintf('SHOW COLUMNS FROM `%s`.`%s`', $schemaName, $tableName);
458
459 26
    return self::executeRows($sql);
460 26
  }
461
462
  //--------------------------------------------------------------------------------------------------------------------
463
  /**
464
   * Releases all table locks.
465 25
   */
466
  public static function unlockTables()
467 26
  {
468
    $sql = 'unlock tables';
469
470
    self::executeNone($sql);
471
  }
472
473
  //--------------------------------------------------------------------------------------------------------------------
474
  /**
475
   * @inheritdoc
476
   */
477
  protected static function realQuery($query)
478
  {
479
    self::logQuery($query);
480
481
    parent::realQuery($query);
482
  }
483
484
  //--------------------------------------------------------------------------------------------------------------------
485
  /**
486
   * Logs the query on the console.
487
   *
488
   * @param string $query The query.
489
   */
490
  private static function logQuery($query)
491
  {
492
    $query = trim($query);
493
494
    if (strpos($query, "\n")!==false)
495
    {
496
      // Query is a multi line query.
497
      self::$io->logVeryVerbose('Executing query:');
498
      self::$io->logVeryVerbose('<sql>%s</sql>', $query);
499
    }
500
    else
501
    {
502
      // Query is a single line query.
503
      self::$io->logVeryVerbose('Executing query: <sql>%s</sql>', $query);
504
    }
505
  }
506
507
  //--------------------------------------------------------------------------------------------------------------------
508
}
509
510
//----------------------------------------------------------------------------------------------------------------------
511