Passed
Push — master ( 685595...680e76 )
by Julien
01:32
created

UnitOfWork::findOldRelation()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 21
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3

Importance

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