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:
| 1 | <?php | ||
| 21 | trait BlogObject | ||
| 22 | { | ||
| 23 | /** | ||
| 24 | * @return ManyManyList|BlogPost[] | ||
| 25 | */ | ||
| 26 | public function BlogPosts() | ||
| 34 | |||
| 35 | /** | ||
| 36 | * Get blog this tag was queried from | ||
| 37 | * | ||
| 38 | * @return Blog|null | ||
| 39 | */ | ||
| 40 | public function Blog() | ||
| 50 | |||
| 51 | /** | ||
| 52 |      * {@inheritdoc} | ||
| 53 | */ | ||
| 54 | public function getCMSFields() | ||
| 69 | |||
| 70 | /** | ||
| 71 | * Number of times this object has blog posts in the current blog | ||
| 72 | * | ||
| 73 | * @return int | ||
| 74 | */ | ||
| 75 | public function getBlogCount() | ||
| 87 | |||
| 88 | /** | ||
| 89 |      * {@inheritdoc} | ||
| 90 | * @return ValidationResult | ||
| 91 | */ | ||
| 92 | public function validate() | ||
| 106 | |||
| 107 | /** | ||
| 108 | * Returns a relative link to this category or tag | ||
| 109 | * | ||
| 110 | * @return string | ||
| 111 | */ | ||
| 112 | public function getLink() | ||
| 124 | |||
| 125 | /** | ||
| 126 | * Inherits from the parent blog or can be overwritten using a DataExtension. | ||
| 127 | * | ||
| 128 | * @param null|Member $member | ||
| 129 | * | ||
| 130 | * @return bool | ||
| 131 | */ | ||
| 132 | View Code Duplication | public function canView($member = null) | |
| 143 | |||
| 144 | /** | ||
| 145 |      * {@inheritdoc} | ||
| 146 | */ | ||
| 147 | public function canCreate($member = null, $context = []) | ||
| 159 | |||
| 160 | /** | ||
| 161 | * Inherits from the parent blog or can be overwritten using a DataExtension. | ||
| 162 | * | ||
| 163 | * @param null|Member $member | ||
| 164 | * | ||
| 165 | * @return bool | ||
| 166 | */ | ||
| 167 | View Code Duplication | public function canDelete($member = null) | |
| 178 | |||
| 179 | /** | ||
| 180 | * Inherits from the parent blog or can be overwritten using a DataExtension. | ||
| 181 | * | ||
| 182 | * @param null|Member $member | ||
| 183 | * | ||
| 184 | * @return bool | ||
| 185 | */ | ||
| 186 | View Code Duplication | public function canEdit($member = null) | |
| 197 | |||
| 198 | /** | ||
| 199 | * @return mixed | ||
| 200 | */ | ||
| 201 | public function getBlogID() | ||
| 205 | |||
| 206 | /** | ||
| 207 | * Set a blog ID for this record | ||
| 208 | * | ||
| 209 | * @param int $id | ||
| 210 | * @return $this | ||
| 211 | */ | ||
| 212 | public function setBlogID($id) | ||
| 217 | |||
| 218 | protected function onBeforeWrite() | ||
| 226 | |||
| 227 | /** | ||
| 228 | * Generates a unique URLSegment from the title. | ||
| 229 | * | ||
| 230 | * @param int $increment | ||
| 231 | * | ||
| 232 | * @return string | ||
| 233 | */ | ||
| 234 | public function generateURLSegment($increment = 0) | ||
| 257 | |||
| 258 | /** | ||
| 259 | * Looks for objects o the same type and the same value by the given Field | ||
| 260 | * | ||
| 261 | * @param string $field E.g. URLSegment or Title | ||
| 262 | * @return DataList | ||
| 263 | */ | ||
| 264 | protected function getDuplicatesByField($field) | ||
| 275 | |||
| 276 | /** | ||
| 277 | * This returns the url segment for the listing page. | ||
| 278 | * eg. 'categories' in /my-blog/categories/category-url | ||
| 279 | * | ||
| 280 | * This is not editable at the moment, but a method is being used incase we want | ||
| 281 | * to make it editable in the future. We can use this method to provide logic | ||
| 282 | * without replacing multiple areas of the code base. We're also not being opinionated | ||
| 283 | * about how the segment should be obtained at the moment and allowing for the | ||
| 284 | * implementation to decide. | ||
| 285 | * | ||
| 286 | * @return string | ||
| 287 | */ | ||
| 288 | abstract protected function getListUrlSegment(); | ||
| 289 | |||
| 290 | /** | ||
| 291 | * Returns an error message for this object when it tries to write a duplicate. | ||
| 292 | * | ||
| 293 | * @return string | ||
| 294 | */ | ||
| 295 | abstract protected function getDuplicateError(); | ||
| 296 | } | ||
| 297 | 
This check looks for methods that are used by a trait but not required by it.
To illustrate, let’s look at the following code example
The trait
Idableprovides a methodequalsIdthat in turn relies on the methodgetId(). If this method does not exist on a class mixing in this trait, the method will fail.Adding the
getId()as an abstract method to the trait will make sure it is available.