Issues (13)

src/Services/XmlDifferenceService.php (1 issue)

1
<?php
2
3
namespace Horat1us\Services;
4
5
use Horat1us\Services\Traits\PropertiesDifferenceTrait;
6
use Horat1us\XmlConvertibleInterface;
7
use Horat1us\XmlConvertibleObject;
8
9
/**
10
 * Class XmlDifferenceService
11
 * @package Horat1us\Services
12
 */
13
class XmlDifferenceService
14
{
15
    use PropertiesDifferenceTrait;
16
17
    /**
18
     * @var XmlConvertibleInterface
19
     */
20
    protected $source;
21
22
    /**
23
     * @var XmlConvertibleInterface
24
     */
25
    protected $target;
26
27
28
    /**
29
     * XmlDifferenceService constructor.
30
     * @param XmlConvertibleInterface $source
31
     * @param XmlConvertibleInterface $target
32
     */
33
    public function __construct(
34
        XmlConvertibleInterface $source,
35
        XmlConvertibleInterface $target
36
    ) {
37
        $this
38
            ->setSource($source)
39
            ->setTarget($target);
40
    }
41 4
42
    /**
43
     * @return XmlConvertibleInterface|null
44
     */
45
    public function difference()
46
    {
47 4
        if ($this->source->xmlEqual($this->target)) {
48 4
            return null;
49 4
        }
50
51
        if ($this->getIsCommonDifferent()) {
52
            return clone $this->getSource();
53
        }
54 4
55
        $newChildren = $this->getDifferentChildren();
56 4
        if (empty($newChildren)) {
57 4
            return null;
58
        }
59
60 2
        $target = clone $this->getSource();
61 2
        $target->setXmlChildren($newChildren);
62 2
63
        return clone $target;
64
    }
65 2
66 2
    /**
67
     * Difference by element name, children count and properties
68 2
     */
69
    public function getIsCommonDifferent()
70
    {
71
        return $this->getSource()->getXmlElementName() !== $this->getTarget()->getXmlElementName()
72
            || empty($this->getSource()->getXmlChildren()) && !empty($this->getTarget()->getXmlChildren())
73
            || $this->getIsDifferentProperties();
74 4
    }
75
76 4
    /**
77 4
     * @return array
78 4
     */
79
    public function getDifferentChildren()
80
    {
81
        $sourceChildren = array_map(
82
            fn($child) => $this->transform($child),
83
            $this->getSource()->getXmlChildren() ?? []
84 2
        );
85
        $targetChildren = array_map(
86 2
            fn($child) => $this->transform($child),
87
            $this->getTarget()->getXmlChildren() ?? []
88 2
        );
89 2
        $sourceChildren = array_filter(
90
            $sourceChildren,
91 2
            function (XmlConvertibleInterface $sourceChild) use ($targetChildren): bool {
92 2
                foreach ($targetChildren as $targetChild) {
93 2
                    if ($targetChild->xmlEqual($sourceChild)) {
94 2
                        return false;
95 2
                    }
96 2
                }
97
                return true;
98
            }
99
        );
100
        $diffChildren = array_map(
101
            fn(XmlConvertibleInterface $child) => $this->findDifference($child),
102
            $sourceChildren
103 2
        );
104
        return array_filter($diffChildren);
105 2
    }
106 2
107 2
    /**
108
     * @param XmlConvertibleInterface|\DOMNode|\DOMDocument $object
109
     * @return XmlConvertibleInterface
110
     */
111
    protected function transform($object)
112
    {
113
        return $object instanceof XmlConvertibleInterface
114 2
            ? $object
115
            : XmlConvertibleObject::fromXml($object);
116
    }
117
118 2
    /**
119 2
     * @param XmlConvertibleInterface $child
120
     * @return XmlConvertibleInterface|null
121 2
     */
122 2
    protected function findDifference(
123
        XmlConvertibleInterface $child
124
    ) {
125
        foreach ($this->getTarget()->getXmlChildren() ?? [] as $comparedChild) {
126 2
            $target = $this->transform($comparedChild);
127
128
            if ($difference = $child->xmlDiff($target)) {
129
                return $difference;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $difference also could return the type Horat1us\XmlConvertible which is incompatible with the documented return type Horat1us\XmlConvertibleInterface|null.
Loading history...
130
            }
131
        }
132 4
133
        return null;
134 4
    }
135
136
    /**
137
     * @return XmlConvertibleInterface
138
     */
139
    public function getSource(): XmlConvertibleInterface
140
    {
141 4
        return $this->source;
142
    }
143 4
144
    /**
145 4
     * @param XmlConvertibleInterface $source
146
     * @return $this
147
     */
148
    public function setSource(XmlConvertibleInterface $source)
149
    {
150
        $this->source = $source;
151 4
152
        return $this;
153 4
    }
154
155
    /**
156
     * @return XmlConvertibleInterface
157
     */
158
    public function getTarget(): XmlConvertibleInterface
159
    {
160 4
        return $this->target;
161
    }
162 4
163
    /**
164 4
     * @param XmlConvertibleInterface $target
165
     * @return $this
166
     */
167
    public function setTarget(XmlConvertibleInterface $target)
168
    {
169
        $this->target = $target;
170
171
        return $this;
172
    }
173
}
174