FieldComparator   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 89
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 43
dl 0
loc 89
ccs 44
cts 44
cp 1
rs 10
c 1
b 0
f 0
wmc 18

5 Methods

Rating   Name   Duplication   Size   Complexity  
A compare() 0 10 4
A generateErrorText() 0 13 4
A compareProperties() 0 17 3
A compareOptions() 0 22 4
A addField() 0 10 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cycle\Schema\Definition\Comparator;
6
7
use Cycle\Schema\Definition\Field;
8
9
final class FieldComparator
10
{
11
    private $columnName;
12
13
    /** @var Field[] */
14
    private $fields = [];
15
16
    public function addField(string $key, Field $field): self
17 14
    {
18
        if ($this->columnName === null) {
19 14
            $this->columnName = $field->getColumn();
20 14
        }
21
        if ($this->columnName !== $field->getColumn()) {
22 14
            throw new \InvalidArgumentException('The field comparator only accepts fields with the same column name.');
23 2
        }
24
        $this->fields[$key] = $field;
25 14
        return $this;
26 14
    }
27
28
    public function compare(): void
29 14
    {
30
        if (count($this->fields) <= 1) {
31 14
            return;
32 2
        }
33
        // Check options
34
        if (!$this->compareOptions() || !$this->compareProperties()) {
35 12
            throw new \Exception(
36 6
                "Different definitions are specified for the `$this->columnName` column:"
37 6
                . "\n\n{$this->generateErrorText()}",
38 6
            );
39
        }
40
    }
41 6
42
    private function generateErrorText(): string
43 6
    {
44
        $lines = [];
45 6
        foreach ($this->fields as $key => $field) {
46 6
            $primary = $field->isPrimary() ? ' primary' : '';
47 6
            $line = sprintf("%s:\n  type=%s%s", $key, $field->getType(), $primary);
48 6
            // Print options
49
            foreach ($field->getOptions() as $optionName => $optionValue) {
50 6
                $line .= " {$optionName}=" . var_export($optionValue, true);
51 6
            }
52
            $lines[] = $line;
53 6
        }
54
        return implode("\n\n", $lines);
55 6
    }
56
57
    private function compareProperties(): bool
58 8
    {
59
        $tuples = array_map(static function (Field $field): array {
60 8
            return [
61
                $field->getType(),
62 4
                // $field->isPrimary(), // should not compared
63
            ];
64
        }, $this->fields);
65 8
66
        // Compare options content
67
        $prototype = array_shift($tuples);
68 8
        foreach ($tuples as $tuple) {
69 8
            if (count(array_diff_assoc($prototype, $tuple)) > 0) {
70 8
                return false;
71 2
            }
72
        }
73
        return true;
74 6
    }
75
76
    private function compareOptions(): bool
77 12
    {
78
        // Collect fields options
79
        $optionsSet = array_map(static function (Field $field): array {
80 12
            return iterator_to_array($field->getOptions());
81 6
        }, $this->fields);
82 12
83
        // Compare options cont
84
        $countResult = array_count_values(array_map('count', $optionsSet));
85 12
        if (count($countResult) !== 1) {
86 12
            return false;
87 2
        }
88
89
        // Compare options content
90
        $prototype = array_shift($optionsSet);
91 10
        foreach ($optionsSet as $options) {
92 10
            if (count(array_diff_assoc($prototype, $options)) > 0) {
93 10
                return false;
94 2
            }
95
        }
96
97
        return true;
98 8
    }
99
}
100