Passed
Push — master ( 7067f6...c51298 )
by Julien
01:15 queued 11s
created

UnitOfWork::getDirtyFields()   C

Complexity

Conditions 23
Paths 78

Size

Total Lines 79
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 39
CRAP Score 23

Importance

Changes 0
Metric Value
cc 23
eloc 41
nc 78
nop 3
dl 0
loc 79
ccs 39
cts 39
cp 1
crap 23
rs 5.0403
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Mapado\RestClientSdk;
4
5
use Mapado\RestClientSdk\Helper\ArrayHelper;
6
use Mapado\RestClientSdk\Mapping;
7
use Mapado\RestClientSdk\Mapping\ClassMetadata;
8
use Mapado\RestClientSdk\Mapping\Relation;
9
10
/**
11
 * UnitOfWork
12
 */
13
class UnitOfWork
14
{
15
    /**
16
     * mapping
17
     *
18
     * @var Mapping
19
     * @access private
20
     */
21
    private $mapping;
22
23
    /**
24
     * storage for every entity retrieved
25
     *
26
     * @var array
27
     */
28
    private $storage;
29
30
    /**
31
     * Constructor.
32
     */
33
    public function __construct(Mapping $mapping)
34
    {
35 1
        $this->mapping = $mapping;
36 1
        $this->storage = [];
37 1
    }
38
39
    /**
40
     * getDirtyData
41
     *
42
     * return the new serialized model with only needed fields to update
43
     *
44
     * @param array $newSerializedModel
45
     * @param array $oldSerializedModel
46
     * @param ClassMetadata $classMetadata
47
     * @access public
48
     * @return array
49
     */
50
    public function getDirtyData(array $newSerializedModel, array $oldSerializedModel, ClassMetadata $classMetadata)
51
    {
52 1
        return $this->getDirtyFields($newSerializedModel, $oldSerializedModel, $classMetadata);
53
    }
54
55
    /**
56
     * registerClean
57
     *
58
     * @param string $id
59
     * @param object $entity
60
     * @access public
61
     * @return UnitOfWork
62
     */
63
    public function registerClean($id, $entity)
64
    {
65 1
        if (is_object($entity)) {
66 1
            $entityStored = clone $entity;
67 1
            $this->storage[$id] = $entityStored;
68
        }
69
70 1
        return $this;
71
    }
72
73
    /**
74
     * getDirtyEntity
75
     *
76
     * @param string $id
77
     * @access public
78
     * @return mixed
79
     */
80
    public function getDirtyEntity($id)
81
    {
82 1
        if (isset($this->storage[$id])) {
83 1
            return $this->storage[$id];
84
        }
85
        return null;
86
    }
87
88
    /**
89
     * clear
90
     *
91
     * @param string $id
92
     * @access public
93
     * @return UnitOfWork
94
     */
95
    public function clear($id)
96
    {
97
        unset($this->storage[$id]);
98
        return $this;
99
    }
100
101
    /**
102
     * getDirtyFields
103
     *
104
     * compares serialize object and returns only modified fields
105
     *
106
     * @param array $newSerializedModel
107
     * @param array $oldSerializedModel
108
     * @param ClassMetadata $classMetadata
109
     * @access private
110
     * @return array
111
     */
112
    private function getDirtyFields(array $newSerializedModel, array $oldSerializedModel, ClassMetadata $classMetadata)
113
    {
114 1
        $dirtyFields = [];
115
116 1
        foreach ($newSerializedModel as $key => $value) {
117 1
            if (!array_key_exists($key, $oldSerializedModel)) {
118
                // a new key has been found, add it to the dirtyFields
119 1
                $dirtyFields[$key] = $value;
120 1
                continue;
121
            }
122
123 1
            $oldValue = $oldSerializedModel[$key];
124
125 1
            $currentRelation = $classMetadata ? $classMetadata->getRelation($key) : null;
126
127 1
            if (!$currentRelation) {
128 1
                if (is_array($value) && !ArrayHelper::arraySame($value, $oldValue ?: [])
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: {currentAssign}, Probably Intended Meaning: {alternativeAssign}
Loading history...
129 1
                    || $value !== $oldValue
130
                ) {
131 1
                    $dirtyFields[$key] = $value;
132
                }
133 1
                continue;
134
            }
135
136 1
            $currentClassMetadata = $this->mapping->getClassMetadata($currentRelation->getTargetEntity());
137
138 1
            $idSerializedKey = $currentClassMetadata ? $currentClassMetadata->getIdSerializeKey() : null;
139
140 1
            if ($currentRelation->getType() === Relation::MANY_TO_ONE) {
141 1
                if ($value !== $oldValue) {
142 1
                    if (is_string($value) || is_string($oldValue)) {
143 1
                        $dirtyFields[$key] = $value;
144
                    } else {
145 1
                        $recursiveDiff = $this->getDirtyFields($value, $oldValue, $currentClassMetadata);
146
147 1
                        if (!empty($recursiveDiff)) {
148 1
                            $recursiveDiff[$idSerializedKey] = self::getEntityId($value, $idSerializedKey);
149 1
                            $dirtyFields[$key] = $recursiveDiff;
150
                        }
151
                    }
152
                }
153
154 1
                continue;
155
            }
156
157
            // ONE_TO_MANY relation
158
159 1
            if (count($value ?? []) !== count($oldValue ?? [])) {
160
                // get all objects ids of new array
161 1
                $dirtyFields[$key] = $this->addIdentifiers($value, [], $idSerializedKey);
162
            }
163
164 1
            if (!empty($value)) {
165 1
                foreach ($value as $relationKey => $relationValue) {
166 1
                    $oldRelationValue = $this->findOldRelation($relationValue, $oldValue, $currentClassMetadata);
167
168 1
                    if ($relationValue !== $oldRelationValue) {
169 1
                        if (is_string($relationValue) || is_string($oldRelationValue)) {
170 1
                            $dirtyFields[$key][$relationKey] = $relationValue;
171
                        } else {
172 1
                            $recursiveDiff = $this->getDirtyFields($relationValue, $oldRelationValue, $currentClassMetadata);
173
174 1
                            if (!empty($recursiveDiff)) {
175 1
                                $idSerializedKey = $currentClassMetadata->getIdSerializeKey();
176
177 1
                                $entityId = self::getEntityId($relationValue, $idSerializedKey);
178 1
                                if ($entityId !== null) {
179 1
                                    $recursiveDiff[$idSerializedKey] = $entityId;
180
                                }
181 1
                                $dirtyFields[$key][$relationKey] = $recursiveDiff;
182
                            }
183
                        }
184
                    }
185
                }
186
            }
187
        }
188
189
190 1
        return $dirtyFields;
191
    }
192
193
    /**
194
     * addIdentifiers
195
     *
196
     * add defined identifiers to given model
197
     *
198
     * @param array $newSerializedModel
199
     * @param array $dirtyFields
200
     * @access private
201
     * @return array
202
     */
203
    private function addIdentifiers($newSerializedModel, $dirtyFields, $idSerializedKey = null)
204
    {
205 1
        foreach ($newSerializedModel as $key => $value) {
206 1
            if ($idSerializedKey && isset($value[$idSerializedKey])) {
207 1
                $dirtyFields[$key][$idSerializedKey] = $value[$idSerializedKey];
208 1
            } elseif (is_string($value) && is_int($key)) {
209 1
                $dirtyFields[$key] = $value;
210
            }
211
        }
212
213 1
        return $dirtyFields;
214
    }
215
216
    private function findOldRelation($relationValue, array $oldValue, ClassMetadata $classMetadata)
217
    {
218 1
        $idSerializedKey = $classMetadata->getIdSerializeKey();
219
220 1
        $relationValueId = self::getEntityId($relationValue, $idSerializedKey);
221
222 1
        foreach ($oldValue as $oldRelationValue) {
223 1
            $oldRelationValueId = self::getEntityId($oldRelationValue, $idSerializedKey);
224
225 1
            if ($relationValueId === $oldRelationValueId) {
226 1
                return $oldRelationValue;
227
            }
228
        }
229
230 1
        return $classMetadata->getDefaultSerializedModel();
231
    }
232
233
    /**
234
     * get entity id from string or array
235
     * @param mixed $stringOrEntity
236
     * @param string $idSerializedKey
237
     */
238
    private static function getEntityId($stringOrEntity, $idSerializedKey)
239
    {
240 1
        if (!is_array($stringOrEntity)) {
241 1
            return $stringOrEntity;
242
        }
243
244 1
        return isset($stringOrEntity[$idSerializedKey])
245 1
            ? $stringOrEntity[$idSerializedKey]
246 1
            : null;
247
    }
248
}
249