Card   F
last analyzed

Complexity

Total Complexity 108

Size/Duplication

Total Lines 824
Duplicated Lines 7.77 %

Coupling/Cohesion

Components 1
Dependencies 11

Importance

Changes 0
Metric Value
wmc 108
lcom 1
cbo 11
dl 64
loc 824
rs 3.5555
c 0
b 0
f 0

70 Methods

Rating   Name   Duplication   Size   Complexity  
A getShortId() 0 4 1
A setName() 0 6 1
A getName() 0 4 1
A setDescription() 0 6 1
A getDescription() 0 4 1
A getDescriptionData() 0 4 1
A getUrl() 0 4 1
A getShortUrl() 0 4 1
A getShortLink() 0 4 1
A setPosition() 0 6 1
A getPosition() 0 4 1
A setDueDate() 0 6 1
A getDueDate() 0 8 2
A setEmail() 0 6 1
A getEmail() 0 4 1
A setClosed() 0 6 1
A isClosed() 0 4 1
A setSubscribed() 0 6 1
A isSubscribed() 0 4 1
A setCheckItemStates() 0 6 1
A getCheckItemStates() 0 4 1
A setBoardId() 0 6 1
A getBoardId() 0 4 1
A setBoard() 0 4 1
A getBoard() 0 4 1
A setListId() 0 6 1
A getListId() 0 4 1
A setList() 0 4 1
A getList() 0 4 1
A moveToList() 0 17 3
A setChecklistIds() 0 6 1
A getChecklistIds() 0 4 1
A setChecklists() 0 10 2
A getChecklists() 0 12 2
A getChecklist() 0 14 3
A hasChecklist() 0 14 4
B addChecklist() 0 32 5
B removeChecklist() 0 23 6
A setMemberIds() 0 6 1
A getMemberIds() 0 4 1
A hasMember() 0 4 1
A addMember() 14 14 2
A removeMember() 18 18 4
A setMembers() 0 10 2
A getMembers() 0 10 2
A setMembersVotedIds() 0 6 1
A getMembersVotedIds() 0 4 1
A hasMemberVoted() 0 4 1
A addMemberVoted() 14 14 2
A removeMemberVoted() 18 18 4
A setMembersVoted() 0 10 2
A getMembersVoted() 0 10 2
A setAttachmentCoverId() 0 6 1
A getAttachmentCoverId() 0 4 1
A setManualCoverAttachment() 0 6 1
A getManualCoverAttachment() 0 4 1
A setLabels() 0 6 1
A getLabels() 0 4 1
A getLabelColors() 0 6 1
A hasLabel() 0 4 1
A addLabel() 0 14 2
A removeLabel() 0 18 4
A setBadges() 0 6 1
A getBadges() 0 4 1
A getDateOfLastActivity() 0 4 1
A getActions() 0 4 1
A addComment() 0 6 1
A removeComment() 0 6 1
A preSave() 0 7 2
A postSave() 0 12 3

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

1
<?php
2
3
namespace Trello\Model;
4
5
use Trello\Events;
6
use Trello\Exception\InvalidArgumentException;
7
use Trello\Exception\RuntimeException;
8
9
/**
10
 * @codeCoverageIgnore
11
 */
