Completed
Pull Request — master (#31)
by
unknown
03:08
created

AuditCommand::auditColumnTypes()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 20
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 20
rs 9.2
cc 4
eloc 12
nc 4
nop 0
1
<?php
2
//----------------------------------------------------------------------------------------------------------------------
3
namespace SetBased\Audit\MySql\Command;
4
5
use SetBased\Audit\MySql\DataLayer;
6
use SetBased\Audit\MySql\Table\Table;
7
use SetBased\Stratum\MySql\StaticDataLayer;
8
use SetBased\Stratum\Style\StratumStyle;
9
use Symfony\Component\Console\Input\InputArgument;
10
use Symfony\Component\Console\Input\InputInterface;
11
use Symfony\Component\Console\Output\OutputInterface;
12
13
//----------------------------------------------------------------------------------------------------------------------
14
/**
15
 * Command for creating audit tables and audit triggers.
16
 */
17
class AuditCommand extends MySqlCommand
18
{
19
  //--------------------------------------------------------------------------------------------------------------------
20
  /**
21
   * All tables in the in the audit schema.
22
   *
23
   * @var array
24
   */
25
  protected $auditSchemaTables;
26
27
  /**
28
   * Array of tables from data schema.
29
   *
30
   * @var array
31
   */
32
  protected $dataSchemaTables;
33
34
  /**
35
   * If true remove all column information from config file.
36
   *
37
   * @var boolean
38
   */
39
  private $pruneOption;
40
41
  //--------------------------------------------------------------------------------------------------------------------
42
  /**
43
   * Compares the tables listed in the config file and the tables found in the audit schema
44
   *
45
   * @param string                              $tableName Name of table
46
   * @param \SetBased\Audit\MySql\Table\Columns $columns   The table columns.
47
   */
48
  public function getColumns($tableName, $columns)
49
  {
50
    $newColumns = [];
51
    foreach ($columns->getColumns() as $column)
52
    {
53
      $newColumns[] = ['column_name' => $column['column_name'],
54
                       'column_type' => $column['column_type']];
55
    }
56
    $this->config['table_columns'][$tableName] = $newColumns;
57
58
    if ($this->pruneOption)
59
    {
60
      $this->config['table_columns'] = [];
61
    }
62
  }
63
64
  //--------------------------------------------------------------------------------------------------------------------
65
  /**
66
   * Getting list of all tables from information_schema of database from config file.
67
   */
68
  public function listOfTables()
69
  {
70
    $this->dataSchemaTables = DataLayer::getTablesNames($this->config['database']['data_schema']);
71
72
    $this->auditSchemaTables = DataLayer::getTablesNames($this->config['database']['audit_schema']);
73
  }
74
75
  //--------------------------------------------------------------------------------------------------------------------
76
  /**
77
   * Found tables in config file
78
   *
79
   * Compares the tables listed in the config file and the tables found in the data schema
80
   */
81
  public function unknownTables()
82
  {
83
    foreach ($this->dataSchemaTables as $table)
84
    {
85
      if (isset($this->config['tables'][$table['table_name']]))
86
      {
87
        if (!isset($this->config['tables'][$table['table_name']]['audit']))
88
        {
89
          $this->io->writeln(sprintf('<info>AuditApplication flag is not set in table %s</info>', $table['table_name']));
90
        }
91
        else
92
        {
93
          if ($this->config['tables'][$table['table_name']]['audit'])
94
          {
95
            $this->config['tables'][$table['table_name']]['alias'] = Table::getRandomAlias();
96
          }
97
        }
98
      }
99
      else
100
      {
101
        $this->io->writeln(sprintf('<info>Found new table %s</info>', $table['table_name']));
102
        $this->config['tables'][$table['table_name']] = ['audit' => false,
103
                                                         'alias' => null,
104
                                                         'skip'  => null];
105
      }
106
    }
107
  }
108
109
  //--------------------------------------------------------------------------------------------------------------------
110
  /**
111
   * {@inheritdoc}
112
   */
113
  protected function configure()
114
  {
115
    $this->setName('audit')
116
         ->setDescription('Create (missing) audit table and (re)creates audit triggers')
117
         ->addArgument('config file', InputArgument::OPTIONAL, 'The audit configuration file', 'etc/audit.json');
118
  }
119
120
  //--------------------------------------------------------------------------------------------------------------------
121
  /**
122
   * {@inheritdoc}
123
   */
124
  protected function execute(InputInterface $input, OutputInterface $output)
125
  {
126
    $this->io = new StratumStyle($input, $output);
127
128
    $this->configFileName = $input->getArgument('config file');
129
    $this->readConfigFile();
130
131
    // Create database connection with params from config file
132
    $this->connect($this->config);
133
134
    $this->auditColumnTypes();
135
136
    $this->listOfTables();
137
138
    $this->unknownTables();
139
140
    foreach ($this->dataSchemaTables as $table)
141
    {
142
      if ($this->config['tables'][$table['table_name']]['audit'])
143
      {
144
        $tableColumns = [];
145
        if (isset($this->config['table_columns'][$table['table_name']]))
146
        {
147
          $tableColumns = $this->config['table_columns'][$table['table_name']];
148
        }
149
        $currentTable = new Table($this->io,
150
                                  $table['table_name'],
151
                                  $this->config['database']['data_schema'],
152
                                  $this->config['database']['audit_schema'],
153
                                  $tableColumns,
154
                                  $this->config['audit_columns'],
155
                                  $this->config['tables'][$table['table_name']]['alias'],
156
                                  $this->config['tables'][$table['table_name']]['skip']);
157
        $res          = StaticDataLayer::searchInRowSet('table_name', $currentTable->getTableName(), $this->auditSchemaTables);
158
        if (!isset($res))
159
        {
160
          $currentTable->createMissingAuditTable();
161
        }
162
163
        $columns        = $currentTable->main($this->config['additional_sql']);
164
        $alteredColumns = $columns['altered_columns']->getColumns();
165
        if (empty($alteredColumns))
166
        {
167
          $this->getColumns($currentTable->getTableName(), $columns['full_columns']);
168
        }
169
      }
170
    }
171
172
    // Drop database connection
173
    DataLayer::disconnect();
174
175
    $this->rewriteConfig();
176
  }
177
178
  //--------------------------------------------------------------------------------------------------------------------
179
  /**
180
   * Get canonical column types for audit columns.
181
   */
182
  protected function auditColumnTypes()
183
  {
184
    $schema    = $this->config['database']['audit_schema'];
185
    $tableName = 'TMP_'.uniqid();
186
    DataLayer::createTemporaryTable($schema, $tableName, $this->config['audit_columns']);
187
    $auditColumns = DataLayer::showColumns($schema, $tableName);
188
    foreach ($auditColumns as $column)
189
    {
190
      $key = StaticDataLayer::searchInRowSet('column_name', $column['Field'], $this->config['audit_columns']);
191
      if (isset($key))
192
      {
193
        $this->config['audit_columns'][$key]['column_type'] = $column['Type'];
194
        if ($column['Null']==='NO')
195
        {
196
          $this->config['audit_columns'][$key]['column_type'] = sprintf('%s not null', $this->config['audit_columns'][$key]['column_type']);
197
        }
198
      }
199
    }
200
    DataLayer::dropTemporaryTable($schema, $tableName);
201
  }
202
203
  //--------------------------------------------------------------------------------------------------------------------
204
  /**
205
   * Write new data to config file.
206
   */
207
  private function rewriteConfig()
208
  {
209
    $this->writeTwoPhases($this->configFileName, json_encode($this->config, JSON_PRETTY_PRINT));
210
  }
211
212
  //--------------------------------------------------------------------------------------------------------------------
213
}
214
215
//----------------------------------------------------------------------------------------------------------------------
216