CreateAuditTrigger::buildStatement()   B
last analyzed

Complexity

Conditions 7
Paths 25

Size

Total Lines 52
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 28
CRAP Score 7.002

Importance

Changes 6
Bugs 0 Features 0
Metric Value
cc 7
eloc 32
c 6
b 0
f 0
nc 25
nop 0
dl 0
loc 52
ccs 28
cts 29
cp 0.9655
crap 7.002
rs 8.4746

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
declare(strict_types=1);
3
4
namespace SetBased\Audit\MySql\Sql;
5
6
use SetBased\Audit\Metadata\TableColumnsMetadata;
7
use SetBased\Audit\MySql\AuditDataLayer;
8
use SetBased\Exception\FallenException;
9
use SetBased\Exception\RuntimeException;
10
use SetBased\Helper\CodeStore\MySqlCompoundSyntaxCodeStore;
11
12
/**
13
 * Class for creating SQL statements for creating audit triggers.
14
 */
15
class CreateAuditTrigger
16
{
17
  //--------------------------------------------------------------------------------------------------------------------
18
  /**
19
   * The metadata of the additional audit columns.
20
   *
21
   * @var TableColumnsMetadata
22
   */
23
  private TableColumnsMetadata $additionalAuditColumns;
24
25
  /**
26
   * Additional SQL statements.
27
   *
28
   * @var string[]|null
29
   */
30
  private ?array $additionalSql;
31
32
  /**
33
   * The name of the audit schema.
34
   *
35
   * @var string
36
   */
37
  private string $auditSchemaName;
38
39
  /**
40
   * The generated code.
41
   *
42
   * @var MySqlCompoundSyntaxCodeStore
43
   */
44
  private MySqlCompoundSyntaxCodeStore $code;
45
46
  /**
47
   * The name of the data schema.
48
   *
49
   * @var string
50
   */
51
  private string $dataSchemaName;
52
53
  /**
54
   * The name of the MySQL user defined variable for skipping triggers. When the value of this variable is not null the
55
   * audit trigger will (effectively) be sipped.
56
   *
57
   * @var string|null
58
   */
59
  private ?string $skipVariable;
60
61
  /**
62
   * Audit columns from metadata.
63
   *
64
   * @var TableColumnsMetadata
65
   */
66
  private TableColumnsMetadata $tableColumns;
67
68
  /**
69
   * The name of the data table.
70
   *
71
   * @var string
72
   */
73
  private string $tableName;
74
75
  /**
76
   * The trigger action (i.e. INSERT, UPDATE, or DELETE).
77
   *
78
   * @var string
79
   */
80
  private string $triggerAction;
81
82
  /**
83
   * The name of the trigger.
84
   *
85
   * @var string
86
   */
87
  private string $triggerName;
88
89
  //--------------------------------------------------------------------------------------------------------------------
90
  /**
91
   * Creates a trigger on a table.
92
   *
93
   * @param string               $dataSchemaName         The name of the data schema.
94
   * @param string               $auditSchemaName        The name of the audit schema.
95
   * @param string               $tableName              The name of the table.
96
   * @param string               $triggerAction          The trigger action (i.e. INSERT, UPDATE, or DELETE).
97
   * @param string               $triggerName            The name of the trigger.
98
   * @param TableColumnsMetadata $additionalAuditColumns The metadata of the additional audit columns.
99
   * @param TableColumnsMetadata $tableColumns           The metadata of the data table columns.
100
   * @param string|null          $skipVariable           The name of the MySQL user defined variable for skipping
101
   *                                                     triggers.
102 32
   * @param string[]|null        $additionalSql          Additional SQL statements.
103
   */
104
  public function __construct(string               $dataSchemaName,
105
                              string               $auditSchemaName,
106
                              string               $tableName,
107
                              string               $triggerName,
108
                              string               $triggerAction,
109
                              TableColumnsMetadata $additionalAuditColumns,
110
                              TableColumnsMetadata $tableColumns,
111
                              ?string              $skipVariable,
112 32
                              ?array               $additionalSql)
113 32
  {
114 32
    $this->dataSchemaName         = $dataSchemaName;
115 32
    $this->auditSchemaName        = $auditSchemaName;
116 32
    $this->tableName              = $tableName;
117 32
    $this->triggerName            = $triggerName;
118 32
    $this->triggerAction          = $triggerAction;
119 32
    $this->skipVariable           = $skipVariable;
120 32
    $this->additionalAuditColumns = $additionalAuditColumns;
121 32
    $this->tableColumns           = $tableColumns;
122
    $this->additionalSql          = $additionalSql;
123
  }
124
125
  //--------------------------------------------------------------------------------------------------------------------
126
  /**
127
   * Returns the SQL code for creating an audit trigger.
128
   *
129
   * @return string
130
   *
131 32
   * @throws FallenException
132
   */
133 32
  public function buildStatement(): string
134
  {
135 32
    $this->code = new MySqlCompoundSyntaxCodeStore();
136 32
137
    $rowState = [];
138 32
    switch ($this->triggerAction)
139 32
    {
140 32
      case 'INSERT':
141
        $rowState[] = 'NEW';
142 32
        break;
143 32
144 32
      case 'DELETE':
145
        $rowState[] = 'OLD';
146 32
        break;
147 32
148 32
      case 'UPDATE':
149 32
        $rowState[] = 'OLD';
150
        $rowState[] = 'NEW';
151
        break;
152
153
      default:
154
        throw new FallenException('action', $this->triggerAction);
155 32
    }
156 32
157 32
    $this->code->append(sprintf('create trigger `%s`.`%s`', $this->dataSchemaName, $this->triggerName));
158 32
    $this->code->append(sprintf('after %s on `%s`.`%s`',
159 32
                                strtolower($this->triggerAction),
160 32
                                $this->dataSchemaName,
161 32
                                $this->tableName));
162
    $this->code->append('for each row');
163 32
    $this->code->append('begin');
164
165 32
    if ($this->skipVariable!==null)
166
    {
167 32
      $this->code->append(sprintf('if (%s is null) then', $this->skipVariable));
168 32
    }
169
170 32
    $this->code->append($this->additionalSql);
171
172
    $this->createInsertStatement($rowState[0]);
173 32
    if (count($rowState)===2)
174 32
    {
175
      $this->createInsertStatement($rowState[1]);
176 32
    }
177
178
    if ($this->skipVariable!==null)
179
    {
180
      $this->code->append('end if;');
181
    }
182
    $this->code->append('end');
183
184
    return $this->code->getCode();
185 32
  }
186
187 32
  //--------------------------------------------------------------------------------------------------------------------
188 32
  /**
189 32
   * Adds an insert SQL statement to SQL code for a trigger.
190
   *
191
   * @param string $rowState The row state (i.e. OLD or NEW).
192
   */
193
  private function createInsertStatement(string $rowState): void
194
  {
195 32
    $this->createInsertStatementInto();
196
    $this->createInsertStatementValues($rowState);
197 32
  }
198
199
  //--------------------------------------------------------------------------------------------------------------------
200 32
  /**
201
   * Adds the "insert into" part of an insert SQL statement to SQL code for a trigger.
202 21
   */
203 21
  private function createInsertStatementInto(): void
204
  {
205
    $columnNames = '';
206
207 32
    // First the audit columns.
208
    foreach ($this->additionalAuditColumns->getColumns() as $column)
209 32
    {
210 32
      if ($columnNames!=='')
211
      {
212
        $columnNames .= ',';
213 32
      }
214 32
      $columnNames .= sprintf('`%s`', $column->getName());
215
    }
216
217
    // Second the audit columns.
218
    foreach ($this->tableColumns->getColumns() as $column)
219
    {
220
      if ($columnNames!=='')
221
      {
222 32
        $columnNames .= ',';
223
      }
224 32
      $columnNames .= sprintf('`%s`', $column->getName());
225
    }
226
227 32
    $this->code->append(sprintf('insert into `%s`.`%s`(%s)', $this->auditSchemaName, $this->tableName, $columnNames));
228
  }
229 21
230 21
  //--------------------------------------------------------------------------------------------------------------------
231
  /**
232
   * Adds the "values" part of an insert SQL statement to SQL code for a trigger.
233
   *
234 21
   * @param string $rowState The row state (i.e. OLD or NEW).
235 20
   */
236
  private function createInsertStatementValues(string $rowState): void
237 20
  {
238 20
    $values = '';
239 20
240
    // First the values for the audit columns.
241 20
    foreach ($this->additionalAuditColumns->getColumns() as $column)
242 20
    {
243 20
      $column = $column->getProperties();
244
      if ($values!=='')
245
      {
246
        $values .= ',';
247
      }
248 20
249
      switch (true)
250 11
      {
251 11
        case (isset($column['value_type'])):
252 11
          switch ($column['value_type'])
253
          {
254
            case 'ACTION':
255
              $values .= AuditDataLayer::$dl->quoteString($this->triggerAction);
256
              break;
257
258
            case 'STATE':
259
              $values .= AuditDataLayer::$dl->quoteString($rowState);
260 32
              break;
261
262 32
            default:
263 32
              throw new FallenException('value_type', ($column['value_type']));
264
          }
265
          break;
266 32
267 32
        case (isset($column['expression'])):
268
          $values .= $column['expression'];
269
          break;
270
271
        default:
272
          throw new RuntimeException('None of value_type and expression are set.');
273
      }
274
    }
275
276
    // Second the values for the audit columns.
277
    foreach ($this->tableColumns->getColumns() as $column)
278
    {
279
      if ($values!=='')
280
      {
281
        $values .= ',';
282
      }
283
      $values .= sprintf('%s.`%s`', $rowState, $column->getName());
284
    }
285
286
    $this->code->append(sprintf('values(%s);', $values));
287
  }
288
289
  //--------------------------------------------------------------------------------------------------------------------
290
}
291
292
//----------------------------------------------------------------------------------------------------------------------
293