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 classes like Blog 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 Blog, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
41 | class Blog extends Page implements PermissionProvider |
||
42 | { |
||
43 | /** |
||
44 | * Permission for user management. |
||
45 | * |
||
46 | * @var string |
||
47 | */ |
||
48 | const MANAGE_USERS = 'BLOG_MANAGE_USERS'; |
||
49 | |||
50 | /** |
||
51 | * If true, users assigned as editor, writer, or contributor will be automatically granted |
||
52 | * CMS_ACCESS_CMSMain permission. If false, only users with this permission already may be |
||
53 | * assigned. |
||
54 | * |
||
55 | * @config |
||
56 | * |
||
57 | * @var boolean |
||
58 | */ |
||
59 | private static $grant_user_access = true; |
||
60 | |||
61 | /** |
||
62 | * Permission to either require, or grant to users assigned to work on this blog. |
||
63 | * |
||
64 | * @config |
||
65 | * |
||
66 | * @var string |
||
67 | */ |
||
68 | private static $grant_user_permission = 'CMS_ACCESS_CMSMain'; |
||
69 | |||
70 | /** |
||
71 | * Group code to assign newly granted users to. |
||
72 | * |
||
73 | * @config |
||
74 | * |
||
75 | * @var string |
||
76 | */ |
||
77 | private static $grant_user_group = 'blog-users'; |
||
78 | |||
79 | /** |
||
80 | * {@inheritDoc} |
||
81 | * @var string |
||
82 | */ |
||
83 | private static $table_name = 'Blog'; |
||
84 | |||
85 | /** |
||
86 | * @var array |
||
87 | */ |
||
88 | private static $db = [ |
||
89 | 'PostsPerPage' => 'Int', |
||
90 | ]; |
||
91 | |||
92 | /** |
||
93 | * @var array |
||
94 | */ |
||
95 | private static $many_many = [ |
||
96 | 'Editors' => Member::class, |
||
97 | 'Writers' => Member::class, |
||
98 | 'Contributors' => Member::class, |
||
99 | ]; |
||
100 | |||
101 | /** |
||
102 | * @var array |
||
103 | */ |
||
104 | private static $allowed_children = [ |
||
105 | BlogPost::class, |
||
106 | ]; |
||
107 | |||
108 | /** |
||
109 | * @var array |
||
110 | */ |
||
111 | private static $extensions = [ |
||
112 | BlogFilter::class, |
||
113 | ]; |
||
114 | |||
115 | /** |
||
116 | * @var array |
||
117 | */ |
||
118 | private static $defaults = [ |
||
119 | 'ProvideComments' => false, |
||
120 | 'PostsPerPage' => 10 |
||
121 | ]; |
||
122 | |||
123 | /** |
||
124 | * @var string |
||
125 | */ |
||
126 | private static $description = 'Adds a blog to your website.'; |
||
127 | |||
128 | private static $icon_class = 'font-icon-p-posts'; |
||
129 | |||
130 | /** |
||
131 | * Gets the list of all tags attached to this blog |
||
132 | * |
||
133 | * @param bool $hideEmpty Set to false to include tags without posts |
||
134 | * @return DataList|BlogTag[] |
||
135 | */ |
||
136 | View Code Duplication | public function Tags($hideEmpty = true) |
|
150 | |||
151 | /** |
||
152 | * Gets the list of all categories attached to this blog |
||
153 | * |
||
154 | * @param bool $hideEmpty Set to false to include categories without posts |
||
155 | * @return DataList|BlogCategory[] |
||
156 | */ |
||
157 | View Code Duplication | public function Categories($hideEmpty = true) |
|
171 | |||
172 | /** |
||
173 | * {@inheritdoc} |
||
174 | */ |
||
175 | public function getCMSFields() |
||
230 | |||
231 | /** |
||
232 | * Adds CMS related css and js overrides |
||
233 | */ |
||
234 | protected function addCMSRequirements() |
||
239 | |||
240 | /** |
||
241 | * {@inheritdoc} |
||
242 | */ |
||
243 | public function canEdit($member = null) |
||
253 | |||
254 | /** |
||
255 | * @param null|int|Member $member |
||
256 | * |
||
257 | * @return null|Member |
||
258 | */ |
||
259 | View Code Duplication | protected function getMember($member = null) |
|
271 | |||
272 | /** |
||
273 | * Check if this member is an editor of the blog. |
||
274 | * |
||
275 | * @param Member $member |
||
276 | * |
||
277 | * @return bool |
||
278 | */ |
||
279 | public function isEditor($member) |
||
286 | |||
287 | /** |
||
288 | * Determine if the given member belongs to the given relation. |
||
289 | * |
||
290 | * @param Member $member |
||
291 | * @param DataList $relation |
||
292 | * |
||
293 | * @return bool |
||
294 | */ |
||
295 | View Code Duplication | protected function isMemberOf($member, $relation) |
|
307 | |||
308 | /** |
||
309 | * Determine the role of the given member. |
||
310 | * |
||
311 | * Call be called via template to determine the current user. |
||
312 | * |
||
313 | * @example "Hello $RoleOf($CurrentMember.ID)" |
||
314 | * |
||
315 | * @param int|Member $member |
||
316 | * |
||
317 | * @return null|string |
||
318 | */ |
||
319 | public function RoleOf($member) |
||
343 | |||
344 | /** |
||
345 | * Check if this member is a writer of the blog. |
||
346 | * |
||
347 | * @param Member $member |
||
348 | * |
||
349 | * @return bool |
||
350 | */ |
||
351 | public function isWriter($member) |
||
358 | |||
359 | /** |
||
360 | * Check if this member is a contributor of the blog. |
||
361 | * |
||
362 | * @param Member $member |
||
363 | * |
||
364 | * @return bool |
||
365 | */ |
||
366 | public function isContributor($member) |
||
373 | |||
374 | /** |
||
375 | * {@inheritdoc} |
||
376 | */ |
||
377 | public function canAddChildren($member = null) |
||
387 | |||
388 | /** |
||
389 | * {@inheritdoc} |
||
390 | */ |
||
391 | public function getSettingsFields() |
||
478 | |||
479 | /** |
||
480 | * Gets the list of user candidates to be assigned to assist with this blog. |
||
481 | * |
||
482 | * @return SS_List |
||
483 | */ |
||
484 | protected function getCandidateUsers() |
||
496 | |||
497 | /** |
||
498 | * Determine if this user can edit the editors list. |
||
499 | * |
||
500 | * @param int|Member $member |
||
501 | * |
||
502 | * @return bool |
||
503 | */ |
||
504 | public function canEditEditors($member = null) |
||
516 | |||
517 | /** |
||
518 | * Determine if this user can edit writers list. |
||
519 | * |
||
520 | * @param int|Member $member |
||
521 | * |
||
522 | * @return boolean |
||
523 | */ |
||
524 | View Code Duplication | public function canEditWriters($member = null) |
|
540 | |||
541 | /** |
||
542 | * Determines if this user can edit the contributors list. |
||
543 | * |
||
544 | * @param int|Member $member |
||
545 | * |
||
546 | * @return boolean |
||
547 | */ |
||
548 | View Code Duplication | public function canEditContributors($member = null) |
|
564 | |||
565 | /** |
||
566 | * Returns BlogPosts for a given date period. |
||
567 | * |
||
568 | * @param int $year |
||
569 | * @param null|int $month |
||
570 | * @param null|int $day |
||
571 | * |
||
572 | * @return DataList |
||
573 | */ |
||
574 | public function getArchivedBlogPosts($year, $month = null, $day = null) |
||
609 | |||
610 | /** |
||
611 | * Return blog posts. |
||
612 | * |
||
613 | * @return DataList of BlogPost objects |
||
614 | */ |
||
615 | public function getBlogPosts() |
||
623 | |||
624 | /** |
||
625 | * Get a link to a Member profile. |
||
626 | * |
||
627 | * @param string $urlSegment |
||
628 | * |
||
629 | * @return string |
||
630 | */ |
||
631 | public function ProfileLink($urlSegment) |
||
635 | |||
636 | /** |
||
637 | * This sets the title for our gridfield. |
||
638 | * |
||
639 | * @return string |
||
640 | */ |
||
641 | public function getLumberjackTitle() |
||
645 | |||
646 | /** |
||
647 | * This overwrites lumberjacks default gridfield config. |
||
648 | * |
||
649 | * @return GridFieldConfig |
||
650 | */ |
||
651 | public function getLumberjackGridFieldConfig() |
||
655 | |||
656 | /** |
||
657 | * {@inheritdoc} |
||
658 | */ |
||
659 | public function providePermissions() |
||
676 | |||
677 | /** |
||
678 | * @throws ValidationException |
||
679 | */ |
||
680 | protected function onBeforeWrite() |
||
685 | |||
686 | /** |
||
687 | * Assign users as necessary to the blog group. |
||
688 | * |
||
689 | * @throws ValidationException |
||
690 | * @throws Exception |
||
691 | */ |
||
692 | protected function assignGroup() |
||
712 | |||
713 | /** |
||
714 | * Gets or creates the group used to assign CMS access. |
||
715 | * |
||
716 | * @return Group |
||
717 | * @throws ValidationException |
||
718 | */ |
||
719 | protected function getUserGroup() |
||
742 | } |
||
743 |
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.