Passed
Branch master (1f48b5)
by P.R.
05:45
created

AuditDataLayer::logQuery()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 1
dl 0
loc 14
ccs 6
cts 6
cp 1
crap 2
rs 9.4285
c 0
b 0
f 0
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 2
  public static function addNewColumns($auditSchemaName, $tableName, $columns)
35
  {
36 2
    $helper = new AlterAuditTableAddColumns($auditSchemaName, $tableName, $columns);
37 2
    $sql    = $helper->buildStatement();
38
39 2
    static::executeNone($sql);
40 2
  }
41
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 22
  public static function createAuditTable($dataSchemaName, $auditSchemaName, $tableName, $columns)
53
  {
54 22
    $helper = new CreateAuditTable($dataSchemaName, $auditSchemaName, $tableName, $columns);
55 22
    $sql    = $helper->buildStatement();
56
57 22
    static::executeNone($sql);
58 22
  }
59
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 25
  public static function createAuditTrigger($dataSchemaName,
75
                                            $auditSchemaName,
76
                                            $tableName,
77
                                            $triggerName,
78
                                            $triggerAction,
79
                                            $additionalAuditColumns,
80
                                            $tableColumns,
81
                                            $skipVariable,
82
                                            $additionSql)
83
  {
84 25
    $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
95 25
    static::executeNone($sql);
96 25
  }
97
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 18
  public static function createTemporaryTable($schemaName, $tableName, $auditColumns)
107
  {
108 18
    $sql = new MySqlCompoundSyntaxCodeStore();
109 18
    $sql->append(sprintf('create table `%s`.`%s` (', $schemaName, $tableName));
110 18
    foreach ($auditColumns as $column)
111
    {
112 18
      $sql->append(sprintf('%s %s', $column['column_name'], $column['column_type']));
113 18
      if (end($auditColumns)!==$column)
114
      {
115 18
        $sql->appendToLastLine(',');
116
      }
117
    }
118 18
    $sql->append(')');
119
120 18
    static::executeNone($sql->getCode());
121 18
  }
122
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 18
  public static function dropTemporaryTable($schemaName, $tableName)
131
  {
132 18
    $sql = sprintf('drop table `%s`.`%s`', $schemaName, $tableName);
133
134 18
    static::executeNone($sql);
135 18
  }
136
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 8
  public static function dropTrigger($triggerSchema, $triggerName)
145
  {
146 8
    $sql = sprintf('drop trigger `%s`.`%s`', $triggerSchema, $triggerName);
147
148 8
    static::executeNone($sql);
149 8
  }
150
151
  //--------------------------------------------------------------------------------------------------------------------
152
  /**
153
   * @inheritdoc
154
   */
155
  public static function executeBulk($bulkHandler, $query)
156
  {
157
    static::logQuery($query);
158
159
    parent::executeBulk($bulkHandler, $query);
160
  }
161
162
  //--------------------------------------------------------------------------------------------------------------------
163
  /**
164
   * @inheritdoc
165
   */
166 25
  public static function executeNone($query)
167
  {
168 25
    static::logQuery($query);
169
170 25
    return parent::executeNone($query);
171
  }
172
173
  //--------------------------------------------------------------------------------------------------------------------
174
  /**
175
   * @inheritdoc
176
   */
177
  public static function executeRow0($query)
178
  {
179
    static::logQuery($query);
180
181
    return parent::executeRow0($query);
182
  }
183
184
  //--------------------------------------------------------------------------------------------------------------------
185
  /**
186
   * @inheritdoc
187
   */
188 22
  public static function executeRow1($query)
189
  {
190 22
    static::logQuery($query);
191
192 22
    return parent::executeRow1($query);
193
  }
194
195
  //--------------------------------------------------------------------------------------------------------------------
196
  /**
197
   * @inheritdoc
198
   */
199 26
  public static function executeRows($query)
200
  {
201 26
    static::logQuery($query);
202
203 26
    return parent::executeRows($query);
204
  }
205
206
  //--------------------------------------------------------------------------------------------------------------------
207
  /**
208
   * @inheritdoc
209
   */
210
  public static function executeSingleton0($query)
211
  {
212
    static::logQuery($query);
213
214
    return parent::executeSingleton0($query);
215
  }
216
217
  //--------------------------------------------------------------------------------------------------------------------
218
  /**
219
   * @inheritdoc
220
   */
221
  public static function executeSingleton1($query)
222
  {
223
    static::logQuery($query);
224
225
    return parent::executeSingleton1($query);
226
  }
227
228
  //--------------------------------------------------------------------------------------------------------------------
229
  /**
230
   * @inheritdoc
231
   */
232
  public static function executeTable($query)
