Passed
Push — master ( 8afc73...99d80c )
by Edward
04:17
created

EqualValueComparator::isObjectEqual()   A

Complexity

Conditions 6
Paths 9

Size

Total Lines 26
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

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