Passed
Pull Request — master (#20)
by Aleksei
03:14
created

FieldComparator::compareProperties()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

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