Completed
Push — 3.x-dev-kit ( 21be5a )
by
unknown
03:10
created

Post   D

Complexity

Total Complexity 59

Size/Duplication

Total Lines 454
Duplicated Lines 0 %

Coupling/Cohesion

Components 4
Dependencies 3

Importance

Changes 3
Bugs 1 Features 0
Metric Value
wmc 59
c 3
b 1
f 0
lcom 4
cbo 3
dl 0
loc 454
rs 4.5454

49 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A isPublic() 0 8 3
B isCommentable() 0 12 5
A setAuthor() 0 4 1
A getAuthor() 0 4 1
A setCollection() 0 4 1
A getCollection() 0 4 1
A setContentFormatter() 0 4 1
A getContentFormatter() 0 4 1
A setRawContent() 0 4 1
A getRawContent() 0 4 1
A __toString() 0 4 2
A setTitle() 0 6 1
A getTitle() 0 4 1
A setAbstract() 0 4 1
A getAbstract() 0 4 1
A setContent() 0 4 1
A getContent() 0 4 1
A setEnabled() 0 4 1
A getEnabled() 0 4 1
A setSlug() 0 4 1
A getSlug() 0 4 1
A setPublicationDateStart() 0 4 1
A getPublicationDateStart() 0 4 1
A setCreatedAt() 0 4 1
A getCreatedAt() 0 4 1
A setUpdatedAt() 0 4 1
A getUpdatedAt() 0 4 1
A addComments() 0 5 1
A setComments() 0 8 2
A getComments() 0 4 1
A addTags() 0 4 1
A getTags() 0 4 1
A setTags() 0 4 1
A prePersist() 0 9 2
A preUpdate() 0 8 2
A getYear() 0 4 1
A getMonth() 0 4 1
A getDay() 0 4 1
A setCommentsEnabled() 0 4 1
A getCommentsEnabled() 0 4 1
A setCommentsCloseAt() 0 4 1
A getCommentsCloseAt() 0 4 1
A setCommentsDefaultStatus() 0 4 1
A getCommentsDefaultStatus() 0 4 1
A setCommentsCount() 0 4 1
A getCommentsCount() 0 4 1
A setImage() 0 4 1
A getImage() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like Post 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 Post, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/*
4
 * This file is part of the Sonata Project package.
5
 *
6
 * (c) Thomas Rabaix <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Sonata\NewsBundle\Model;
13
14
use Sonata\ClassificationBundle\Model\CollectionInterface;
15
use Sonata\ClassificationBundle\Model\Tag;
16
use Sonata\ClassificationBundle\Model\TagInterface;
17
18
abstract class Post implements PostInterface
19
{
20
    protected $title;
21
22
    protected $slug;
23
24
    protected $abstract;
25
26
    protected $content;
27
28
    protected $rawContent;
29
30
    protected $contentFormatter;
31
32
    protected $tags;
33
34
    protected $comments;
35
36
    protected $enabled;
37
38
    protected $publicationDateStart;
39
40
    protected $createdAt;
41
42
    protected $updatedAt;
43
44
    protected $commentsEnabled = true;
45
46
    protected $commentsCloseAt;
47
48
    protected $commentsDefaultStatus;
49
50
    protected $commentsCount = 0;
51
52
    protected $author;
53
54
    protected $image;
55
56
    protected $collection;
57
58
    /**
59
     * {@inheritdoc}
60
     */
61
    public function __construct()
62
    {
63
        $this->setPublicationDateStart(new \DateTime());
64
    }
65
66
    /**
67
     * {@inheritdoc}
68
     */
69
    public function __toString()
70
    {
71
        return $this->getTitle() ?: 'n/a';
72
    }
73
74
    /**
75
     * {@inheritdoc}
76
     */
77
    public function setTitle($title)
78
    {
79
        $this->title = $title;
80
81
        $this->setSlug(Tag::slugify($title));
82
    }
83
84
    /**
85
     * {@inheritdoc}
86
     */
87
    public function getTitle()
88
    {
89
        return $this->title;
90
    }
91
92
    /**
93
     * {@inheritdoc}
94
     */
95
    public function setAbstract($abstract)
96
    {
97
        $this->abstract = $abstract;
98
    }
99
100
    /**
101
     * {@inheritdoc}
102
     */
103
    public function getAbstract()
104
    {
105
        return $this->abstract;
106
    }
