Completed
Pull Request — master (#375)
by Paul
06:22
created

WidgetMap   F

Complexity

Total Complexity 75

Size/Duplication

Total Lines 479
Duplicated Lines 7.72 %

Coupling/Cohesion

Components 4
Dependencies 2

Importance

Changes 6
Bugs 2 Features 1
Metric Value
wmc 75
c 6
b 2
f 1
lcom 4
cbo 2
dl 37
loc 479
rs 2.3076

35 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A getId() 0 4 1
A setId() 0 4 1
A isAsynchronous() 0 4 1
A setAsynchronous() 0 4 1
A setAction() 0 9 4
A getAction() 0 4 1
A getWidgets() 0 4 1
A addWidget() 0 6 1
A setWidgets() 0 6 1
A getView() 0 4 1
A setView() 0 4 1
A getReplaced() 0 4 1
A setReplaced() 0 7 2
A getSlot() 0 4 1
A setSlot() 0 4 1
C getChildren() 37 56 23
A getChildrenRaw() 0 4 1
A hasChild() 0 10 4
A getChild() 0 11 4
A getChilds() 0 11 4
A setChildren() 0 4 1
A removeChildren() 0 6 2
A addChild() 0 4 1
A removeChild() 0 4 1
A getParent() 0 4 1
A setParent() 0 10 3
A getPosition() 0 4 1
A setPosition() 0 4 1
A getSubstitutes() 0 4 1
A getSubstituteForView() 0 8 3
A addSubstitute() 0 4 1
A setSubstitutes() 0 4 1
A getWidget() 0 4 1
A setWidget() 0 6 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like WidgetMap 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 WidgetMap, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Victoire\Bundle\WidgetMapBundle\Entity;
4
5
use Doctrine\Common\Collections\ArrayCollection;
6
use Doctrine\Common\Collections\Collection;
7
use Doctrine\ORM\Mapping as ORM;
8
use Victoire\Bundle\CoreBundle\Entity\View;
9
use Victoire\Bundle\WidgetBundle\Entity\Widget;
10
11
/**
12
 * @ORM\Table("vic_widget_map")
13
 * @ORM\Entity()
14
 */
15
class WidgetMap
16
{
17
    const ACTION_CREATE = 'create';
18
    const ACTION_OVERWRITE = 'overwrite';
19
    const ACTION_DELETE = 'delete';
20
21
    const POSITION_BEFORE = 'before';
22
    const POSITION_AFTER = 'after';
23
24
    /**
25
     * @var int
26
     *
27
     * @ORM\Column(name="id", type="integer")
28
     * @ORM\Id
29
     * @ORM\GeneratedValue(strategy="AUTO")
30
     */
31
    protected $id;
32
33
    /**
34
     * @var string
35
     *
36
     * @ORM\Column(name="action", type="string", length=255)
37
     */
38
    protected $action = null;
39
40
    /**
41
     * @var View
42
     *
43
     * @ORM\ManyToOne(targetEntity="\Victoire\Bundle\CoreBundle\Entity\View", inversedBy="widgetMaps")
44
     * @ORM\JoinColumn(name="view_id", referencedColumnName="id", onDelete="cascade")
45
     */
46
    protected $view;
47
48
    /**
49
     * @var Widget
50
     *
51
     * @ORM\OneToMany(targetEntity="\Victoire\Bundle\WidgetBundle\Entity\Widget", mappedBy="widgetMap", orphanRemoval=true, cascade={"persist", "remove"})
52
     */
53
    protected $widgets;
54
55
    /**
56
     * @deprecated
57
     * @var Widget
58
     *
59
     * @ORM\ManyToOne(targetEntity="\Victoire\Bundle\WidgetBundle\Entity\Widget")
60
     * @ORM\JoinColumn(name="widget_id", referencedColumnName="id", onDelete="SET NULL")
61
     */
62
    protected $widget;
63
64
    /**
65
     * @ORM\ManyToOne(targetEntity="\Victoire\Bundle\WidgetMapBundle\Entity\WidgetMap", inversedBy="substitutes")
66
     * @ORM\JoinColumn(name="replaced_id", referencedColumnName="id")
67
     */
68
    protected $replaced;
69
70
    /**
71
     * @var ArrayCollection
72
     * @ORM\OneToMany(targetEntity="\Victoire\Bundle\WidgetMapBundle\Entity\WidgetMap", mappedBy="replaced")
73
     */
74
    protected $substitutes;
75
76
    /**
77
     * @var string
78
     *
79
     * @ORM\Column(name="asynchronous", type="boolean")
80
     */
81
    protected $asynchronous = false;
82
83
    /**
84
     * @ORM\ManyToOne(targetEntity="\Victoire\Bundle\WidgetMapBundle\Entity\WidgetMap", inversedBy="children")
85
     * @ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="SET NULL")
86
     */
87
    protected $parent;
88
89
    /**
90
     * @var string
91
     *
92
     * @ORM\Column(name="position", type="string", nullable=true)
93
     */
94
    protected $position;
95
96
    /**
97
     * @var Collection
98
     * @ORM\OneToMany(targetEntity="\Victoire\Bundle\WidgetMapBundle\Entity\WidgetMap", mappedBy="parent")
99
     */
100
    protected $children;
101
102
    /**
103
     * @var string
104
     *
105
     * @ORM\Column(name="slot", type="string", length=255, nullable=true)
106
     */
107
    protected $slot;
108
109
    public function __construct()
110
    {
111
        $this->children = new ArrayCollection();
112
        $this->substitutes = new ArrayCollection();
113
    }
114
115
    /**
116
     * @return int
117
     */
118
    public function getId()
119
    {
120
        return $this->id;
121
    }
122
123
    public function setId($id)
124
    {
125
        $this->id = $id;
126
    }
127
128
    /**
129
     * @return string
130
     */
131
    public function isAsynchronous()
132
    {
133
        return $this->asynchronous;
134
    }
135
136
    /**
137
     * @param bool|string $asynchronous
138
     */
139
    public function setAsynchronous($asynchronous)
140
    {
141
        $this->asynchronous = $asynchronous;
0 ignored issues
show
Documentation Bug introduced by
It seems like $asynchronous can also be of type boolean. However, the property $asynchronous is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
142
    }
143
144
    /**
145
     * Set the action.
146
     *
147
     * @param string $action
148
     *
149
     * @throws \Exception The action is not valid
150
     */
151
    public function setAction($action)
152
    {
153
        //test validity of the action
154
        if ($action !== self::ACTION_CREATE && $action !== self::ACTION_OVERWRITE && $action !== self::ACTION_DELETE) {
155
            throw new \Exception('The action of the widget map is not valid. Action: ['.$action.']');
156
        }
157
158
        $this->action = $action;
159
    }
160
161
    /**
162
     * Get the action.
163
     *
164
     * @return string The action
165
     */
166
    public function getAction()
167
    {
168
        return $this->action;
169
    }
170
171
    /**
172
     * @return [Widget]
0 ignored issues
show
Documentation introduced by
The doc-type [Widget] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
173
     */
174
    public function getWidgets()
175
    {
176
        return $this->widgets;
177
    }
178
179
    /**
180
     * @param Widget $widget
181
     *
182
     * @return $this
183
     */
184
    public function addWidget(Widget $widget)
185
    {
186
        $this->widgets[] = $widget;
187
188
        return $this;
189
    }
190
    /**
191
     * @param [Widget] $widgets
0 ignored issues
show
Documentation introduced by
The doc-type [Widget] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
192
     *
193
     * @return $this
194
     */
195
    public function setWidgets($widgets)
196
    {
197
        $this->widgets = $widgets;
198
199
        return $this;
200
    }
201
202
    /**
203
     * @return View
204
     */
205
    public function getView()
206
    {
207
        return $this->view;
208
    }
209
210
    /**
211
     * @param View $view
212
     */
213
    public function setView(View $view)
214
    {
215
        $this->view = $view;
216
    }
217
218
    /**
219
     * @return mixed
220
     */
221
    public function getReplaced()
222
    {
223
        return $this->replaced;
224
    }
225
226
    /**
227
     * @param mixed $replaced
228
     */
229
    public function setReplaced($replaced)
230
    {
231
        if ($replaced) {
232
            $replaced->addSubstitute($this);
233
        }
234
        $this->replaced = $replaced;
235
    }
236
237
    /**
238
     * @return string
239
     */
240
    public function getSlot()
241
    {
242
        return $this->slot;
243
    }
244
245
    /**
246
     * @param string $slot
247
     */
248
    public function setSlot($slot)
249
    {
250
        $this->slot = $slot;
251
    }
252
253
    /**
254
     * @return mixed
255
     */
256
    public function getChildren(View $view = null)
257
    {
258
        $positions = [self::POSITION_BEFORE, self::POSITION_AFTER];
259
        $children = [];
260
        $widgetMap = $this;
261
        foreach ($positions as $position) {
262
            $children[$position] = null;
263
            if (($childs = $widgetMap->getChilds($position)) && !empty($childs)) {
264 View Code Duplication
                foreach ($childs as $_child) {
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...
265
                    // found child must belongs to the given view or one of it's templates
266
                    if ($view) {
267
                        // if child has a view
268
                        // and child view is same as given view or the child view is a template of given view
269
                        if ($_child->getView() && ($view == $_child->getView() || $_child->getView()->isTemplateOf($view))
270
                        ) {
271
                            // if child is a substitute in view
272
                            if ($substitute = $_child->getSubstituteForView($view)) {
273
                                // if i'm not the parent of the substitute or i does not have the same position, child is not valid
274
                                if ($substitute->getParent() != $this || $substitute->getPosition() != $position) {
275
                                    $_child = null;
276
                                }
277
                            }
278
                            $children[$position] = $_child;
279
                        }
280
                    } else {
281
                        $children[$position] = $_child;
282
                    }
283
                }
284
            }
285
            // If I am replaced and my replacement has children for the position
286
            if (!$children[$position]
287
                && ($replaced = $this->getReplaced())
288
                && !empty($this->getReplaced()->getChilds($position))) {
289 View Code Duplication
                foreach ($this->getReplaced()->getChilds($position) as $_child) {
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...
290
                    if ($view) {
291
                        // if child view is same as given view or the child view is a template of given view
292
                        if ($_child->getView() && ($view == $_child->getView() || $_child->getView()->isTemplateOf($view))) {
293
294
                            // if child is a substitute in view
295
                            if ($substitute = $_child->getSubstituteForView($view)) {
296
                                // if i'm not the parent of the substitute or i does not have the same position, child is not valid
297
                                if ($substitute->getParent() != $this || $substitute->getPosition() != $position) {
298
                                    $_child = null;
299
                                }
300
                            }
301
                            $children[$position] = $_child;
302
                        }
303
                    } else {
304
                        $children[$position] = $_child;
305
                    }
306
                }
307
            }
308
        }
309
310
        return $children;
311
    }
312
313
    /**
314
     * @return Collection
315
     */
316
    public function getChildrenRaw()
317
    {
318
        return $this->children;
319
    }
320
321
    public function hasChild($position, View $view = null)
322
    {
323
        foreach ($this->getChildren($view) as $child) {
324
            if ($child && $child->getPosition() === $position) {
325
                return true;
326
            }
327
        }
328
329
        return false;
330
    }
331
332
    /**
333
     * @return WidgetMap|null
334
     */
335
    public function getChild($position)
336
    {
337
        $child = null;
338
        foreach ($this->children as $_child) {
339
            if ($_child && $_child->getPosition() == $position) {
340
                $child = $_child;
341
            }
342
        }
343
344
        return $child;
345
    }
346
347
    /**
348
     * @return [WidgetMap]
0 ignored issues
show
Documentation introduced by
The doc-type [WidgetMap] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
349
     */
350
    public function getChilds($position)
351
    {
352
        $childs = [];
353
        foreach ($this->children as $_child) {
354
            if ($_child && $_child->getPosition() == $position) {
355
                $childs[] = $_child;
356
            }
357
        }
358
359
        return $childs;
360
    }
361
362
    /**
363
     * @param mixed $children
364
     */
365
    public function setChildren($children)
366
    {
367
        $this->children = $children;
368
    }
369
370
    /**
371
     * @return void
372
     */
373
    public function removeChildren()
374
    {
375
        foreach ($this->children as $child) {
376
            $this->removeChild($child);
377
        }
378
    }
379
380
    /**
381
     * @param WidgetMap $child
382
     */
383
    public function addChild($child)
384
    {
385
        $this->children->add($child);
386
    }
387
388
    /**
389
     * @param WidgetMap $child
390
     */
391
    public function removeChild($child)
392
    {
393
        $this->children->removeElement($child);
394
    }
395
396
    /**
397
     * @return WidgetMap|null
398
     */
399
    public function getParent()
400
    {
401
        return $this->parent;
402
    }
403
404
    /**
405
     * @param null|WidgetMap $parent
406
     */
407
    public function setParent(WidgetMap $parent = null)
408
    {
409
        if ($this->parent) {
410
            $this->parent->removeChild($this);
411
        }
412
        if ($parent) {
413
            $parent->addChild($this);
414
        }
415
        $this->parent = $parent;
416
    }
417
418
    /**
419
     * @return string
420
     */
421
    public function getPosition()
422
    {
423
        return $this->position;
424
    }
425
426
    /**
427
     * @param string $position
428
     */
429
    public function setPosition($position)
430
    {
431
        $this->position = $position;
432
    }
433
434
    /**
435
     * @return ArrayCollection
436
     */
437
    public function getSubstitutes()
438
    {
439
        return $this->substitutes;
440
    }
441
442
    /**
443
     * @return mixed
444
     */
445
    public function getSubstituteForView(View $view)
446
    {
447
        foreach ($this->substitutes as $substitute) {
448
            if ($substitute->getView() == $view) {
449
                return $substitute;
450
            }
451
        }
452
    }
453
454
    /**
455
     * @param WidgetMap $substitute
456
     */
457
    public function addSubstitute(WidgetMap $substitute)
458
    {
459
        $this->substitutes->add($substitute);
460
    }
461
462
    /**
463
     * @param [WidgetMap] $substitutes
0 ignored issues
show
Documentation introduced by
The doc-type [WidgetMap] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
464
     */
465
    public function setSubstitutes($substitutes)
466
    {
467
        $this->substitutes = $substitutes;
468
    }
469
470
    /**
471
     * @deprecated
472
     *
473
     * @return Widget
474
     */
475
    public function getWidget()
476
    {
477
        return $this->widget;
0 ignored issues
show
Deprecated Code introduced by
The property Victoire\Bundle\WidgetMa...tity\WidgetMap::$widget has been deprecated.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
478
    }
479
480
    /**
481
     * @deprecated
482
     *
483
     * @param Widget $widget
484
     *
485
     * @return WidgetMap
486
     */
487
    public function setWidget(Widget $widget = null)
488
    {
489
        $this->widget = $widget;
0 ignored issues
show
Deprecated Code introduced by
The property Victoire\Bundle\WidgetMa...tity\WidgetMap::$widget has been deprecated.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
490
491
        return $this;
492
    }
493
}
494