Passed
Push — master ( 9e86dc...6cbe7e )
by P.R.
06:56
created

BaseCommand::readConfigFile()   A

Complexity

Conditions 5
Paths 9

Size

Total Lines 20
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 5

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 10
c 1
b 0
f 0
nc 9
nop 0
dl 0
loc 20
ccs 11
cts 11
cp 1
crap 5
rs 9.6111
1
<?php
2
declare(strict_types=1);
3
4
namespace SetBased\Audit\Command;
5
6
use Noodlehaus\Config;
7
use SetBased\Audit\MySql\AuditDataLayer;
8
use SetBased\Audit\Style\AuditStyle;
9
use SetBased\Config\TypedConfig;
10
use SetBased\Stratum\MySql\MySqlDefaultConnector;
11
use Symfony\Component\Console\Command\Command;
12
use Symfony\Component\Console\Formatter\OutputFormatter;
13
14
/**
15
 * Base command for other commands of AuditApplication.
16
 */
17
class BaseCommand extends Command
18
{
19
  //--------------------------------------------------------------------------------------------------------------------
20
  /**
21
   * The sections in the configurations file.
22
   *
23
   * @var array
24
   */
25
  private static $sections = ['database', 'audit_columns', 'additional_sql', 'tables'];
26
27
  /**
28
   * The strong typed configuration reader and writer.
29
   *
30
   * @var TypedConfig
31
   */
32
  protected $config;
33
34
  /**
35
   * The name of the configuration file.
36
   *
37
   * @var string
38
   */
39
  protected $configFileName = '';
40
41
  /**
42
   * The Output decorator.
43
   *
44
   * @var AuditStyle
45
   */
46
  protected $io;
47
48
  /**
49
   * If set (the default) the config file must be rewritten. Set to false for testing only.
50
   *
51
   * @var bool
52
   */
53
  protected $rewriteConfigFile = true;
54
55
  //--------------------------------------------------------------------------------------------------------------------
56
  /**
57
   * Reads configuration parameters from the configuration file.
58
   */
59 30
  public function readConfigFile(): void
60
  {
61 30
    $this->config = new TypedConfig(new Config($this->configFileName));
62 30
    $config       = $this->config->getConfig();
63
64 30
    foreach (self::$sections as $key)
65
    {
66 30
      if (!isset($config[$key]))
67
      {
68 12
        $config[$key] = [];
69
      }
70
    }
71
72 30
    $credentials = $this->config->getOptString('database.credentials');
73 30
    if ($credentials!==null)
74
    {
75 3
      $tmp = new TypedConfig(new Config(dirname($this->configFileName).'/'.$credentials));
76 3
      foreach ($tmp->getManArray('database') as $key => $value)
77
      {
78 3
        $config->set('database.'.$key, $value);
79
      }
80
    }
81 30
  }
82
83
  //--------------------------------------------------------------------------------------------------------------------
84
  /**
85
   * Use for testing only.
86
   *
87
   * @param bool $rewriteConfigFile If true the config file must be rewritten. Otherwise the config must not be
88
   *                                rewritten.
89
   */
90 30
  public function setRewriteConfigFile(bool $rewriteConfigFile)
91
  {
92 30
    $this->rewriteConfigFile = $rewriteConfigFile;
93 30
  }
94
95
  //--------------------------------------------------------------------------------------------------------------------
96
  /**
97
   * Connects to a MySQL instance.
98
   */
99 30
  protected function connect(): void
100
  {
101 30
    $connector = new MySqlDefaultConnector($this->config->getManString('database.host'),
102 30
                                           $this->config->getManString('database.user'),
103 30
                                           $this->config->getManString('database.password'),
104 30
                                           $this->config->getManString('database.data_schema'),
105 30
                                           $this->config->getManInt('database.port', 3306));
106 30
    $dl = new AuditDataLayer($connector, $this->io);
107 30
    $dl->connect();
108 30
  }
109
110
  //--------------------------------------------------------------------------------------------------------------------
111
  /**
112
   * Rewrites the config file with updated data.
113
   */
114 30
  protected function rewriteConfig(): void
115
  {
116
    // Return immediately when the config file must not be rewritten.
117 30
    if (!$this->rewriteConfigFile) return;
118
119 12
    $tables = $this->config->getManArray('tables');
120 12
    ksort($tables);
121
122 12
    $config           = new Config($this->configFileName);
123 12
    $config['tables'] = $tables;
124
125 12
    $data = [];
126 12
    foreach (self::$sections as $key)
127
    {
128 12
      if (!empty($config->get($key)))
129
      {
130 12
        $data[$key] = $config->get($key);
131
      }
132
    }
133
134 12
    $this->writeTwoPhases($this->configFileName, json_encode($data, JSON_PRETTY_PRINT));
135 12
  }
136
137
  //--------------------------------------------------------------------------------------------------------------------
138
  /**
139
   * Writes a file in two phase to the filesystem.
140
   *
141
   * First write the data to a temporary file (in the same directory) and than renames the temporary file. If the file
142
   * already exists and its content is equal to the data that must be written no action  is taken. This has the
143
   * following advantages:
144
   * * In case of some write error (e.g. disk full) the original file is kept in tact and no file with partially data
145
   * is written.
146
   * * Renaming a file is atomic. So, running processes will never read a partially written data.
147
   *
148
   * @param string $filename The name of the file were the data must be stored.
149
   * @param string $data     The data that must be written.
150
   */
151 12
  protected function writeTwoPhases(string $filename, string $data): void
152
  {
153 12
    $write_flag = true;
154 12
    if (file_exists($filename))
155
    {
156 12
      $old_data = file_get_contents($filename);
157 12
      if ($data==$old_data) $write_flag = false;
158
    }
159
160 12
    if ($write_flag)
161
    {
162 11
      $tmp_filename = $filename.'.tmp';
163 11
      file_put_contents($tmp_filename, $data);
164 11
      rename($tmp_filename, $filename);
165
166 11
      $this->io->text(sprintf('Wrote <fso>%s</fso>', OutputFormatter::escape($filename)));
167
    }
168
    else
169
    {
170 10
      $this->io->text(sprintf('File <fso>%s</fso> is up to date', OutputFormatter::escape($filename)));
171
    }
172 12
  }
173
174
  //--------------------------------------------------------------------------------------------------------------------
175
}
176
177
//----------------------------------------------------------------------------------------------------------------------
178