Completed
Push — master ( 08e0f6...9db3f2 )
by P.R.
15:16
created

BaseCommand::rewriteConfig()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 7.2349

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 13
ccs 2
cts 9
cp 0.2222
rs 9.4285
cc 3
eloc 6
nc 3
nop 0
crap 7.2349
1
<?php
2
//----------------------------------------------------------------------------------------------------------------------
3
namespace SetBased\Audit\Command;
4
5
use SetBased\Exception\RuntimeException;
6
use SetBased\Stratum\Style\StratumStyle;
7
use Symfony\Component\Console\Command\Command;
8
use Symfony\Component\Console\Formatter\OutputFormatter;
9
10
//----------------------------------------------------------------------------------------------------------------------
11
/**
12
 * Base command for other commands of AuditApplication.
13
 */
14
class BaseCommand extends Command
15
{
16
  //--------------------------------------------------------------------------------------------------------------------
17
  /**
18
   * All config file as array.
19
   *
20
   * @var array
21
   */
22
  protected $config = [];
23
24
  /**
25
   * The name of the configuration file.
26
   *
27
   * @var string
28
   */
29
  protected $configFileName = '';
30
31
  /**
32
   * Table metadata from config file.
33
   *
34
   * @var array
35
   */
36
  protected $configMetadata = [];
37
38
  /**
39
   * The Output decorator.
40
   *
41
   * @var StratumStyle
42
   */
43
  protected $io;
44
45
  /**
46
   * If set (the default) the config file must be rewritten. Set to false for testing only.
47
   *
48
   * @var bool
49
   */
50
  protected $rewriteConfigFile = true;
51
52
  //--------------------------------------------------------------------------------------------------------------------
53
  /**
54
   * Returns the value of a setting.
55
   *
56
   * @param array  $settings    The settings as returned by parse_ini_file.
57
   * @param bool   $mandatory   If set and setting $settingName is not found in section $sectionName an exception
58
   *                            will be thrown.
59
   * @param string $sectionName The name of the section of the requested setting.
60
   * @param string $settingName The name of the setting of the requested setting.
61
   *
62
   * @return null|string
63
   *
64
   * @throws RuntimeException
65
   */
66 13
  protected static function getSetting($settings, $mandatory, $sectionName, $settingName)
67
  {
68
    // Test if the section exists.
69 13 View Code Duplication
    if (!array_key_exists($sectionName, $settings))
70 13
    {
71
      if ($mandatory)
72
      {
73
        throw new RuntimeException("Section '%s' not found in configuration file.", $sectionName);
74
      }
75
      else
76
      {
77
        return null;
78
      }
79
    }
80
81
    // Test if the setting in the section exists.
82 13 View Code Duplication
    if (!array_key_exists($settingName, $settings[$sectionName]))
83 13
    {
84
      if ($mandatory)
85
      {
86
        throw new RuntimeException("Setting '%s' not found in section '%s' configuration file.",
87
                                   $settingName,
88
                                   $sectionName);
89
      }
90
      else
91
      {
92
        return null;
93
      }
94
    }
95
96 13
    return $settings[$sectionName][$settingName];
97
  }
98
99
  //--------------------------------------------------------------------------------------------------------------------
100
  /**
101
   * Reads configuration parameters from the configuration file.
102
   */
103 13
  public function readConfigFile()
104
  {
105 13
    $content = file_get_contents($this->configFileName);
106
107 13
    $this->config = (array)json_decode($content, true);
108 13
    if (json_last_error()!=JSON_ERROR_NONE)
109 13
    {
110
      throw new RuntimeException("Error decoding JSON: '%s'.", json_last_error_msg());
111
    }
112
113 13
    if (!isset($this->config['audit_columns']))
114 13
    {
115 1
      $this->config['audit_columns'] = [];
116 1
    }
117
118 13
    if (!isset($this->config['additional_sql']))
119 13
    {
120 2
      $this->config['additional_sql'] = [];
121 2
    }
122
123 13
    if (!isset($this->config['tables']))
124 13
    {
125 1
      $this->config['tables'] = [];
126 1
    }
127
128 13
    foreach ($this->config['tables'] as $table_name => $params)
129
    {
130 12
      $this->config['tables'][$table_name]['audit'] = filter_var($params['audit'], FILTER_VALIDATE_BOOLEAN);
131 13
    }
132
133 13
    $this->readMetadata();
134 13
  }
135
136
  //--------------------------------------------------------------------------------------------------------------------
137
  /**
138
   * Use for testing only.
139
   *
140
   * @param bool $rewriteConfigFile If true the config file must be rewritten. Otherwise the config must not be
141
   *                                rewritten.
142
   */
143 13
  public function setRewriteConfigFile($rewriteConfigFile)
144
  {
145 13
    $this->rewriteConfigFile = $rewriteConfigFile;
146 13
  }
147
148
  //--------------------------------------------------------------------------------------------------------------------
149
  /**
150
   * Rewrites the config file with updated data.
151
   */
152 13
  protected function rewriteConfig()
153
  {
154
    // Return immediately when the config file must not be rewritten.
155 13
    if (!$this->rewriteConfigFile) return;
156
157
    $this->writeTwoPhases($this->configFileName, json_encode($this->config, JSON_PRETTY_PRINT));
158
159
    $filename = $this->getTableMetadataPath();
160
    if ($filename!==null)
161
    {
162
      $this->writeTwoPhases($filename, json_encode($this->configMetadata, JSON_PRETTY_PRINT));
163
    }
164
  }
165
166
  //--------------------------------------------------------------------------------------------------------------------
167
  /**
168
   * Writes a file in two phase to the filesystem.
169
   *
170
   * First write the data to a temporary file (in the same directory) and than renames the temporary file. If the file
171
   * already exists and its content is equal to the data that must be written no action  is taken. This has the
172
   * following advantages:
173
   * * In case of some write error (e.g. disk full) the original file is kept in tact and no file with partially data
174
   * is written.
175
   * * Renaming a file is atomic. So, running processes will never read a partially written data.
176
   *
177
   * @param string $filename The name of the file were the data must be stored.
178
   * @param string $data     The data that must be written.
179
   */
180
  protected function writeTwoPhases($filename, $data)
181
  {
182
    $write_flag = true;
183
    if (file_exists($filename))
184
    {
185
      $old_data = file_get_contents($filename);
186
      if ($data==$old_data) $write_flag = false;
187
    }
188
189
    if ($write_flag)
190
    {
191
      $tmp_filename = $filename.'.tmp';
192
      file_put_contents($tmp_filename, $data);
193
      rename($tmp_filename, $filename);
194
195
      $this->io->text(sprintf('Wrote <fso>%s</fso>', OutputFormatter::escape($filename)));
196
    }
197
    else
198
    {
199
      $this->io->text(sprintf('File <fso>%s</fso> is up to date', OutputFormatter::escape($filename)));
200
    }
201
  }
202
203
  //--------------------------------------------------------------------------------------------------------------------
204
  /**
205
   * Returns the path of the table metadata file.
206
   *
207
   * @return string|null
208
   */
209 13
  private function getTableMetadataPath()
210
  {
211 13
    if (isset($this->config['metadata']))
212 13
    {
213 13
      return dirname($this->configFileName).'/'.$this->config['metadata'];
214
    }
215
216
    return null;
217
  }
218
219
  //--------------------------------------------------------------------------------------------------------------------
220
  /**
221
   * Reads table metadata from the table metadata config file (if any).
222
   */
223 13
  private function readMetadata()
224
  {
225 13
    $filename = $this->getTableMetadataPath();
226 13
    if ($filename!==null)
227 13
    {
228 13
      if (file_exists($filename))
229 13
      {
230 13
        $content = file_get_contents($filename);
231
232 13
        $this->configMetadata = (array)json_decode($content, true);
233 13
        if (json_last_error()!=JSON_ERROR_NONE)
234 13
        {
235
          throw new RuntimeException("Error decoding JSON: '%s'.", json_last_error_msg());
236
        }
237 13
      }
238 13
    }
239 13
  }
240
241
  //--------------------------------------------------------------------------------------------------------------------
242
}
243
244
//----------------------------------------------------------------------------------------------------------------------
245