Passed
Branch master (406faa)
by P.R.
05:09
created

AuditDataLayer::executeMulti()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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