Completed
Push — master ( 1c49db...1a6bbd )
by Julien
02:00
created

UnitOfWork::findOldRelation()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 8
nc 3
nop 3
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
        $this->mapping = $mapping;
36
        $this->storage = [];
37
    }
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
        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
        if (is_object($entity)) {
66
            $entityStored = clone $entity;
67
            $this->storage[$id] = $entityStored;
68
        }
69
70
        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
        if (isset($this->storage[$id])) {
83
            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 = null)
113
    {
114
        $dirtyFields = [];
115
116
        foreach ($newSerializedModel as $key => $value) {
117
            if (!array_key_exists($key, $oldSerializedModel)) {
118
                // a new key has been found, add it to the dirtyFields
119
                $dirtyFields[$key] = $value;
120
                continue;
121
            }
122
123
            $oldValue = $oldSerializedModel[$key];
124
125
            $currentRelation = $classMetadata ? $classMetadata->getRelation($key) : null;
126
127
            if (!$currentRelation) {
128
                if (is_array($value) && !ArrayHelper::arraySame($value, $oldValue)
129
                    || $value != $oldValue
130
                ) {
131
                    $dirtyFields[$key] = $value;
132
                }
133
                continue;
134
            }
135
136
            $currentClassMetadata = $this->mapping->getClassMetadata($currentRelation->getTargetEntity());
137
138
            $idSerializedKey = $currentClassMetadata ? $currentClassMetadata->getIdSerializeKey() : null;
139
140
            if ($currentRelation->getType() === Relation::MANY_TO_ONE) {
141
                if ($value !== $oldValue) {
142
                    if (is_string($value) || is_string($oldValue)) {
143
                        $dirtyFields[$key] = $value;
144 View Code Duplication
                    } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
145
                        $recursiveDiff = $this->getDirtyFields($value, $oldValue, $currentClassMetadata);
146
147
                        if (!empty($recursiveDiff)) {
148
                            $recursiveDiff[$idSerializedKey] = self::getEntityId($value, $idSerializedKey);
149
                            $dirtyFields[$key] = $recursiveDiff;
150
                        }
151
                    }
152
                }
153
154
                continue;
155
            }
156
157
            // ONE_TO_MANY relation
158
159
            if (count($value) != count($oldValue)) {
160
                // get all objects ids of new array
161
                $dirtyFields[$key] = $this->addIdentifiers($value, [], $idSerializedKey);
162
            }
163
164
            foreach ($value as $relationKey => $relationValue) {
165
                $oldRelationValue = $this->findOldRelation($relationValue, $oldValue, $currentClassMetadata);
166
167
168
                if ($relationValue !== $oldRelationValue) {
169
                    if (is_string($relationValue) || is_string($oldRelationValue)) {
170
                        $dirtyFields[$key][$relationKey] = $relationValue;
171
                    } else {
172
                        $recursiveDiff = $this->getDirtyFields($relationValue, $oldRelationValue, $currentClassMetadata);
173
174 View Code Duplication
                        if (!empty($recursiveDiff)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
175
                            $idSerializedKey = $currentClassMetadata->getIdSerializeKey();
176
177
                            $recursiveDiff[$idSerializedKey] = self::getEntityId($relationValue, $idSerializedKey);
178
                            $dirtyFields[$key][$relationKey] = $recursiveDiff;
179
                        }
180
                    }
181
                }
182
            }
183
        }
184
185
186
        return $dirtyFields;
187
    }
188
189
    /**
190
     * addIdentifiers
191
     *
192
     * add defined identifiers to given model
193
     *
194
     * @param array $newSerializedModel
195
     * @param array $dirtyFields
196
     * @access private
197
     * @return array
198
     */
199
    private function addIdentifiers($newSerializedModel, $dirtyFields, $idSerializedKey = null)
200
    {
201
        foreach ($newSerializedModel as $key => $value) {
202
            if ($idSerializedKey && isset($value[$idSerializedKey])) {
203
                $dirtyFields[$key][$idSerializedKey] = $value[$idSerializedKey];
204
            } elseif (is_string($value) && is_int($key)) {
205
                $dirtyFields[$key] = $value;
206
            }
207
        }
208
209
        return $dirtyFields;
210
    }
211
212
    private function findOldRelation($relationValue, array $oldValue, ClassMetadata $classMetadata)
213
    {
214
        $idSerializedKey = $classMetadata->getIdSerializeKey();
215
216
        $relationValueId = self::getEntityId($relationValue, $idSerializedKey);
217
218
        foreach ($oldValue as $oldRelationValue) {
219
            $oldRelationValueId = self::getEntityId($oldRelationValue, $idSerializedKey);
220
221
            if ($relationValueId === $oldRelationValueId) {
222
                return $oldRelationValue;
223
            }
224
        }
225
226
        return [];
227
    }
228
229
    /**
230
     * get entity id from string or array
231
     * @param mixed $stringOrEntity
232
     * @param string $idSerializedKey
233
     */
234
    private static function getEntityId($stringOrEntity, $idSerializedKey)
235
    {
236
        if (!is_array($stringOrEntity)) {
237
            return $stringOrEntity;
238
        }
239
240
        return $stringOrEntity[$idSerializedKey];
241
    }
242
}
243