107
108
    /**
109
     * {@inheritdoc}
110
     */
111
    public function setContent($content)
112
    {
113
        $this->content = $content;
114
    }
115
116
    /**
117
     * {@inheritdoc}
118
     */
119
    public function getContent()
120
    {
121
        return $this->content;
122
    }
123
124
    /**
125
     * {@inheritdoc}
126
     */
127
    public function setEnabled($enabled)
128
    {
129
        $this->enabled = $enabled;
130
    }
131
132
    /**
133
     * {@inheritdoc}
134
     */
135
    public function getEnabled()
136
    {
137
        return $this->enabled;
138
    }
139
140
    /**
141
     * {@inheritdoc}
142
     */
143
    public function setSlug($slug)
144
    {
145
        $this->slug = $slug;
146
    }
147
148
    /**
149
     * {@inheritdoc}
150
     */
151
    public function getSlug()
152
    {
153
        return $this->slug;
154
    }
155
156
    /**
157
     * {@inheritdoc}
158
     */
159
    public function setPublicationDateStart(\DateTime $publicationDateStart = null)
160
    {
161
        $this->publicationDateStart = $publicationDateStart;
162
    }
163
164
    /**
165
     * {@inheritdoc}
166
     */
167
    public function getPublicationDateStart()
168
    {
169
        return $this->publicationDateStart;
170
    }
171
172
    /**
173
     * {@inheritdoc}
174
     */
175
    public function setCreatedAt(\DateTime $createdAt = null)
176
    {
177
        $this->createdAt = $createdAt;
178
    }
179
180
    /**
181
     * {@inheritdoc}
182
     */
183
    public function getCreatedAt()
184
    {
185
        return $this->createdAt;
186
    }
187
188
    /**
189
     * {@inheritdoc}
190
     */
191
    public function setUpdatedAt(\DateTime $updatedAt = null)
192
    {
193
        $this->updatedAt = $updatedAt;
194
    }
195
196
    /**
197
     * {@inheritdoc}
198
     */
199
    public function getUpdatedAt()
200
    {
201
        return $this->updatedAt;
202
    }
203
204
    /**
205
     * {@inheritdoc}
206
     */
207
    public function addComments(CommentInterface $comment)
208
    {
209
        $this->comments[] = $comment;
210
        $comment->setPost($this);
211
    }
212
213
    /**
214
     * {@inheritdoc}
215
     */
216
    public function setComments($comments)
217
    {
218
        $this->comments = new \Doctrine\Common\Collections\ArrayCollection();
219
220
        foreach ($this->comments as $comment) {
221
            $this->addComments($comment);
222
        }
223
    }
224
225
    /**
226
     * {@inheritdoc}
227
     */
228
    public function getComments()
229
    {
230
        return $this->comments;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->comments; (Doctrine\Common\Collections\ArrayCollection) is incompatible with the return type declared by the interface Sonata\NewsBundle\Model\PostInterface::getComments of type array.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
231
    }
232
233
    /**
234
     * {@inheritdoc}
235
     */
236
    public function addTags(TagInterface $tags)
237
    {
238
        $this->tags[] = $tags;
239
    }
240
241
    /**
242
     * {@inheritdoc}
243
     */
244
    public function getTags()
245
    {
246
        return $this->tags;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->tags; (Doctrine\Common\Collections\ArrayCollection) is incompatible with the return type declared by the interface Sonata\NewsBundle\Model\PostInterface::getTags of type array.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
247
    }
248
249
    /**
250
     * {@inheritdoc}
251
     */
252
    public function setTags($tags)
253
    {
254
        $this->tags = $tags;
255
    }
256
257
    public function prePersist()
258
    {
259
        if (!$this->getPublicationDateStart()) {
260
            $this->setPublicationDateStart(new \DateTime());
261
        }
262
263
        $this->setCreatedAt(new \DateTime());
264
        $this->setUpdatedAt(new \DateTime());
265
    }
266
267
    public function preUpdate()
268
    {
269
        if (!$this->getPublicationDateStart()) {
270
            $this->setPublicationDateStart(new \DateTime());
271
        }
272
273
        $this->setUpdatedAt(new \DateTime());
274
    }
275
276
    /**
277
     * {@inheritdoc}
278
     */
279
    public function getYear()
280
    {
281
        return $this->getPublicationDateStart()->format('Y');
282
    }
