EqualsBuilder   A
last analyzed

Complexity

Total Complexity 21

Size/Duplication

Total Lines 110
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 0
Metric Value
wmc 21
lcom 1
cbo 0
dl 0
loc 110
rs 10
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A create() 0 4 1
A append() 0 16 4
A checkForSameType() 0 10 2
A checkIfValuesAreAnObjectAndEqual() 0 20 4
A checkIfValuesAreAnObject() 0 4 2
A compareObjectProperties() 0 12 1
A checkValuesRecursively() 0 14 2
A getPropertiesAsAnArray() 0 13 4
A isEquals() 0 4 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Selami\Stdlib;
6
7
use ReflectionClass;
8
9
use function is_object;
10
11
/**
12
 * This class provides methods to build a equals method for any class. Intended to be use to compare Value Objects.
13
 */
14
15
final class EqualsBuilder
16
{
17
    private $isEquals = true;
18
19
    public static function create(): EqualsBuilder
20
    {
21
        return new static();
22
    }
23
24
    public function append($leftHandedValue, $rightHandedValue)
25
    {
26
        if ($this->isEquals === false) {
27
            return $this;
28
        }
29
30
        if ($this->checkIfValuesAreAnObjectAndEqual($leftHandedValue, $rightHandedValue)) {
31
            return $this;
32
        }
33
34
        if ($this->checkForSameType($leftHandedValue, $rightHandedValue)) {
35
            return $this;
36
        }
37
38
        return $this;
39
    }
40
41
    private function checkForSameType($leftHandedValue, $rightHandedValue): bool
42
    {
43
        if ($leftHandedValue !== $rightHandedValue) {
44
            $this->isEquals = false;
45
46
            return false;
47
        }
48
49
        return true;
50
    }
51
52
    private function checkIfValuesAreAnObjectAndEqual($leftHandedValue, $rightHandedValue): bool
53
    {
54
        if (! $this->checkIfValuesAreAnObject($leftHandedValue, $rightHandedValue)) {
55
            return false;
56
        }
57
58
        if (get_class($leftHandedValue) !== get_class($rightHandedValue)) {
59
            $this->isEquals = false;
60
61
            return false;
62
        }
63
64
        if (! $this->compareObjectProperties($leftHandedValue, $rightHandedValue)) {
65
            $this->isEquals = false;
66
67
            return false;
68
        }
69
70
        return true;
71
    }
72
73
    private function checkIfValuesAreAnObject($leftHandedValue, $rightHandedValue): bool
74
    {
75
        return is_object($leftHandedValue) && is_object($rightHandedValue);
76
    }
77
78
    private function compareObjectProperties($leftHandedObject, $rightHandedObject): bool
79
    {
80
        $reflectionOfLeftHandedObject  = new ReflectionClass($leftHandedObject);
81
        $propertiesOfLeftHandedObject  = $this->getPropertiesAsAnArray($leftHandedObject, $reflectionOfLeftHandedObject);
82
        $reflectionOfRightHandedObject = new ReflectionClass($rightHandedObject);
83
        $propertiesOfRightHandedObject = $this->getPropertiesAsAnArray(
84
            $rightHandedObject,
85
            $reflectionOfRightHandedObject
86
        );
87
88
        return $this->checkValuesRecursively($propertiesOfRightHandedObject, $propertiesOfLeftHandedObject);
89
    }
90
91
    private function checkValuesRecursively(
92
        array $propertiesOfLeftHandedObject,
93
        array $propertiesOfRightHandedObject
94
    ): bool {
95
        $innerEqualsBuilder = self::create();
96
        foreach ($propertiesOfLeftHandedObject as $propertyName => $propertyValue) {
97
            $innerEqualsBuilder = $innerEqualsBuilder->append(
98
                $propertyValue,
99
                $propertiesOfRightHandedObject[$propertyName]
100
            );
101
        }
102
103
        return $innerEqualsBuilder->isEquals();
104
    }
105
106
    private function getPropertiesAsAnArray($sourceObject, $object): array
107
    {
108
        $propertyList = [];
109
        foreach ($object->getProperties() as $property) {
110
            if ($property->isProtected() || $property->isPrivate()) {
111
                $property->setAccessible(true);
112
            }
113
114
            $propertyList[$property->name] = $property->getValue($sourceObject);
115
        }
116
117
        return $propertyList;
118
    }
119
120
    public function isEquals(): bool
121
    {
122
        return $this->isEquals;
123
    }
124
}
125