Passed
Push — master ( 99d80c...db9e79 )
by Edward
02:29
created

EqualValueComparator   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 94
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 45
c 1
b 0
f 1
dl 0
loc 94
rs 10
wmc 24

6 Methods

Rating   Name   Duplication   Size   Complexity  
A isArrayEqual() 0 17 4
A __construct() 0 3 1
A isObjectEqual() 0 21 6
A isScalarEqual() 0 10 3
A getPropertiesWithoutDuplicates() 0 13 3
B compare() 0 15 7
1
<?php
2
declare(strict_types=1);
3
4
namespace Remorhaz\JSON\Data\Comparator;
5
6
use Collator;
7
use Iterator;
8
use function is_string;
9
use Remorhaz\JSON\Data\Value\ArrayValueInterface;
10
use Remorhaz\JSON\Data\Value\ObjectValueInterface;
11
use Remorhaz\JSON\Data\Value\ScalarValueInterface;
12
use Remorhaz\JSON\Data\Value\ValueInterface;
13
14
final class EqualValueComparator implements ComparatorInterface
15
{
16
17
    private $collator;
18
19
    public function __construct(Collator $collator)
20
    {
21
        $this->collator = $collator;
22
    }
23
24
    public function compare(ValueInterface $leftValue, ValueInterface $rightValue): bool
25
    {
26
        if ($leftValue instanceof ScalarValueInterface && $rightValue instanceof ScalarValueInterface) {
27
            return $this->isScalarEqual($leftValue, $rightValue);
28
        }
29
30
        if ($leftValue instanceof ArrayValueInterface && $rightValue instanceof ArrayValueInterface) {
31
            return $this->isArrayEqual($leftValue, $rightValue);
32
        }
33
34
        if ($leftValue instanceof ObjectValueInterface && $rightValue instanceof ObjectValueInterface) {
35
            return $this->isObjectEqual($leftValue, $rightValue);
36
        }
37
38
        return false;
39
    }
40
41
    private function isScalarEqual(ScalarValueInterface $leftValue, ScalarValueInterface $rightValue): bool
42
    {
43
        $leftData = $leftValue->getData();
44
        $rightData = $rightValue->getData();
45
46
        if (is_string($leftData) && is_string($rightData)) {
47
            return 0 === $this->collator->compare($leftData, $rightData);
48
        }
49
50
        return $leftData === $rightData;
51
    }
52
53
    private function isArrayEqual(ArrayValueInterface $leftValue, ArrayValueInterface $rightValue): bool
54
    {
55
        $leftValueIterator = $leftValue->createChildIterator();
56
        $rightValueIterator = $rightValue->createChildIterator();
57
58
        while ($leftValueIterator->valid()) {
59
            if (!$rightValueIterator->valid()) {
60
                return false;
61
            }
62
            if (!$this->compare($leftValueIterator->current(), $rightValueIterator->current())) {
63
                return false;
64
            }
65
            $leftValueIterator->next();
66
            $rightValueIterator->next();
67
        }
68
69
        return !$rightValueIterator->valid();
70
    }
71
72
    private function isObjectEqual(ObjectValueInterface $leftValue, ObjectValueInterface $rightValue): bool
73
    {
74
        $leftProperties = $this->getPropertiesWithoutDuplicates($leftValue->createChildIterator());
75
        if (!isset($leftProperties)) {
76
            return false;
77
        }
78
        $rightProperties = $this->getPropertiesWithoutDuplicates($rightValue->createChildIterator());
79
        if (!isset($rightProperties)) {
80
            return false;
81
        }
82
        foreach ($rightProperties as $property => $rightValue) {
83
            if (!isset($leftProperties[$property])) {
84
                return false;
85
            }
86
            if (!$this->compare($leftProperties[$property], $rightValue)) {
87
                return false;
88
            }
89
            unset($leftProperties[$property]);
90
        }
91
92
        return empty($leftProperties);
93
    }
94
95
    private function getPropertiesWithoutDuplicates(Iterator $valueIterator): ?array
96
    {
97
        $valuesByProperty = [];
98
        while ($valueIterator->valid()) {
99
            $property = $valueIterator->key();
100
            if (isset($valuesByProperty[$property])) {
101
                return null;
102
            }
103
            $valuesByProperty[$property] = $valueIterator->current();
104
            $valueIterator->next();
105
        }
106
107
        return $valuesByProperty;
108
    }
109
}
110