DiffTable::getRows()   B
last analyzed

Complexity

Conditions 8
Paths 10

Size

Total Lines 28
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 8

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
eloc 12
c 1
b 0
f 0
nc 10
nop 1
dl 0
loc 28
ccs 12
cts 12
cp 1
crap 8
rs 8.4444
1
<?php
2
declare(strict_types=1);
3
4
namespace SetBased\Audit;
5
6
use SetBased\Audit\Metadata\TableMetadata;
7
use SetBased\Audit\Style\AuditStyle;
8
use SetBased\Exception\FallenException;
9
use Symfony\Component\Console\Helper\Table;
10
use Symfony\Component\Console\Helper\TableSeparator;
11
12
/**
13
 * Class for printing the differences between audit and data tables.
14
 */
15
class DiffTable
16
{
17
  //--------------------------------------------------------------------------------------------------------------------
18
  /**
19
   * The audit table.
20
   *
21
   * @var TableMetadata
22
   */
23
  private TableMetadata $auditTable;
24
25
  /**
26
   * The data table.
27
   *
28
   * @var TableMetadata
29
   */
30
  private TableMetadata $dataTable;
31
32
  /**
33
   * The join column names of the audit and data table.
34
   *
35
   * @var array[]
36
   */
37
  private array $rows = [];
38
39
  //--------------------------------------------------------------------------------------------------------------------
40
  /**
41
   * Object constructor.
42
   *
43
   * @param TableMetadata $dataTable  The data table.
44
   * @param TableMetadata $auditTable The audit table.
45
   */
46 6
  public function __construct(TableMetadata $dataTable, TableMetadata $auditTable)
47
  {
48 6
    $this->dataTable  = $dataTable;
49 6
    $this->auditTable = $auditTable;
50 6
  }
51
52
  //--------------------------------------------------------------------------------------------------------------------
53
  /**
54
   * @param AuditStyle $io   The IO object.
55
   * @param bool       $full If false and only if only differences are shown.
56
   */
57 6
  public function print(AuditStyle $io, bool $full): void
58
  {
59 6
    $this->rowsEnhanceWithTableColumns();
60 6
    $this->rowsEnhanceWithTableOptions();
61 6
    $this->rowsEnhanceWithDiffIndicator();
62 6
    $this->rowsEnhanceWithColumnTypeInfo();
63 6
    $this->rowsEnhanceWithFormatting();
64
65 6
    if ($full || $this->hasDifferences())
66
    {
67 5
      $io->writeln('<dbo>'.$this->dataTable->getTableName().'</dbo>');
68
69 5
      $table = new Table($io);
70 5
      $table->setHeaders(['column', 'audit table', 'config / data table'])
71 5
            ->setRows($this->getRows($full));
72 5
      $table->render();
73
74 5
      $io->writeln('');
75
    }
76 6
  }
77
78
  //--------------------------------------------------------------------------------------------------------------------
79
  /**
80
   * Returns the rows suitable for Symfony's table.
81
   *
82
   * @param bool $full If false and only if only differences are shown.
83
   *
84
   * @return array
85
   */
86 5
  private function getRows(bool $full): array
87
  {
88 5
    $ret     = [];
89 5
    $options = false;
90 5
    foreach ($this->rows as $row)
91
    {
92
      // Add separator between columns and options.
93 5
      if ($options===false && $row['type']==='option')
94
      {
95 5
        if (!empty($ret))
96 5
        {
97
          $ret[] = new TableSeparator();
98
        }
99 5
        $options = true;
100
      }
101 5
102
      if ($full || $row['diff'])
103 5
      {
104
        $ret[] = [$row['name'], $row['audit1'], $row['data1']];
105 3
106
        if ($row['rowspan']===2)
107
        {
108
          $ret[] = ['', $row['audit2'], $row['data2']];
109
        }
110 5
      }
111
    }
112
113
    return $ret;
114
  }
115
116
  //--------------------------------------------------------------------------------------------------------------------
117
  /**
118
   * Returns true if and only if the audit and data tables have differences.
119 6
   *
120
   * @return bool
121 6
   */
122
  private function hasDifferences(): bool
123 6
  {
124
    foreach ($this->rows as $row)
125
    {
126 2
      if ($row['diff'])
127
      {
128
        return true;
129
      }
130
    }
131
132
    return false;
133 6
  }
134
135 6
  //--------------------------------------------------------------------------------------------------------------------
136
  /**
137 6
   * Enhances rows with column type info.
138
   */
139 6
  private function rowsEnhanceWithColumnTypeInfo(): void
140
  {
141 6
    foreach ($this->rows as &$row)
142 6
    {
143
      if ($row['type']==='column')
144
      {
145
        if ($row['data']!==null)
146 1
        {
147 1
          $row['data1'] = $row['data']->getTypeInfo1();
148
          $row['data2'] = $row['data']->getTypeInfo2();
149
        }
150 6
        else
151
        {
152 6
          $row['data1'] = null;
153 6
          $row['data2'] = null;
154
        }
155
156
        if ($row['audit']!==null)
157 1
        {
158 1
          $row['audit1'] = $row['audit']->getTypeInfo1();
159
          $row['audit2'] = $row['audit']->getTypeInfo2();
160
        }
161 6
        else
162
        {
163
          $row['audit1'] = null;
164 6
          $row['audit2'] = null;
165
        }
166
167
        $row['rowspan'] = ($row['data2']===null && $row['audit2']===null) ? 1 : 2;
168
      }
169
    }
170 6
  }
171
172 6
  //--------------------------------------------------------------------------------------------------------------------
173
  /**
174 6
   * Enhances rows with diff indicator.
175
   */
176 6
  private function rowsEnhanceWithDiffIndicator(): void
177 6
  {
178 6
    foreach ($this->rows as &$row)
179 6
    {
180
      switch ($row['type'])
181 6
      {
182 6
        case 'column':
183 6
          $row['diff'] = (isset($row['audit'])!==isset($row['data']) ||
184
            $row['audit']->getColumnDefinition()!==$row['data']->getColumnDefinition());
185
          break;
186
187
        case 'option':
188
          $row['diff'] = ($row['audit1']!==$row['data1']);
189 6
          break;
190
191
        default:
192
          throw new FallenException('type', $row['type']);
193
      }
194
    }
195 6
  }
196
197 6
  //--------------------------------------------------------------------------------------------------------------------
198
  /**
199 6
   * Enhances rows text with formatting.
200
   */
201 4
  private function rowsEnhanceWithFormatting(): void
202
  {
203
    foreach ($this->rows as &$row)
204 6
    {
205
      if ($row['diff'])
206 3
      {
207 3
        $row['name'] = sprintf('<mm_column>%s</mm_column>', $row['name']);
208
      }
209
210 6
      if ($row['audit1']!==$row['data1'])
211
      {
212 2
        $row['audit1'] = sprintf('<mm_type>%s</mm_type>', $row['audit1']);
213 2
        $row['data1']  = sprintf('<mm_type>%s</mm_type>', $row['data1']);
214
      }
215
216 6
      if ($row['rowspan']===2 && ($row['audit2']!==$row['data2']))
217
      {
218
        $row['audit2'] = sprintf('<mm_type>%s</mm_type>', $row['audit2']);
219
        $row['data2']  = sprintf('<mm_type>%s</mm_type>', $row['data2']);
220
      }
221
    }
222 6
  }
223
224 6
  //--------------------------------------------------------------------------------------------------------------------
225 6
  /**
226
   * Computes the joins columns of the audit and data table.
227 6
   */
228 6
  private function rowsEnhanceWithTableColumns(): void
229
  {
230 6
    $auditColumns = $this->auditTable->getColumns()
231
                                     ->getColumnNames();
232 6
    $dataColumns  = $this->dataTable->getColumns()
233 6
                                    ->getColumnNames();
234 6
235 6
    $this->rows = [];
236
    foreach ($dataColumns as $column)
237
    {
238
      if (in_array($column, $auditColumns))
239
      {
240
        $this->rows[] = ['name'     => $column,
241 1
                         'audit'    => $this->auditTable->getColumns()
242
                                                        ->getColumn($column),
243 1
                         'data'     => $this->dataTable->getColumns()
244 1
                                                       ->getColumn($column),
245
                         'type'     => 'column',
246
                         'new'      => false,
247
                         'obsolete' => false];
248
      }
249
      else
250 6
      {
251
        $this->rows[] = ['name'     => $column,
252 6
                         'audit'    => null,
253
                         'data'     => $this->dataTable->getColumns()
254 1
                                                       ->getColumn($column),
255 1
                         'type'     => 'column',
256
                         'new'      => true,
257 1
                         'obsolete' => false];
258
      }
259
    }
260
261
    foreach ($auditColumns as $column)
262 6
    {
263
      if (!in_array($column, $dataColumns))
264
      {
265
        $this->rows[] = ['name'     => $column,
266
                         'audit'    => $this->auditTable->getColumns()
267
                                                        ->getColumn($column),
268 6
                         'data'     => null,
269
                         'type'     => 'column',
270 6
                         'new'      => false,
271 6
                         'obsolete' => true];
272
      }
273 6
    }
274
  }
275 6
276 6
  //--------------------------------------------------------------------------------------------------------------------
277 6
  /**
278 6
   * Adds table options to the rows.
279 6
   */
280
  private function rowsEnhanceWithTableOptions(): void
281
  {
282 6
    $auditOptions = array_keys($this->auditTable->getOptions());
283
    $dataOptions  = array_keys($this->dataTable->getOptions());
284 6
285
    foreach ($dataOptions as $option)
286
    {
287
      $this->rows[] = ['name'    => $option,
288
                       'audit1'  => $this->auditTable->getProperty($option),
289
                       'data1'   => $this->dataTable->getProperty($option),
290
                       'type'    => 'option',
291
                       'rowspan' => 1];
292
    }
293 6
294
    foreach ($auditOptions as $option)
295
    {
296
      if (!in_array($option, $dataOptions))
297
      {
298
        $this->rows[] = ['name'    => $option,
299
                         'audit1'  => $this->auditTable->getProperty($option),
300
                         'data2'   => null,
301
                         'type'    => 'option',
302
                         'rowspan' => 1];
303
      }
304
    }
305
  }
306
307
  //--------------------------------------------------------------------------------------------------------------------
308
}
309
310
//----------------------------------------------------------------------------------------------------------------------
311