EqualValueComparator::isScalarEqual()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

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