Passed
Push — master ( 4fb543...e7c8f8 )
by Giacomo
10:34
created

MongoSyncTrait   F

Complexity

Total Complexity 61

Size/Duplication

Total Lines 387
Duplicated Lines 0 %

Importance

Changes 4
Bugs 1 Features 0
Metric Value
eloc 176
c 4
b 1
f 0
dl 0
loc 387
rs 3.52
wmc 61

10 Methods

Rating   Name   Duplication   Size   Complexity  
A storeWithSync() 0 11 1
A destroyWithSync() 0 39 5
A updateRelationWithSync() 0 27 6
C processAllRelationships() 0 70 15
A deleteTargetObj() 0 11 4
B storeEditAllItems() 0 34 10
A getOptionValue() 0 2 2
A handleSubTarget() 0 12 3
C processOneEmbededRelationship() 0 70 14
A updateWithSync() 0 10 1

How to fix   Complexity   

Complex Class

Complex classes like MongoSyncTrait often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use MongoSyncTrait, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace OfflineAgency\MongoAutoSync\Traits;
4
5
use DateTime;
6
use Exception;
7
use Illuminate\Http\Request;
8
use MongoDB\BSON\UTCDateTime;
9
10
trait MongoSyncTrait
11
{
12
    /**
13
     * @param Request $request
14
     * @param array $additionalData
15
     * @param array $options
16
     * @return $this
17
     * @throws Exception
18
     */
19
    public function storeWithSync(Request $request, array $additionalData = [], array $options = [])
20
    {
21
        $request = $request->merge($additionalData);
22
23
        $this->storeEditAllItems($request, "add", $options);
24
        $this->processAllRelationships($request, "add", "", "", $options);
25
26
        //Dispatch the creation event
27
        $this->fireModelEvent('storeWithSync');
0 ignored issues
show
Bug introduced by
It seems like fireModelEvent() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

27
        $this->/** @scrutinizer ignore-call */ 
28
               fireModelEvent('storeWithSync');
Loading history...
28
29
        return $this;
30
    }
31
32
    /**
33
     * @param Request $request
34
     * @param string $event
35
     * @param array $options
36
     * @throws Exception
37
     */
38
    public function storeEditAllItems(Request $request, string $event, array $options)
39
    {
40
        //Get the item name
41
        $items = $this->getItems();
0 ignored issues
show
Bug introduced by
It seems like getItems() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

41
        /** @scrutinizer ignore-call */ 
42
        $items = $this->getItems();
Loading history...
42
        $is_skippable = $this->getOptionValue($options, 'request_type');
43
        //Current Obj Create
44
        foreach ($items as $key => $item) {
45
            $is_ML = isML($item);
46
            $is_MD = isMD($item);
47
48
            $is_fillable = isFillable($item, $event);
49
            if ( is_null($request->input($key)) && $is_skippable ) { continue; }//Skip with partial request type
50
51
            if ($is_fillable) {
52
                if ($is_ML) {
53
                    if (is_null($this->$key)) {
54
                        $old_value = array();
55
                    } else {
56
                        $old_value = $this->$key;
57
                    }
58
                    $this->$key = ml($old_value, $request->input($key));
59
                } elseif ($is_MD) {
60
                    if ($request->input($key) == "" || $request->input($key) == null) {
61
                        $this->$key = null;
62
                    } else {
63
                        $this->$key = new UTCDateTime(new DateTime($request->input($key)));
0 ignored issues
show
Bug introduced by
new DateTime($request->input($key)) of type DateTime is incompatible with the type integer expected by parameter $milliseconds of MongoDB\BSON\UTCDateTime::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

63
                        $this->$key = new UTCDateTime(/** @scrutinizer ignore-type */ new DateTime($request->input($key)));
Loading history...
64
                    }
65
                } else {
66
                    $this->$key = $request->input($key);
67
                }
68
            }
69
        }
70
71
        $this->save();
0 ignored issues
show
Bug introduced by
It seems like save() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

71
        $this->/** @scrutinizer ignore-call */ 
72
               save();
Loading history...
72
    }
73
74
    /**
75
     * @param Request $request
76
     * @param string $event
77
     * @param string $parent
78
     * @param string $counter
79
     * @param array $options
80
     * @throws Exception
81
     */
82
    public function processAllRelationships(Request $request, string $event, string $parent, string $counter, array $options)
83
    {
84
        //Get the relation info
85
        $relations = $this->getMongoRelation();
0 ignored issues
show
Bug introduced by
It seems like getMongoRelation() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

85
        /** @scrutinizer ignore-call */ 
86
        $relations = $this->getMongoRelation();
Loading history...
86
87
        //Process all relationships
88
        foreach ($relations as $method => $relation) {
89
            //Get Relation Save Mode
90
            $type = $relation['type'];
91
            $model = $relation['model'];
92
            $hasTarget = hasTarget($relation);
93
            if ($hasTarget) {
94
                $modelTarget = $relation['modelTarget'];
95
                $methodOnTarget = $relation['methodOnTarget'];
96
                $modelOnTarget = $relation['modelOnTarget'];
97
            } else {
98
                $modelTarget = "";
99
                $methodOnTarget = "";
100
                $modelOnTarget = "";
101
            }
102
103
            $is_EO = is_EO($type);
104
            $is_EM = is_EM($type);
105
            $is_skippable = $this->getOptionValue($options, 'request_type');
106
107
            $key = $parent . $method . $counter;
108
            $value = $request->input($key);
109
            if ( is_null($value) && $is_skippable ) { continue; }//Skip with partial request type
110
111
            if (!is_null($value) && !($value == "") && !($value == "[]")) {
112
                $objs = json_decode($value);
113
            } else {
114
                $objs = getArrayWithEmptyObj($model, $is_EO, $is_EM);
115
            }
116
117
            if ($is_EO || $is_EM) {//EmbedsOne Create - EmbedsMany Create
118
                if ($event == "update") {
119
120
                    //Delete EmbedsMany or EmbedsOne on Target
121
                    if ($hasTarget) {
122
                        $this->deleteTargetObj($method, $modelTarget, $methodOnTarget, $is_EO);
123
                    }
124
                    //Delete EmbedsMany or EmbedsOne on current object
125
                    if ($is_EM) {
126
                        $this->$method()->delete();
127
                    }
128
                }
129
130
                if (!empty($objs)) {
131
                    $i = 0;
132
                    foreach ($objs as $obj) {
133
                        $this->processOneEmbededRelationship(
134
                            $request,
135
                            $obj,
136
                            $type,
137
                            $model,
138
                            $method,
139
                            $modelTarget,
140
                            $methodOnTarget,
141
                            $modelOnTarget, $event,
142
                            $hasTarget,
143
                            $is_EO,
144
                            $is_EM,
145
                            $i,
146
                            $options);
147
                        $i++;
148
                    }
149
                } else {
150
                    $this->$method = [];
151
                    $this->save();
152
                }
153
            }
154
        }
155
    }
156
157
    /**
158
     * @param Request $request
159
     * @param $methodOnTarget
160
     * @param $modelOnTarget
161
     * @throws Exception
162
     */
163
    public function updateRelationWithSync(Request $request, $methodOnTarget, $modelOnTarget)
164
    {
165
        $embededModel = new $modelOnTarget;
166
        //Get the item name
167
        $items = $embededModel->getItems();
168
        $embededObj = $request->input($methodOnTarget);
169
        $embededObj = json_decode($embededObj);
170
171
        //Current Obj Create
172
        foreach ($items as $key => $item) {
173
            $is_ML = isML($item);
174
            $is_MD = isMD($item);
175
176
            if ($is_ML) {
177
                $embededModel->$key = ml(array(), $embededObj->$key);
178
            } elseif ($is_MD) {
179
                if ($embededObj->$key == "" || $embededObj->$key == null) {
180
                    $embededModel->$key = null;
181
                } else {
182
                    $embededModel->$key = new UTCDateTime(new DateTime($embededObj->$key));
0 ignored issues
show
Bug introduced by
new DateTime($embededObj->$key) of type DateTime is incompatible with the type integer expected by parameter $milliseconds of MongoDB\BSON\UTCDateTime::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

182
                    $embededModel->$key = new UTCDateTime(/** @scrutinizer ignore-type */ new DateTime($embededObj->$key));
Loading history...
183
                }
184
            } else {
185
                $embededModel->$key = $embededObj->$key;
186
            }
187
        }
188
        $this->$methodOnTarget()->associate($embededModel);
189
        $this->save();
190
    }
191
192
    /**
193
     * @param Request $request
194
     * @param $obj
195
     * @param $type
196
     * @param $model
197
     * @param $method
198
     * @param $modelTarget
199
     * @param $methodOnTarget
200
     * @param $modelOnTarget
201
     * @param $event
202
     * @param $hasTarget
203
     * @param $is_EO
204
     * @param $is_EM
205
     * @param $i
206
     * @throws Exception
207
     */
208
    public function processOneEmbededRelationship(Request $request, $obj, $type, $model, $method, $modelTarget, $methodOnTarget, $modelOnTarget, $event, $hasTarget, $is_EO, $is_EM, $i, $options)
209
    {
210
        //Init the embedone model
211
        $embedObj = new $model;
212
213
        $EOitems = $embedObj->getItems();
214
        //Current Obj Create
215
        foreach ($EOitems as $EOkey => $item) {
216
            if (!is_null($obj)) {
217
                $is_ML = isML($item);
218
                $is_MD = isMD($item);
219
220
                if ($is_ML) {
221
                    $embedObj->$EOkey = ml(array(), $obj->$EOkey);
222
                } elseif ($EOkey == "updated_at" || $EOkey == "created_at") {
223
                    $embedObj->$EOkey = now();
224
                } elseif ($is_MD) {
225
                    if ($obj->$EOkey == "" ||  $obj->$EOkey == null) {
226
                        $embedObj->$EOkey = null;
227
                    } else {
228
                        $embedObj->$EOkey = new UTCDateTime(new DateTime($obj->$EOkey));
0 ignored issues
show
Bug introduced by
new DateTime($obj->$EOkey) of type DateTime is incompatible with the type integer expected by parameter $milliseconds of MongoDB\BSON\UTCDateTime::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

228
                        $embedObj->$EOkey = new UTCDateTime(/** @scrutinizer ignore-type */ new DateTime($obj->$EOkey));
Loading history...
229
                    }
230
                } else {
231
                    if (!property_exists($obj, $EOkey)) {
232
                        $msg = ('Error - ' . $EOkey . ' attribute not found on obj ' . json_encode($obj));
233
                        (new Exception($msg) );
234
                    }
235
                    $embedObj->$EOkey = $obj->$EOkey;
236
                }
237
            }
238
        }
239
240
        //else if($is_EM){//To be implemented}
241
        //else if($is_HM){//To be implemented}
242
        //else if($is_HO){//To be implemented}
243
244
        //Get counter for embeds many with level > 1
245
        $counter = getCounterForRelationships($method, $is_EO, $is_EM, $i);
246
        //Check for another Level of Relationship
247
        $embedObj->processAllRelationships($request, $event, $method . "-", $counter, $options);
248
249
        if ($is_EO) {
250
            $this->$method = $embedObj->attributes;
251
        } else {
252
            $this->$method()->associate($embedObj);
253
        }
254
        $this->save();
255
256
        //dd($embedObj, $this);
257
258
        if ($hasTarget) {
259
            //sync Permission to Permissiongroup
260
            //Init the Target Model
261
            $target_model = new $modelTarget;
0 ignored issues
show
Unused Code introduced by
The assignment to $target_model is dead and can be removed.
Loading history...
262
263
            if (!property_exists($obj, 'ref_id')) {
264
                $msg = ('Error - ref_id attribute not found on obj ' . json_encode($obj));
265
                throw (new \Exception($msg) );
266
            }
267
268
            $target_id = $obj->ref_id;
269
270
            $ref_id = $this->getId();
0 ignored issues
show
Bug introduced by
It seems like getId() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

270
            /** @scrutinizer ignore-call */ 
271
            $ref_id = $this->getId();
Loading history...
271
272
            $requestToBeSync = getRequestToBeSync($ref_id, $modelOnTarget, $request, $methodOnTarget);
273
274
            $modelToBeSync = new $modelTarget;
275
            $modelToBeSync = $modelToBeSync->find($target_id);
276
            if (!is_null($modelToBeSync)) {
277
                $modelToBeSync->updateRelationWithSync($requestToBeSync, $methodOnTarget, $modelOnTarget);
278
                //TODO:Sync target on level > 1
279
                //$modelToBeSync->processAllRelationships($request, $event, $methodOnTarget, $methodOnTarget . "-");
280
            }
281
        }
282
    }
283
284
285
    /**
286
     * @param Request $request
287
     * @param array $additionalData
288
     * @param array $options
289
     * @return $this
290
     * @throws Exception
291
     */
292
    public function updateWithSync(Request $request, array $additionalData = [], array $options)
293
    {
294
        $request = $request->merge($additionalData);
295
        $this->storeEditAllItems($request, "update", $options);
296
        $this->processAllRelationships($request, "update", "", "", $options);
297
298
        //Dispatch the update event
299
        $this->fireModelEvent('updateWithSync');
300
301
        return $this;
302
    }
303
304
    /**
305
     * @param $method
306
     * @param $modelTarget
307
     * @param $methodOnTarget
308
     * @param $id
309
     */
310
    public function deleteTargetObj($method, $modelTarget, $methodOnTarget, $is_EO)
311
    {
312
        if ($is_EO) {
313
            $embedObj = $this->$method;
314
            if (!is_null($embedObj)) {
315
                $target_id = $embedObj->ref_id;
316
                $this->handleSubTarget($target_id, $modelTarget, $methodOnTarget);
317
            }
318
        } else {
319
            foreach ($this->$method as $target) {
320
                $this->handleSubTarget($target->ref_id, $modelTarget, $methodOnTarget);
321
            }
322
        }
323
    }
324
325
    /**
326
     * @param $target_id
327
     * @param $modelTarget
328
     * @param $methodOnTarget
329
     */
330
    public function handleSubTarget($target_id, $modelTarget, $methodOnTarget)
331
    {
332
        $id = $this->getId();
333
        $target = new $modelTarget;
334
        $target = $target->all()->where('id', $target_id)->first();
335
        if (!is_null($target)) {
336
            $subTarget = $target->$methodOnTarget()->where('ref_id', $id)->first();
337
            $temps = $target->$methodOnTarget()->where('ref_id', '!=', $id);
338
            $target->$methodOnTarget()->delete($subTarget);
339
            foreach ($temps as $temp) {
340
                $target->$methodOnTarget()->associate($temp);
341
                $target->save();
342
            }
343
        }
344
    }
345
346
    /**
347
     * @return $this
348
     */
349
    public function destroyWithSync()
350
    {
351
        //Get the relation info
352
        $relations = $this->getMongoRelation();
353
354
        //Process all relationships
355
        foreach ($relations as $method => $relation) {
356
            //Get Relation Save Mode
357
            $type = $relation['type'];
358
            $hasTarget = hasTarget($relation);
359
            if ($hasTarget) {
360
                $modelTarget = $relation['modelTarget'];
361
                $methodOnTarget = $relation['methodOnTarget'];
362
                $modelOnTarget = $relation['modelOnTarget'];
0 ignored issues
show
Unused Code introduced by
The assignment to $modelOnTarget is dead and can be removed.
Loading history...
363
364
                $is_EO = is_EO($type);
365
                $is_EM = is_EM($type);
366
                $is_HO = is_HO($type);
0 ignored issues
show
Unused Code introduced by
The assignment to $is_HO is dead and can be removed.
Loading history...
367
                $is_HM = is_HM($type);
0 ignored issues
show
Unused Code introduced by
The assignment to $is_HM is dead and can be removed.
Loading history...
368
369
370
                if ($is_EO || $is_EM) {//EmbedsOne Create - EmbedsMany Create
371
                    //Delete EmbedsMany or EmbedsOne on Target
372
                    $this->deleteTargetObj($method, $modelTarget, $methodOnTarget, $is_EO);
373
                }
374
375
                //TODO: Need to be implemented
376
               /* elseif ($is_HM) {//HasMany
377
                } elseif ($is_HO) {//HasOne Create
378
                }*/
379
            }
380
        }
381
        //Delete current object
382
        $this->delete();
0 ignored issues
show
Bug introduced by
The method delete() does not exist on OfflineAgency\MongoAutoSync\Traits\MongoSyncTrait. Did you maybe mean deleteTargetObj()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

382
        $this->/** @scrutinizer ignore-call */ 
383
               delete();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
383
384
        //Dispatch the destroy event
385
        $this->fireModelEvent('destroyWithSync');
386
387
        return $this;
388
    }
389
390
    /**
391
     * @param array $options
392
     * @param string $key
393
     * @return bool|mixed
394
     */
395
    private function getOptionValue(array $options, string $key){
396
        return array_key_exists('',  $options) ?   $options[$key] : false;
397
    }
398
}
399