12
class Card extends AbstractObject implements CardInterface
13
{
14
    protected $apiName = 'card';
15
16
    protected $loadParams = array(
17
        'fields'          => 'all',
18
        'board'           => true,
19
        'list'            => true,
20
        'stickers'        => true,
21
        'members'         => true,
22
        'membersVoted'    => true,
23
        'attachments'     => true,
24
        'checklists'      => 'all',
25
        'checkItemStates' => true,
26
        'actions'         => Events::CARD_COMMENT,
27
    );
28
29
    protected $newChecklists = array();
30
    protected $newComments = array();
31
    protected $commentsToBeRemoved = array();
32
33
    /**
34
     * {@inheritdoc}
35
     */
36
    public function getShortId()
37
    {
38
        return $this->data['idShort'];
39
    }
40
41
    /**
42
     * {@inheritdoc}
43
     */
44
    public function setName($name)
45
    {
46
        $this->data['name'] = $name;
47
48
        return $this;
49
    }
50
51
    /**
52
     * {@inheritdoc}
53
     */
54
    public function getName()
55
    {
56
        return $this->data['name'];
57
    }
58
59
    /**
60
     * {@inheritdoc}
61
     */
62
    public function setDescription($desc)
63
    {
64
        $this->data['desc'] = $desc;
65
66
        return $this;
67
    }
68
69
    /**
70
     * {@inheritdoc}
71
     */
72
    public function getDescription()
73
    {
74
        return $this->data['desc'];
75
    }
76
77
    /**
78
     * {@inheritdoc}
79
     */
80
    public function getDescriptionData()
81
    {
82
        return $this->data['descData'];
83
    }
84
85
    /**
86
     * {@inheritdoc}
87
     */
88
    public function getUrl()
89
    {
90
        return $this->data['url'];
91
    }
92
93
    /**
94
     * {@inheritdoc}
95
     */
96
    public function getShortUrl()
97
    {
98
        return $this->data['shortUrl'];
99
    }
100
101
    /**
102
     * {@inheritdoc}
103
     */
104
    public function getShortLink()
105
    {
106
        return $this->data['shortLink'];
107
    }
108
109
    /**
110
     * {@inheritdoc}
111
     */
112
    public function setPosition($pos)
113
    {
114
        $this->data['pos'] = $pos;
115
116
        return $this;
117
    }
118
119
    /**
120
     * {@inheritdoc}
121
     */
122
    public function getPosition()
123
    {
124
        return $this->data['pos'];
125
    }
126
127
    /**
128
     * {@inheritdoc}
129
     */
130
    public function setDueDate(\DateTime $due = null)
131
    {
132
        $this->data['due'] = $due;
133
134
        return $this;
135
    }
136
137
    /**
138
     * {@inheritdoc}
139
     */
140
    public function getDueDate()
141
    {
142
        if ($this->data['due'] instanceof \DateTime) {
143
            return $this->data['due'];
144
        }
145
146
        return new \DateTime($this->data['due']);
147
    }
148
149
    /**
150
     * {@inheritdoc}
151
     */
152
    public function setEmail($email)
153
    {
154
        $this->data['email'] = $email;
155
156
        return $this;
157
    }
158
159
    /**
160
     * {@inheritdoc}
161
     */
162
    public function getEmail()
163
    {
164
        return $this->data['email'];
165
    }
166
167
    /**
168
     * {@inheritdoc}
169
     */
170
    public function setClosed($closed)
171
    {
172
        $this->data['closed'] = $closed;
173
174
        return $this;
175
    }
176
177
    /**
178
     * {@inheritdoc}
179
     */
180
    public function isClosed()
181
    {
182
        return $this->data['closed'];
183
    }
184
185
    /**
186
     * {@inheritdoc}
187
     */
188
    public function setSubscribed($subscribed)
189
    {
190
        $this->data['subscribed'] = $subscribed;
191
192
        return $this;
193
    }
194
195
    /**
196
     * {@inheritdoc}
197
     */
198
    public function isSubscribed()
199
    {
200
        return $this->data['subscribed'];
201
    }
202
203
    /**
204
     * {@inheritdoc}
205
     */
206
    public function setCheckItemStates(array $checkItemStates)
207
    {
208
        $this->data['checkItemStates'] = $checkItemStates;
209
210
        return $this;
211
    }
212
213
    /**
214
     * {@inheritdoc}
215
     */
216
    public function getCheckItemStates()
217
    {
218
        return $this->data['checkItemStates'];
219
    }
220
221
    /**
222
     * {@inheritdoc}
223
     */
224
    public function setBoardId($boardId)
225
    {
226
        $this->data['idBoard'] = $boardId;
227
228
        return $this;
229
    }
230
231
    /**
232
     * {@inheritdoc}
233
     */
234
    public function getBoardId()
235
    {
236
        return $this->data['idBoard'];
237
    }
238
239
    /**
240
     * {@inheritdoc}
241
     */
242
    public function setBoard(BoardInterface $board)
243
    {
244
        return $this->setBoardId($board->getId());
245
    }
246
247
    /**
248
     * {@inheritdoc}
249
     */
250
    public function getBoard()
251
    {
252
        return new Board($this->client, $this->getBoardId());
253
    }
254
255
    /**
256
     * {@inheritdoc}
257
     */
258
    public function setListId($listId)
259
    {
260
        $this->data['idList'] = $listId;
261
262
        return $this;
263
    }
264
265
    /**
266
     * {@inheritdoc}
267
     */
268
    public function getListId()
269
    {
270
        return $this->data['idList'];
271
    }
272
273
    /**
274
     * {@inheritdoc}
275
     */
276
    public function setList(CardlistInterface $list)
277
    {
278
        return $this->setListId($list->getId());
279
    }
280
281
    /**
282
     * {@inheritdoc}
283
     */
284
    public function getList()
285
    {
286
        return new Cardlist($this->client, $this->getListId());
287
    }
288
289
    public function moveToList($name)
290
    {
291
        foreach ($this->getBoard()->getLists() as $list) {
292
            if ($list->getName() === $name) {
293
                $this->setList($list);
294
295
                return $this;
296
            }
297
        }
298
299
        throw new InvalidArgumentException(sprintf(
300
            'Card "%s" could not be moved to list "%s" as no list with that name exists on the board named "%s"',
301
            $this->getName(),
302
            $name,
303
            $this->getBoard()->getName()
304
        ));
305
    }
306
307
    /**
308
     * {@inheritdoc}
309
     */
310
    public function setChecklistIds(array $checklistIds)
311
    {
312
        $this->data['idChecklists'] = $checklistIds;
313
314
        return $this;
315
    }
316
317
    /**
318
     * {@inheritdoc}
319
     */
320
    public function getChecklistIds()
321
    {
322
        return $this->data['idChecklists'];
323
    }
324
325
    /**
326
     * {@inheritdoc}
327
     */
328
    public function setChecklists(array $checklists)
329
    {
330
        $ids = array();
331
332
        foreach ($checklists as $checklist) {
333
            $ids[] = $checklist->getId();
334
        }
335
336
        return $this->setChecklistIds($ids);
337
    }
338
339
    /**
340
     * {@inheritdoc}
341
     */
342
    public function getChecklists()
343
    {
344
        $checklists = array();
345
346
        foreach ($this->getChecklistIds() as $id) {
347
            $checklists[] = new Checklist($this->client, $id);
348
        }
349
350
        $checklists = array_merge($checklists, $this->newChecklists);
351
352
        return $checklists;
353
    }
354
355
    /**
356
     * {@inheritdoc}
357
     * @param string $name
358
     */
359
    public function getChecklist($name)
360
    {
361
        foreach ($this->getChecklists() as $checklist) {
362
            if ($checklist->getName() === $name) {
363
                return $checklist;
364
            }
365
        }
366
367
        throw new InvalidArgumentException(sprintf(
368
            'There is no checklist named "%s"  on this card (%s).',
369
            $name,
370
            $this->getName()
371
        ));
372
    }
373
374
    /**
375
     * {@inheritdoc}
376
     */
377
    public function hasChecklist($checklist)
378
    {
379
        if ($checklist instanceof ChecklistInterface) {
380
            return in_array($checklist->getId(), $this->data['idChecklists']);
381
        }
382
383
        foreach ($this->getChecklists() as $existingList) {
384
            if ($existingList->getName() === $checklist) {
385
                return true;
386
            }
387
        }
388
389
        return false;
390
    }
391
392
    /**
393
     * {@inheritdoc}
394
     */
395
    public function addChecklist($checklist)
396
    {
397
        if (!$this->id) {
398
            throw new RuntimeException("You can't add checklists to a new card, you have to save it first.");
399
        }
400
401
        if (!$checklist instanceof ChecklistInterface) {
402
            $name = $checklist;
403
            $checklist = new Checklist($this->client);
404
            $checklist->setName($name);
405
        }
406
407
        $checklist->setCard($this);
408
409
        if (!$checklist->getId()) {
410
            $this->newChecklists[] = $checklist;
411
412
            return $this;
413
        }
414
415
        if ($this->hasChecklist($checklist)) {
416
            throw new InvalidArgumentException(sprintf(
417
                'Checklist %s is already on this card (%s).',
418
                $checklist->getName(),
419
                $this->getName()
420
            ));
421
        }
422
423
        $this->data['idChecklists'][] = $checklist->getId();
424
425
        return $this;
426
    }
427
428
    /**
429
     * {@inheritdoc}
430
     */
431
    public function removeChecklist($checklist)
432
    {
433
        if (!$this->hasChecklist($checklist)) {
434
            throw new InvalidArgumentException(sprintf(
435
                "Checklist %s is not on this card (%s), so you can't remove it.",
436
                is_object($checklist) ? $checklist->getName() : $checklist,
437
                $this->getName()
438
            ));
439
        }
440
441
        if (!$checklist instanceof ChecklistInterface) {
442
            $checklist = $this->getChecklist($checklist);
443
        }
444
445
        foreach ($this->data['idChecklists'] as $key => $checklistId) {
446
            if ($checklistId === $checklist->getId()) {
447
                unset($this->data['idChecklists'][$key]);
448
                $checklist->remove();
449
            }
450
        }
451
452
        return $this;
453
    }
454
455
    /**
456
     * {@inheritdoc}
457
     */
458
    public function setMemberIds(array $memberIds)
459
    {
460
        $this->data['idMembers'] = $memberIds;
461
462
        return $this;
463
    }
464
465
    /**
466
     * {@inheritdoc}
467
     */
468
    public function getMemberIds()
469
    {
470
        return $this->data['idMembers'];
471
    }
472
473
    /**
474
     * {@inheritdoc}
475
     */
476
    public function hasMember(MemberInterface $member)
477
    {
478
        return in_array($member->getId(), $this->data['idMembers']);
479
    }
480
481
    /**
482
     * {@inheritdoc}
483
     */
484 View Code Duplication
    public function addMember(MemberInterface $member)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
485
    {
486
        if ($this->hasMember($member)) {
487
            throw new InvalidArgumentException(sprintf(
488
                'Member %s is already on this card (%s).',
489
                $member->getFullName(),
490
                $this->getName()
491
            ));
492
        }
493
494
        $this->data['idMembers'][] = $member->getId();
495
496
        return $this;
497
    }
498
499
    /**
500
     * {@inheritdoc}
501
     */
502 View Code Duplication
    public function removeMember(MemberInterface $member)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
503
    {
504
        if (!$this->hasMember($member)) {
505
            throw new InvalidArgumentException(sprintf(
506
                "Member %s is not on this card (%s), so you can't remove him.",
507
                $member->getFullName(),
508
                $this->getName()
509
            ));
510
        }
511
512
        foreach ($this->data['idMembers'] as $key => $memberArray) {
513
            if ($memberArray['id'] === $member->getId()) {
514
                unset($this->data['idMembers'][$key]);
515
            }
516
        }
517
518
        return $this;
519
    }
520
521
    /**
522
     * {@inheritdoc}
523
     */
524
    public function setMembers(array $members)
525
    {
526
        $ids = array();
527
528
        foreach ($members as $member) {
529
            $ids[] = $member->getId();
530
        }
531
532
        return $this->setMemberIds($ids);
533
    }
534
535
    /**
536
     * {@inheritdoc}
537
     */
538
    public function getMembers()
539
    {
540
        $members = array();
541
542
        foreach ($this->getMemberIds() as $id) {
543
            $members[] = new Member($this->client, $id);
544
        }
545
546
        return $members;
547
    }
548
549
    /**
550
     * {@inheritdoc}
551
     */
552
    public function setMembersVotedIds(array $membersVotedIds)
553
    {
554
        $this->data['idMembersVoted'] = $membersVotedIds;
555
556
        return $this;
557
    }
558
559
    /**
560
     * {@inheritdoc}
561
     */
562
    public function getMembersVotedIds()
563
    {
564
        return $this->data['idMembersVoted'];
565
    }
566
567
    /**
568
     * {@inheritdoc}
569
     */
570
    public function hasMemberVoted(MemberInterface $member)
571
    {
572
        return in_array($member->getId(), $this->data['idMembersVoted']);
573
    }
574
575
    /**
576
     * {@inheritdoc}
577
     */
578 View Code Duplication
    public function addMemberVoted(MemberInterface $member)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
579
    {
580
        if ($this->hasMemberVoted($member)) {
581
            throw new InvalidArgumentException(sprintf(
582
                'Member %s has already voted this card (%s).',
583
                $member->getFullName(),
584
                $this->getName()
585
            ));
586
        }
587
588
        $this->data['idMembersVoted'][] = $member->getId();
589
590
        return $this;
591
    }
592
593
    /**
594
     * {@inheritdoc}
595
     */
596 View Code Duplication
    public function removeMemberVoted(MemberInterface $member)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
597
    {
598
        if (!$this->hasMemberVoted($member)) {
599
            throw new InvalidArgumentException(sprintf(
600
                "Member %s hasn't voted this card (%s), so you can't remove his vote.",
601
                $member->getFullName(),
602
                $this->getName()
603
            ));
604
        }
605
606
        foreach ($this->data['idMembersVoted'] as $key => $memberArray) {
607
            if ($memberArray['id'] === $member->getId()) {
608
                unset($this->data['idMembersVoted'][$key]);
609
            }
610
        }
611
612
        return $this;
613
    }
614
615
    /**
616
     * {@inheritdoc}
617
     */
618
    public function setMembersVoted(array $members)
619
    {
620
        $ids = array();
621
622
        foreach ($members as $member) {
623
            $ids[] = $member->getId();
624
        }
625
626
        return $this->setMembersVotedIds($ids);
627
    }
628
629
    /**
630
     * {@inheritdoc}
631
     */
632
    public function getMembersVoted()
633
    {
634
        $members = array();
635
636
        foreach ($this->getMembersVotedIds() as $id) {
637
            $members[] = new Member($this->client, $id);
638
        }
639
640
        return $members;
641
    }
642
643
    /**
644
     * {@inheritdoc}
645
     */
646
    public function setAttachmentCoverId($attachmentCoverId)
647
    {
648
        $this->data['idAttachmentCover'] = $attachmentCoverId;
649
650
        return $this;
651
    }
652
653
    /**
654
     * {@inheritdoc}
655
     */
656
    public function getAttachmentCoverId()
657
    {
658
        return $this->data['idAttachmentCover'];
659
    }
660
661
    /**
662
     * {@inheritdoc}
663
     */
664
    public function setManualCoverAttachment($coverAttachment)
665
    {
666
        $this->data['manualCoverAttachment'] = $coverAttachment;
667
668
        return $this;
669
    }
670
671
    /**
672
     * {@inheritdoc}
673
     */
674
    public function getManualCoverAttachment()
675
    {
676
        return $this->data['manualCoverAttachment'];
677
    }
678
679
    /**
680
     * {@inheritdoc}
681
     */
682
    public function setLabels(array $labels)
683
    {
684
        $this->data['labels'] = $labels;
685
686
        return $this;
687
    }
688
689
    /**
690
     * {@inheritdoc}
691
     */
692
    public function getLabels()
693
    {
694
        return $this->data['labels'];
695
    }
696
697
    /**
698
     * {@inheritdoc}
699
     */
700
    public function getLabelColors()
701
    {
702
        return array_map(function ($label) {
703
            return $label['color'];
704
        }, $this->data['labels']);
705
    }
706
707
    /**
708
     * {@inheritdoc}
709
     */
710
    public function hasLabel($color)
711
    {
712
        return in_array($color, $this->getLabelColors());
713
    }
714
715
    /**
716
     * {@inheritdoc}
717
     */
718
    public function addLabel($color)
719
    {
720
        if ($this->hasLabel($color)) {
721
            throw new InvalidArgumentException(sprintf(
722
                'Card %s already has the %s label.',
723
                $this->getName(),
724
                $color
725
            ));
726
        }
727
728
        $this->data['labels'][] = array('color' => $color);
729
730
        return $this;
731
    }
732
733
    /**
734
     * {@inheritdoc}
735
     */
736
    public function removeLabel($color)
737
    {
738
        if (!$this->hasLabel($color)) {
739
            throw new InvalidArgumentException(sprintf(
740
                "Can't remove the %s label because card %s doesn't have it.",
741
                $color,
742
                $this->getName()
743
            ));
744
        }
745
746
        foreach ($this->data['labels'] as $key => $label) {
747
            if ($label['color'] === $color) {
748
                unset($this->data['labels'][$key]);
749
            }
750
        }
751
752
        return $this;
753
    }
754
755
    /**
756
     * {@inheritdoc}
757
     */
758
    public function setBadges(array $badges)
759
    {
760
        $this->data['badges'] = $badges;
761
762
        return $this;
763
    }
764
765
    /**
766
     * {@inheritdoc}
767
     */
768
    public function getBadges()
769
    {
770
        return $this->data['badges'];
771
    }
772
773
    /**
774
     * {@inheritdoc}
775
     */
776
    public function getDateOfLastActivity()
777
    {
778
        return new \DateTime($this->data['dateLastActivity']);
779
    }
780
781
    /**
782
     * {@inheritdoc}
783
     */
784
    public function getActions($params = array())
785
    {
786
        return $this->api->actions()->all($this->id, $params);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Trello\Api\ApiInterface as the method actions() does only exist in the following implementations of said interface: Trello\Api\Board, Trello\Api\Card, Trello\Api\Cardlist, Trello\Api\Member.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
787
    }
788
789
    /**
790
     * {@inheritdoc}
791
     */
792
    public function addComment($text)
793
    {
794
        $this->newComments[] = $text;
795
796
        return $this;
797
    }
798
799
    /**
800
     * {@inheritdoc}
801
     */
802
    public function removeComment($commentId)
803
    {
804
        $this->commentsToBeRemoved[] = $commentId;
805
806
        return $this;
807
    }
808
809
    /**
810
     * {@inheritdoc}
811
     */
812
    protected function preSave()
813
    {
814
        foreach ($this->newChecklists as $checklist) {
815
            $checklist->save();
816
            $this->addChecklist($checklist);
817
        }
818
    }
819
820
    /**
821
     * {@inheritdoc}
822
     */
823
    protected function postSave()
824
    {
825
        foreach ($this->newComments as $key => $text) {
826
            $this->api->actions()->addComment($this->id, $text);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Trello\Api\ApiInterface as the method actions() does only exist in the following implementations of said interface: Trello\Api\Board, Trello\Api\Card, Trello\Api\Cardlist, Trello\Api\Member.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
827
            unset($this->newComments[$key]);
828
        }
829
830
        foreach ($this->commentsToBeRemoved as $key => $commentId) {
831
            $this->api->actions()->removeComment($this->id, $commentId);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Trello\Api\ApiInterface as the method actions() does only exist in the following implementations of said interface: Trello\Api\Board, Trello\Api\Card, Trello\Api\Cardlist, Trello\Api\Member.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
832
            unset($this->commentsToBeRemoved[$key]);
833
        }
834
    }
835
}
836