233
  {
234
    static::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 25
  public static function getTableColumns($schemaName, $tableName)
249
  {
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 25
    $sql = sprintf("
253
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 25
                   static::quoteString($schemaName),
264 25
                   static::quoteString($tableName));
265
266 25
    return static::executeRows($sql);
267
  }
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 22
  public static function getTableOptions($schemaName, $tableName)
279
  {
280 22
    $sql = sprintf('
281
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 22
                   static::quoteString($schemaName),
291 22
                   static::quoteString($tableName));
292
293 22
    return static::executeRow1($sql);
294
  }
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 25
  public static function getTableTriggers($schemaName, $tableName)
306
  {
307 25
    $sql = sprintf('
308
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 25
                   static::quoteString($schemaName),
314 25
                   static::quoteString($tableName));
315
316 25
    return static::executeRows($sql);
317
  }
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 26
  public static function getTablesNames($schemaName)
328
  {
329 26
    $sql = sprintf("
330
select TABLE_NAME as table_name
331
from   information_schema.TABLES
332
where  TABLE_SCHEMA = %s
333
and    TABLE_TYPE   = 'BASE TABLE'
334 26
order by TABLE_NAME", static::quoteString($schemaName));
335
336 26
    return static::executeRows($sql);
337
  }
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 static::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
    static::executeNone($sql);
373 25
  }
374
375
  //--------------------------------------------------------------------------------------------------------------------
376
  /**
377
   * @inheritdoc
378
   */
379
  public static function multiQuery($queries)
380
  {
381
    static::logQuery($queries);
382
383
    return parent::multiQuery($queries);
384
  }
385
386
  //--------------------------------------------------------------------------------------------------------------------
387
  /**
388
   * @inheritdoc
389
   */
390
  public static function query($query)
391
  {
392
    static::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
   *
404
   * @return TableColumnsMetadata
405
   */
406 26
  public static function resolveCanonicalAdditionalAuditColumns($auditSchema, $additionalAuditColumns)
407
  {
408 26
    if (empty($additionalAuditColumns))
409
    {
410 8
      return new TableColumnsMetadata([], 'AuditColumnMetadata');
411
    }
412
413 18
    $tableName = '_TMP_'.uniqid();
414 18
    static::createTemporaryTable($auditSchema, $tableName, $additionalAuditColumns);
415 18
    $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 18
    static::dropTemporaryTable($auditSchema, $tableName);
417
418 18
    foreach ($additionalAuditColumns as $column)
419
    {
420 18
      $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 18
      if (isset($column['value_type']))
423
      {
424 18
        $columns[$key]['value_type'] = $column['value_type'];
425
      }
426 18
      if (isset($column['expression']))
427
      {
428 18
        $columns[$key]['expression'] = $column['expression'];
429
      }
430
    }
431
432 18
    return new TableColumnsMetadata($columns, 'AuditColumnMetadata');
433
  }
434
435
  //--------------------------------------------------------------------------------------------------------------------
436
  /**
437
   * Sets the Output decorator.
438
   *
439
   * @param StratumStyle $io The Output decorator.
440
   */
441 26
  public static function setIo($io)
442
  {
443 26
    static::$io = $io;
0 ignored issues
show
Bug introduced by
Since $io is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $io to at least protected.
Loading history...
444 26
  }
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
   *
453
   * @return array[]
454
   */
455
  public static function showColumns($schemaName, $tableName)
456
  {
457
    $sql = sprintf('SHOW COLUMNS FROM `%s`.`%s`', $schemaName, $tableName);
458
459
    return static::executeRows($sql);
460
  }
461
462
  //--------------------------------------------------------------------------------------------------------------------
463
  /**
464
   * Releases all table locks.
465
   */
466 25
  public static function unlockTables()
467
  {
468 25
    $sql = 'unlock tables';
469
470 25
    static::executeNone($sql);
471 25
  }
472
473
  //--------------------------------------------------------------------------------------------------------------------
474
  /**
475
   * @inheritdoc
476
   */
477
  protected static function realQuery($query)
478
  {
479
    static::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 26
  private static function logQuery($query)
491
  {
492 26
    $query = trim($query);
493
494 26
    if (strpos($query, "\n")!==false)
495
    {
496
      // Query is a multi line query.
497 26
      static::$io->logVeryVerbose('Executing query:');
0 ignored issues
show
Bug introduced by
Since $io is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $io to at least protected.
Loading history...
498 26
      static::$io->logVeryVerbose('<sql>%s</sql>', $query);
499
    }
500
    else
501
    {
502
      // Query is a single line query.
503 25
      static::$io->logVeryVerbose('Executing query: <sql>%s</sql>', $query);
504
    }
505 26
  }
506
507
  //--------------------------------------------------------------------------------------------------------------------
508
}
509
510
//----------------------------------------------------------------------------------------------------------------------
511