Completed
Push — master ( 2ffb4e...c08922 )
by Alexander
02:39
created

XmlDifferenceService::difference()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 16
ccs 9
cts 9
cp 1
rs 9.4285
cc 3
eloc 9
nc 3
nop 0
crap 3
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: horat1us
5
 * Date: 5/11/17
6
 * Time: 6:41 PM
7
 */
8
9
namespace Horat1us\Services;
10
11
use Horat1us\Arrays\Collection;
12
use Horat1us\XmlConvertibleInterface;
13
use Horat1us\XmlConvertibleObject;
14
15
16
/**
17
 * Class XmlDifferenceService
18
 * @package Horat1us\Services
19
 */
20
class XmlDifferenceService
21
{
22
    /**
23
     * @var XmlConvertibleInterface
24
     */
25
    protected $source;
26
27
    /**
28
     * @var XmlConvertibleInterface
29
     */
30
    protected $target;
31
32
33
    /**
34
     * XmlDifferenceService constructor.
35
     * @param XmlConvertibleInterface $source
36
     * @param XmlConvertibleInterface $target
37
     */
38 4
    public function __construct(
39
        XmlConvertibleInterface $source,
40
        XmlConvertibleInterface $target
41
    )
42
    {
43
        $this
44 4
            ->setSource($source)
45 4
            ->setTarget($target);
46 4
    }
47
48
    /**
49
     * @return XmlConvertibleInterface|null
50
     */
51 4
    public function difference()
52
    {
53 4
        if ($this->getIsCommonDifferent()) {
54 4
            return clone $this->getSource();
55
        }
56
57 2
        $newChildren = $this->getDifferentChildren();
58 2
        if (empty($newChildren)) {
59 2
            return null;
60
        }
61
62 2
        $target = clone $this->getSource();
63 2
        $target->setXmlChildren($newChildren);
64
65 2
        return clone $target;
66
    }
67
68
    /**
69
     * Difference by element name, children count and properties
70
     */
71 4
    public function getIsCommonDifferent()
72
    {
73 4
        return $this->getSource()->getXmlElementName() !== $this->getTarget()->getXmlElementName()
74 4
            || empty($this->getSource()->getXmlChildren()) && !empty($this->getTarget()->getXmlChildren())
75 4
            || $this->getIsDifferentProperties();
76
    }
77
78
    /**
79
     * @return array
80
     */
81 2
    public function getDifferentChildren()
82
    {
83 2
        return Collection::from($this->getSource()->getXmlChildren() ?? [])
84
            ->map(function ($child) {
85 2
                return $this->transform($child);
86 2
            })
87
            ->map(function (XmlConvertibleInterface $child) {
88 2
                return $this->findDifference($child);
89 2
            })
90 2
            ->filter(function ($child) {
91 2
                return $child !== null;
92 2
            })
93 2
            ->array;
94
    }
95
96
    /**
97
     * Finding difference in properties
98
     *
99
     * @return bool
100
     */
101 3
    protected function getIsDifferentProperties()
102
    {
103 3
        foreach ($this->getSource()->getXmlProperties() as $property) {
104
            if (
105 3
                !property_exists($this->getTarget(), $property)
106 3
                || $this->getSource()->{$property} !== $this->getTarget()->{$property}
107
            ) {
108 3
                return true;
109
            }
110
        }
111
112 2
        return false;
113
    }
114
115
    /**
116
     * @param XmlConvertibleInterface|\DOMNode|\DOMDocument $object
117
     * @return XmlConvertibleInterface
118
     */
119 2
    protected function transform($object)
120
    {
121 2
        return $object instanceof XmlConvertibleInterface
122 2
            ? $object
123 2
            : XmlConvertibleObject::fromXml($object);
0 ignored issues
show
Documentation introduced by
$object is of type object<DOMNode>, but the function expects a object<DOMDocument>|object<DOMElement>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
124
    }
125
126
    /**
127
     * @param XmlConvertibleInterface $child
128
     * @return XmlConvertibleInterface|null
129
     */
130 2
    protected function findDifference(
131
        XmlConvertibleInterface $child
132
    )
133
    {
134 2
        foreach ($this->getTarget()->getXmlChildren() ?? [] as $comparedChild) {
135 2
            $target = $this->transform($comparedChild);
136
137 2
            if ($difference = $child->xmlDiff($target)) {
138 2
                return $difference;
139
            }
140
        }
141
142 2
        return null;
143
    }
144
145
    /**
146
     * @return XmlConvertibleInterface
147
     */
148 4
    public function getSource(): XmlConvertibleInterface
149
    {
150 4
        return $this->source;
151
    }
152
153
    /**
154
     * @param XmlConvertibleInterface $source
155
     * @return $this
156
     */
157 4
    public function setSource(XmlConvertibleInterface $source)
158
    {
159 4
        $this->source = $source;
160
161 4
        return $this;
162
    }
163
164
    /**
165
     * @return XmlConvertibleInterface
166
     */
167 4
    public function getTarget(): XmlConvertibleInterface
168
    {
169 4
        return $this->target;
170
    }
171
172
    /**
173
     * @param XmlConvertibleInterface $target
174
     * @return $this
175
     */
176 4
    public function setTarget(XmlConvertibleInterface $target)
177
    {
178 4
        $this->target = $target;
179
180 4
        return $this;
181
    }
182
}