283
284
    /**
285
     * {@inheritdoc}
286
     */
287
    public function getMonth()
288
    {
289
        return $this->getPublicationDateStart()->format('m');
290
    }
291
292
    /**
293
     * {@inheritdoc}
294
     */
295
    public function getDay()
296
    {
297
        return $this->getPublicationDateStart()->format('d');
298
    }
299
300
    /**
301
     * {@inheritdoc}
302
     */
303
    public function setCommentsEnabled($commentsEnabled)
304
    {
305
        $this->commentsEnabled = $commentsEnabled;
306
    }
307
308
    /**
309
     * {@inheritdoc}
310
     */
311
    public function getCommentsEnabled()
312
    {
313
        return $this->commentsEnabled;
314
    }
315
316
    /**
317
     * {@inheritdoc}
318
     */
319
    public function setCommentsCloseAt(\DateTime $commentsCloseAt = null)
320
    {
321
        $this->commentsCloseAt = $commentsCloseAt;
322
    }
323
324
    /**
325
     * {@inheritdoc}
326
     */
327
    public function getCommentsCloseAt()
328
    {
329
        return $this->commentsCloseAt;
330
    }
331
332
    /**
333
     * {@inheritdoc}
334
     */
335
    public function setCommentsDefaultStatus($commentsDefaultStatus)
336
    {
337
        $this->commentsDefaultStatus = $commentsDefaultStatus;
338
    }
339
340
    /**
341
     * {@inheritdoc}
342
     */
343
    public function getCommentsDefaultStatus()
344
    {
345
        return $this->commentsDefaultStatus;
346
    }
347
348
    /**
349
     * {@inheritdoc}
350
     */
351
    public function setCommentsCount($commentsCount)
352
    {
353
        $this->commentsCount = $commentsCount;
354
    }
355
356
    /**
357
     * {@inheritdoc}
358
     */
359
    public function getCommentsCount()
360
    {
361
        return $this->commentsCount;
362
    }
363
364
    /**
365
     * {@inheritdoc}
366
     */
367
    public function isCommentable()
368
    {
369
        if (!$this->getCommentsEnabled() || !$this->getEnabled()) {
370
            return false;
371
        }
372
373
        if ($this->getCommentsCloseAt() instanceof \DateTime) {
374
            return $this->getCommentsCloseAt()->diff(new \DateTime())->invert == 1 ? true : false;
375
        }
376
377
        return true;
378
    }
379
380
    /**
381
     * {@inheritdoc}
382
     */
383
    public function isPublic()
384
    {
385
        if (!$this->getEnabled()) {
386
            return false;
387
        }
388
389
        return $this->getPublicationDateStart()->diff(new \DateTime())->invert == 0 ? true : false;
390
    }
391
392
    /**
393
     * {@inheritdoc}
394
     */
395
    public function setAuthor($author)
396
    {
397
        $this->author = $author;
398
    }
399
400
    /**
401
     * {@inheritdoc}
402
     */
403
    public function getAuthor()
404
    {
405
        return $this->author;
406
    }
407
408
    /**
409
     * {@inheritdoc}
410
     */
411
    public function setImage($image)
412
    {
413
        $this->image = $image;
414
    }
415
416
    /**
417
     * {@inheritdoc}
418
     */
419
    public function getImage()
420
    {
421
        return $this->image;
422
    }
423
424
    /**
425
     * {@inheritdoc}
426
     */
427
    public function setCollection(CollectionInterface $collection = null)
428
    {
429
        $this->collection = $collection;
430
    }
431
432
    /**
433
     * {@inheritdoc}
434
     */
435
    public function getCollection()
436
    {
437
        return $this->collection;
438
    }
439
440
    /**
441
     * @param $contentFormatter
442
     */
443
    public function setContentFormatter($contentFormatter)
444
    {
445
        $this->contentFormatter = $contentFormatter;
446
    }
447
448
    /**
449
     * {@inheritdoc}
450
     */
451
    public function getContentFormatter()
452
    {
453
        return $this->contentFormatter;
454
    }
455
456
    /**
457
     * {@inheritdoc}
458
     */
459
    public function setRawContent($rawContent)
460
    {
461
        $this->rawContent = $rawContent;
462
    }
463
464
    /**
465
     * {@inheritdoc}
466
     */
467
    public function getRawContent()
468
    {
469
        return $this->rawContent;
470
    }
471
}
472