Completed
Push — master ( cc21f4...3eeaf5 )
by Julien
06:41 queued 03:06
created

UnitOfWork::clear()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 5
ccs 0
cts 2
cp 0
crap 2
rs 10
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->getRelation($key);
136
137 1
            if (!$currentRelation) {
138
                if (
139 1
                    is_array($value) &&
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: (is_array($value) && ! M...|| $value !== $oldValue, Probably Intended Meaning: is_array($value) && (! M...| $value !== $oldValue)
Loading history...
140 1
                    !ArrayHelper::arraySame($value, $oldValue ?: []) ||
141 1
                    $value !== $oldValue
142
                ) {
143 1
                    $dirtyFields[$key] = $value;
144
                }
145 1
                continue;
146
            }
147
148 1
            $currentClassMetadata = $this->mapping->getClassMetadata(
149 1
                $currentRelation->getTargetEntity()
150
            );
151
152 1
            $idSerializedKey = $currentClassMetadata->getIdSerializeKey();
153
154 1
            if (Relation::MANY_TO_ONE === $currentRelation->getType()) {
155 1
                if ($value !== $oldValue) {
156 1
                    if (is_string($value) || is_string($oldValue)) {
157 1
                        $dirtyFields[$key] = $value;
158
                    } else {
159 1
                        $recursiveDiff = $this->getDirtyFields(
160 1
                            $value,
161 1
                            $oldValue,
162 1
                            $currentClassMetadata
163
                        );
164
165 1
                        if (!empty($recursiveDiff)) {
166
                            $recursiveDiff[
167 1
                                $idSerializedKey
168 1
                            ] = self::getEntityId($value, $idSerializedKey);
169 1
                            $dirtyFields[$key] = $recursiveDiff;
170
                        }
171
                    }
172
                }
173
174 1
                continue;
175
            }
176
177
            // ONE_TO_MANY relation
178 1
            if (count($value ?? []) !== count($oldValue ?? [])) {
179
                // get all objects ids of new array
180 1
                $dirtyFields[$key] = $this->addIdentifiers(
181 1
                    $value,
182 1
                    [],
183 1
                    $idSerializedKey
184
                );
185
            }
186
187 1
            if (!empty($value)) {
188 1
                foreach ($value as $relationKey => $relationValue) {
189 1
                    $oldRelationValue = $this->findOldRelation(
190 1
                        $relationValue,
191 1
                        $oldValue,
192 1
                        $currentClassMetadata
193
                    );
194
195 1
                    if ($relationValue !== $oldRelationValue) {
196
                        if (
197 1
                            is_string($relationValue) ||
198 1
                            is_string($oldRelationValue)
199
                        ) {
200 1
                            $dirtyFields[$key][$relationKey] = $relationValue;
201
                        } else {
202 1
                            $recursiveDiff = $this->getDirtyFields(
203 1
                                $relationValue,
204 1
                                $oldRelationValue,
205 1
                                $currentClassMetadata
206
                            );
207
208 1
                            if (!empty($recursiveDiff)) {
209 1
                                $idSerializedKey = $currentClassMetadata->getIdSerializeKey();
210
211 1
                                $entityId = self::getEntityId(
212 1
                                    $relationValue,
213 1
                                    $idSerializedKey
214
                                );
215 1
                                if (null !== $entityId) {
216
                                    $recursiveDiff[
217 1
                                        $idSerializedKey
218
                                    ] = $entityId;
219
                                }
220 1
                                $dirtyFields[$key][
221 1
                                    $relationKey
222 1
                                ] = $recursiveDiff;
223
                            }
224
                        }
225
                    }
226
                }
227
            }
228
        }
229
230 1
        return $dirtyFields;
231
    }
232
233
    /**
234
     * addIdentifiers
235
     *
236
     * add defined identifiers to given model
237
     *
238
     * @param array $newSerializedModel
239
     * @param array $dirtyFields
240
     *
241
     * @return array
242
     */
243
    private function addIdentifiers(
244
        $newSerializedModel,
245
        $dirtyFields,
246
        $idSerializedKey = null
247
    ) {
248 1
        foreach ($newSerializedModel as $key => $value) {
249 1
            if ($idSerializedKey && isset($value[$idSerializedKey])) {
250 1
                $dirtyFields[$key][$idSerializedKey] = $value[$idSerializedKey];
251 1
            } elseif (is_string($value) && is_int($key)) {
252 1
                $dirtyFields[$key] = $value;
253
            }
254
        }
255
256 1
        return $dirtyFields;
257
    }
258
259
    private function findOldRelation(
260
        $relationValue,
261
        array $oldValue,
262
        ClassMetadata $classMetadata
263
    ) {
264 1
        $idSerializedKey = $classMetadata->getIdSerializeKey();
265
266 1
        $relationValueId = self::getEntityId($relationValue, $idSerializedKey);
267
268 1
        foreach ($oldValue as $oldRelationValue) {
269 1
            $oldRelationValueId = self::getEntityId(
270 1
                $oldRelationValue,
271 1
                $idSerializedKey
272
            );
273
274 1
            if ($relationValueId === $oldRelationValueId) {
275 1
                return $oldRelationValue;
276
            }
277
        }
278
279 1
        return $classMetadata->getDefaultSerializedModel();
280
    }
281
282
    /**
283
     * get entity id from string or array
284
     *
285
     * @param mixed $stringOrEntity
286
     * @param string $idSerializedKey
287
     */
288
    private static function getEntityId($stringOrEntity, $idSerializedKey)
289
    {
290 1
        if (!is_array($stringOrEntity)) {
291 1
            return $stringOrEntity;
292
        }
293
294 1
        return $stringOrEntity[$idSerializedKey] ?? null;
295
    }
296
}
297