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 Reservation 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 Reservation, and based on these observations, apply Extract Interface, too.
| 1 | <?php  | 
            ||
| 55 | class Reservation extends DataObject  | 
            ||
| 56 | { | 
            ||
| 57 | const STATUS_CART = 'CART';  | 
            ||
| 58 | const STATUS_PENDING = 'PENDING';  | 
            ||
| 59 | const STATUS_PAID = 'PAID';  | 
            ||
| 60 | const STATUS_CANCELED = 'CANCELED';  | 
            ||
| 61 | |||
| 62 | /**  | 
            ||
| 63 | * Time to wait before deleting the discarded cart  | 
            ||
| 64 | * Give a string that is parsable by strtotime  | 
            ||
| 65 | *  | 
            ||
| 66 | * @var string  | 
            ||
| 67 | */  | 
            ||
| 68 | private static $delete_after = '+1 hour';  | 
            ||
| 69 | |||
| 70 | /**  | 
            ||
| 71 | * The address to whom the ticket notifications are sent  | 
            ||
| 72 | * By default the admin email is used  | 
            ||
| 73 | *  | 
            ||
| 74 | * @config  | 
            ||
| 75 | * @var string  | 
            ||
| 76 | */  | 
            ||
| 77 | private static $mail_sender;  | 
            ||
| 78 | |||
| 79 | /**  | 
            ||
| 80 | * The address from where the ticket mails are sent  | 
            ||
| 81 | * By default the admin email is used  | 
            ||
| 82 | *  | 
            ||
| 83 | * @config  | 
            ||
| 84 | * @var string  | 
            ||
| 85 | */  | 
            ||
| 86 | private static $mail_receiver;  | 
            ||
| 87 | |||
| 88 | private static $db = array(  | 
            ||
| 89 |         'Status' => 'Enum("CART,PENDING,PAID,CANCELED","CART")', | 
            ||
| 90 | 'Title' => 'Varchar(255)',  | 
            ||
| 91 | 'Subtotal' => 'Currency',  | 
            ||
| 92 | 'Total' => 'Currency',  | 
            ||
| 93 | 'Gateway' => 'Varchar(255)',  | 
            ||
| 94 | 'Comments' => 'Text',  | 
            ||
| 95 | 'AgreeToTermsAndConditions' => 'Boolean',  | 
            ||
| 96 | 'ReservationCode' => 'Varchar(255)',  | 
            ||
| 97 | 'SentTickets' => 'Boolean',  | 
            ||
| 98 | 'SentReservation' => 'Boolean',  | 
            ||
| 99 | 'SentNotification' => 'Boolean',  | 
            ||
| 100 | );  | 
            ||
| 101 | |||
| 102 | private static $default_sort = 'Created DESC';  | 
            ||
| 103 | |||
| 104 | private static $has_one = array(  | 
            ||
| 105 | 'Event' => 'CalendarEvent',  | 
            ||
| 106 | 'MainContact' => 'Broarm\EventTickets\Attendee'  | 
            ||
| 107 | );  | 
            ||
| 108 | |||
| 109 | private static $has_many = array(  | 
            ||
| 110 | 'Payments' => 'Payment',  | 
            ||
| 111 | 'Attendees' => 'Broarm\EventTickets\Attendee.Reservation'  | 
            ||
| 112 | );  | 
            ||
| 113 | |||
| 114 | private static $belongs_many_many = array(  | 
            ||
| 115 | 'PriceModifiers' => 'Broarm\EventTickets\PriceModifier'  | 
            ||
| 116 | );  | 
            ||
| 117 | |||
| 118 | private static $indexes = array(  | 
            ||
| 119 |         'ReservationCode' => 'unique("ReservationCode")' | 
            ||
| 120 | );  | 
            ||
| 121 | |||
| 122 | private static $summary_fields = array(  | 
            ||
| 
                                                                                                    
                        
                         | 
                |||
| 123 | 'ReservationCode' => 'Reservation',  | 
            ||
| 124 | 'Title' => 'Customer',  | 
            ||
| 125 | 'Total.Nice' => 'Total',  | 
            ||
| 126 | 'State' => 'Status',  | 
            ||
| 127 | 'GatewayNice' => 'Payment method',  | 
            ||
| 128 | 'Created.Nice' => 'Date'  | 
            ||
| 129 | );  | 
            ||
| 130 | |||
| 131 | /**  | 
            ||
| 132 | * Actions usable on the cms detail view  | 
            ||
| 133 | *  | 
            ||
| 134 | * @var array  | 
            ||
| 135 | */  | 
            ||
| 136 | private static $better_buttons_actions = array(  | 
            ||
| 137 | 'send'  | 
            ||
| 138 | );  | 
            ||
| 139 | |||
| 140 | public function getCMSFields()  | 
            ||
| 161 | |||
| 162 | /**  | 
            ||
| 163 | * Add utility actions to the reservation details view  | 
            ||
| 164 | *  | 
            ||
| 165 | * @return FieldList  | 
            ||
| 166 | */  | 
            ||
| 167 | public function getBetterButtonsActions()  | 
            ||
| 175 | |||
| 176 | /**  | 
            ||
| 177 | * Generate a reservation code if it does not yet exists  | 
            ||
| 178 | */  | 
            ||
| 179 | public function onBeforeWrite()  | 
            ||
| 191 | |||
| 192 | /**  | 
            ||
| 193 | * After deleting a reservation, delete the attendees and files  | 
            ||
| 194 | */  | 
            ||
| 195 | public function onBeforeDelete()  | 
            ||
| 212 | |||
| 213 | /**  | 
            ||
| 214 | * Gets a nice unnamespaced name  | 
            ||
| 215 | *  | 
            ||
| 216 | * @return string  | 
            ||
| 217 | */  | 
            ||
| 218 | public function singular_name()  | 
            ||
| 223 | |||
| 224 | /**  | 
            ||
| 225 | * Returns the nice gateway title  | 
            ||
| 226 | *  | 
            ||
| 227 | * @return string  | 
            ||
| 228 | */  | 
            ||
| 229 | public function getGatewayNice()  | 
            ||
| 233 | |||
| 234 | /**  | 
            ||
| 235 | * Check if the cart is still in cart state and the delete_after time period has been exceeded  | 
            ||
| 236 | *  | 
            ||
| 237 | * @return bool  | 
            ||
| 238 | */  | 
            ||
| 239 | public function isDiscarded()  | 
            ||
| 244 | |||
| 245 | /**  | 
            ||
| 246 | * Get the full name  | 
            ||
| 247 | *  | 
            ||
| 248 | * @return string  | 
            ||
| 249 | */  | 
            ||
| 250 | public function getName()  | 
            ||
| 259 | |||
| 260 | /**  | 
            ||
| 261 | * Return the translated state  | 
            ||
| 262 | *  | 
            ||
| 263 | * @return string  | 
            ||
| 264 | */  | 
            ||
| 265 | public function getState()  | 
            ||
| 269 | |||
| 270 | /**  | 
            ||
| 271 | * Get a the translated map of available states  | 
            ||
| 272 | *  | 
            ||
| 273 | * @return array  | 
            ||
| 274 | */  | 
            ||
| 275 | private function getStates()  | 
            ||
| 281 | |||
| 282 | /**  | 
            ||
| 283 | * Get the total by querying the sum of attendee ticket prices  | 
            ||
| 284 | *  | 
            ||
| 285 | * @return float  | 
            ||
| 286 | */  | 
            ||
| 287 | public function calculateTotal()  | 
            ||
| 303 | |||
| 304 | /**  | 
            ||
| 305 | * Safely change to a state  | 
            ||
| 306 | * todo check if state direction matches  | 
            ||
| 307 | *  | 
            ||
| 308 | * @param $state  | 
            ||
| 309 | *  | 
            ||
| 310 | * @return boolean  | 
            ||
| 311 | */  | 
            ||
| 312 | public function changeState($state)  | 
            ||
| 323 | |||
| 324 | /**  | 
            ||
| 325 | * Complete the reservation  | 
            ||
| 326 | *  | 
            ||
| 327 | * @throws \ValidationException  | 
            ||
| 328 | */  | 
            ||
| 329 | public function complete()  | 
            ||
| 336 | |||
| 337 | /**  | 
            ||
| 338 | * Set the main contact id  | 
            ||
| 339 | * @param $id  | 
            ||
| 340 | *  | 
            ||
| 341 | * @throws \ValidationException  | 
            ||
| 342 | */  | 
            ||
| 343 | public function setMainContact($id)  | 
            ||
| 348 | |||
| 349 | /**  | 
            ||
| 350 | * Create a reservation code  | 
            ||
| 351 | *  | 
            ||
| 352 | * @return string  | 
            ||
| 353 | */  | 
            ||
| 354 | public function createReservationCode()  | 
            ||
| 358 | |||
| 359 | /**  | 
            ||
| 360 | * Generate the qr codes and downloadable pdf  | 
            ||
| 361 | */  | 
            ||
| 362 | public function createFiles()  | 
            ||
| 370 | |||
| 371 | /**  | 
            ||
| 372 | * Send the reservation mail  | 
            ||
| 373 | *  | 
            ||
| 374 | * @return mixed  | 
            ||
| 375 | */  | 
            ||
| 376 | View Code Duplication | public function sendReservation()  | 
            |
| 400 | |||
| 401 | /**  | 
            ||
| 402 | * Send the reserved tickets  | 
            ||
| 403 | *  | 
            ||
| 404 | * @return mixed  | 
            ||
| 405 | */  | 
            ||
| 406 | public function sendTickets()  | 
            ||
| 445 | |||
| 446 | |||
| 447 | /**  | 
            ||
| 448 | * Send a booking notification to the ticket mail sender or the site admin  | 
            ||
| 449 | * @return mixed  | 
            ||
| 450 | */  | 
            ||
| 451 | public function sendNotification()  | 
            ||
| 475 | |||
| 476 | /**  | 
            ||
| 477 | * Create the files and send the reservation, notification and tickets  | 
            ||
| 478 | */  | 
            ||
| 479 | public function send()  | 
            ||
| 486 | |||
| 487 | /**  | 
            ||
| 488 | * Get the download link  | 
            ||
| 489 | *  | 
            ||
| 490 | * @return string|null  | 
            ||
| 491 | */  | 
            ||
| 492 | public function getDownloadLink()  | 
            ||
| 505 | |||
| 506 | public function canView($member = null)  | 
            ||
| 510 | |||
| 511 | public function canEdit($member = null)  | 
            ||
| 515 | |||
| 516 | public function canDelete($member = null)  | 
            ||
| 520 | |||
| 521 | public function canCreate($member = null)  | 
            ||
| 525 | }  | 
            ||
| 526 |