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 BaseElement 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 BaseElement, and based on these observations, apply Extract Interface, too.
| 1 | <?php  | 
            ||
| 6 | class BaseElement extends Widget  | 
            ||
| 
                                                                                                    
                        
                         | 
                |||
| 7 | { | 
            ||
| 8 | /**  | 
            ||
| 9 | * @var array $db  | 
            ||
| 10 | */  | 
            ||
| 11 | private static $db = array(  | 
            ||
| 12 | 'ExtraClass' => 'Varchar(255)',  | 
            ||
| 13 | 'HideTitle' => 'Boolean'  | 
            ||
| 14 | );  | 
            ||
| 15 | |||
| 16 | /**  | 
            ||
| 17 | * @var array $has_one  | 
            ||
| 18 | */  | 
            ||
| 19 | private static $has_one = array(  | 
            ||
| 20 | 'List' => 'ElementList' // optional.  | 
            ||
| 21 | );  | 
            ||
| 22 | |||
| 23 | /**  | 
            ||
| 24 | * @var array $has_many  | 
            ||
| 25 | */  | 
            ||
| 26 | private static $has_many = array(  | 
            ||
| 27 | 'VirtualClones' => 'ElementVirtualLinked'  | 
            ||
| 28 | );  | 
            ||
| 29 | |||
| 30 | /**  | 
            ||
| 31 | * @var string  | 
            ||
| 32 | */  | 
            ||
| 33 | private static $title = "Content Block";  | 
            ||
| 34 | |||
| 35 | /**  | 
            ||
| 36 | * @var string  | 
            ||
| 37 | */  | 
            ||
| 38 | private static $singular_name = 'Content Block';  | 
            ||
| 39 | |||
| 40 | /**  | 
            ||
| 41 | * @var array  | 
            ||
| 42 | */  | 
            ||
| 43 | private static $summary_fields = array(  | 
            ||
| 44 | 'ID' => 'ID',  | 
            ||
| 45 | 'Title' => 'Title',  | 
            ||
| 46 | 'ElementType' => 'Type'  | 
            ||
| 47 | );  | 
            ||
| 48 | |||
| 49 | /**  | 
            ||
| 50 | * @var array  | 
            ||
| 51 | */  | 
            ||
| 52 | private static $searchable_fields = array(  | 
            ||
| 53 | 'ID' => array(  | 
            ||
| 54 | 'field' => 'NumericField'  | 
            ||
| 55 | ),  | 
            ||
| 56 | 'Title',  | 
            ||
| 57 | 'LastEdited',  | 
            ||
| 58 | 'ClassName'  | 
            ||
| 59 | );  | 
            ||
| 60 | |||
| 61 | /**  | 
            ||
| 62 | * @var boolean  | 
            ||
| 63 | */  | 
            ||
| 64 | private static $enable_title_in_template = false;  | 
            ||
| 65 | |||
| 66 | /**  | 
            ||
| 67 | * @var Object  | 
            ||
| 68 | * The virtual owner VirtualLinkedElement  | 
            ||
| 69 | */  | 
            ||
| 70 | public $virtualOwner;  | 
            ||
| 71 | |||
| 72 | |||
| 73 | public function getCMSFields()  | 
            ||
| 152 | |||
| 153 | /**  | 
            ||
| 154 | * Version viewer must only be added at if this is the final getCMSFields for a class.  | 
            ||
| 155 | * in order to avoid having to rename all fields from eg Root.Main to Root.Current.Main  | 
            ||
| 156 | * To do this we test if getCMSFields is from the current class  | 
            ||
| 157 | */  | 
            ||
| 158 | public function isEndofLine($className)  | 
            ||
| 168 | |||
| 169 | |||
| 170 | public function onBeforeWrite()  | 
            ||
| 184 | |||
| 185 | /**  | 
            ||
| 186 | * Ensure that if there are elements that are virtualised from this element  | 
            ||
| 187 | * that we move the original element to replace one of the virtual elements  | 
            ||
| 188 | * But only if it's a delete not an unpublish  | 
            ||
| 189 | */  | 
            ||
| 190 |     public function onBeforeDelete() { | 
            ||
| 242 | |||
| 243 | /**  | 
            ||
| 244 | * @return string  | 
            ||
| 245 | */  | 
            ||
| 246 | public function i18n_singular_name()  | 
            ||
| 250 | |||
| 251 | /**  | 
            ||
| 252 | * @return string  | 
            ||
| 253 | */  | 
            ||
| 254 | public function getElementType()  | 
            ||
| 258 | |||
| 259 | /**  | 
            ||
| 260 | * @return string  | 
            ||
| 261 | */  | 
            ||
| 262 | View Code Duplication | public function getTitle()  | 
            |
| 274 | |||
| 275 | /**  | 
            ||
| 276 | * @return string  | 
            ||
| 277 | */  | 
            ||
| 278 | View Code Duplication | public function getCMSTitle()  | 
            |
| 289 | |||
| 290 | public function ControllerTop()  | 
            ||
| 294 | |||
| 295 | public function getPage()  | 
            ||
| 309 | |||
| 310 | /**  | 
            ||
| 311 |      * Override the {@link Widget::forTemplate()} method so that holders are not rendered twice. The controller should | 
            ||
| 312 | * render with widget inside the  | 
            ||
| 313 | *  | 
            ||
| 314 | * @return HTML  | 
            ||
| 315 | */  | 
            ||
| 316 | public function forTemplate($holder = true)  | 
            ||
| 320 | |||
| 321 | /**  | 
            ||
| 322 | * @return string  | 
            ||
| 323 | */  | 
            ||
| 324 |     public function getEditLink() { | 
            ||
| 332 | |||
| 333 | public function onBeforeVersionedPublish()  | 
            ||
| 337 | |||
| 338 | 		public static function all_allowed_elements() { | 
            ||
| 366 | |||
| 367 | public function getDefaultSearchContext()  | 
            ||
| 383 | |||
| 384 |     public function setVirtualOwner(ElementVirtualLinked $virtualOwner) { | 
            ||
| 387 | |||
| 388 | /**  | 
            ||
| 389 | * Finds and returns elements  | 
            ||
| 390 | * that are virtual elements which link to this element  | 
            ||
| 391 | */  | 
            ||
| 392 |     public function getVirtualLinkedElements() { | 
            ||
| 395 | |||
| 396 | /**  | 
            ||
| 397 | * Finds and returns published elements  | 
            ||
| 398 | * that are virtual elements which link to this element  | 
            ||
| 399 | */  | 
            ||
| 400 |     public function getPublishedVirtualLinkedElements() { | 
            ||
| 407 | }  | 
            ||
| 408 | |||
| 410 | 
You can fix this by adding a namespace to your class:
When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.