Complex classes like OrderModifier 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 OrderModifier, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
31 | class OrderModifier extends OrderAttribute |
||
32 | { |
||
33 | /** |
||
34 | * what variables are accessible through http://mysite.com/api/ecommerce/v1/OrderModifier/. |
||
35 | * |
||
36 | * @var array |
||
37 | */ |
||
38 | private static $api_access = array( |
||
|
|||
39 | 'view' => array( |
||
40 | 'CalculatedTotal', |
||
41 | 'Sort', |
||
42 | 'GroupSort', |
||
43 | 'TableTitle', |
||
44 | 'TableSubTitle', |
||
45 | 'CartTitle', |
||
46 | 'CartSubTitle', |
||
47 | 'Name', |
||
48 | 'TableValue', |
||
49 | 'HasBeenRemoved', |
||
50 | 'Order', |
||
51 | ), |
||
52 | ); |
||
53 | |||
54 | // ######################################## *** 1. model defining static variables (e.g. $db, $has_one) |
||
55 | |||
56 | /** |
||
57 | * @var array |
||
58 | * stardard SS definition |
||
59 | */ |
||
60 | private static $db = array( |
||
61 | 'Name' => 'HTMLText', // we use this to create the TableTitle, CartTitle and TableSubTitle |
||
62 | 'TableValue' => 'Currency', //the $$ shown in the checkout table |
||
63 | 'HasBeenRemoved' => 'Boolean', // we add this so that we can see what modifiers have been removed |
||
64 | ); |
||
65 | |||
66 | /** |
||
67 | * make sure to choose the right Type and Name for this. |
||
68 | * stardard SS variable. |
||
69 | * |
||
70 | * @var array |
||
71 | */ |
||
72 | private static $defaults = array( |
||
73 | 'Name' => 'Modifier', //making sure that you choose a different name for any class extensions. |
||
74 | ); |
||
75 | |||
76 | // ######################################## *** 2. cms variables + functions (e.g. getCMSFields, $searchableFields) |
||
77 | |||
78 | /** |
||
79 | * stardard SS variable. |
||
80 | * |
||
81 | * @var array |
||
82 | */ |
||
83 | private static $searchable_fields = array( |
||
84 | 'OrderID' => array( |
||
85 | 'field' => 'NumericField', |
||
86 | 'title' => 'Order Number', |
||
87 | ), |
||
88 | //"TableTitle" => "PartialMatchFilter", |
||
89 | 'TableValue', |
||
90 | 'HasBeenRemoved', |
||
91 | ); |
||
92 | |||
93 | /** |
||
94 | * stardard SS definition. |
||
95 | * |
||
96 | * @var array |
||
97 | */ |
||
98 | private static $summary_fields = array( |
||
99 | 'OrderID' => 'Order ID', |
||
100 | 'TableTitle' => 'Table Title', |
||
101 | 'TableSubTitle' => 'More ...', |
||
102 | 'TableValue' => 'Value Shown', |
||
103 | 'CalculatedTotal' => 'Calculation Total', |
||
104 | ); |
||
105 | |||
106 | /** |
||
107 | * stardard SS definition. |
||
108 | * |
||
109 | * @var array |
||
110 | */ |
||
111 | private static $casting = array( |
||
112 | 'TableValueAsMoney' => 'Money', |
||
113 | ); |
||
114 | |||
115 | /** |
||
116 | * stardard SS variable. |
||
117 | * |
||
118 | * @var string |
||
119 | */ |
||
120 | private static $singular_name = 'Order Modifier'; |
||
121 | public function i18n_singular_name() |
||
125 | |||
126 | /** |
||
127 | * stardard SS variable. |
||
128 | * |
||
129 | * @var string |
||
130 | */ |
||
131 | private static $plural_name = 'Order Modifiers'; |
||
132 | public function i18n_plural_name() |
||
136 | |||
137 | /** |
||
138 | * Standard SS variable. |
||
139 | * |
||
140 | * @var string |
||
141 | */ |
||
142 | private static $description = 'An addition to the order that sits between the sub-total and the total (e.g. tax, delivery, etc...).'; |
||
143 | |||
144 | /** |
||
145 | * stardard SS metbod. |
||
146 | * |
||
147 | * @return FieldList |
||
148 | */ |
||
149 | public function getCMSFields() |
||
193 | |||
194 | /** |
||
195 | * Determine which properties on the DataObject are |
||
196 | * searchable, and map them to their default {@link FormField} |
||
197 | * representations. Used for scaffolding a searchform for {@link ModelAdmin}. |
||
198 | * |
||
199 | * Some additional logic is included for switching field labels, based on |
||
200 | * how generic or specific the field type is. |
||
201 | * |
||
202 | * Used by {@link SearchContext}. |
||
203 | * |
||
204 | * @param array $_params |
||
205 | * 'fieldClasses': Associative array of field names as keys and FormField classes as values |
||
206 | * 'restrictFields': Numeric array of a field name whitelist |
||
207 | * |
||
208 | * @return FieldList |
||
209 | */ |
||
210 | public function scaffoldSearchFields($_params = null) |
||
217 | |||
218 | // ######################################## *** 3. other static variables (e.g. special_name_for_something) |
||
219 | |||
220 | /** |
||
221 | * $doNotAddAutomatically Identifies whether a modifier is NOT automatically added |
||
222 | * Most modifiers, such as delivery and GST would be added automatically. |
||
223 | * However, there are also ones that are not added automatically. |
||
224 | * |
||
225 | * @var bool |
||
226 | **/ |
||
227 | protected $doNotAddAutomatically = false; |
||
228 | |||
229 | /** |
||
230 | * $can_be_removed Identifies whether a modifier can be removed by the user. |
||
231 | * |
||
232 | * @var bool |
||
233 | **/ |
||
234 | protected $canBeRemoved = false; |
||
235 | |||
236 | /** |
||
237 | * This is a flag for running an update. |
||
238 | * Running an update means that all fields are (re)set, using the Live{FieldName} methods. |
||
239 | * |
||
240 | * @var bool |
||
241 | **/ |
||
242 | protected $mustUpdate = false; |
||
243 | |||
244 | /** |
||
245 | * When recalculating all the modifiers, this private variable is added to as a running total |
||
246 | * other modifiers can then tap into this to work out their own values. |
||
247 | * For example, a tax modifier needs to know the value of the other modifiers before calculating |
||
248 | * its own value (i.e. tax is also paid over handling and shipping). |
||
249 | * Always consider the "order" (which one first) of the order modifiers when using this variable. |
||
250 | * |
||
251 | * @var float |
||
252 | **/ |
||
253 | private $runningTotal = 0; |
||
254 | |||
255 | // ######################################## *** 4. CRUD functions (e.g. canEdit) |
||
256 | |||
257 | // ######################################## *** 5. init and update functions |
||
258 | |||
259 | /** |
||
260 | * |
||
261 | */ |
||
262 | public static function init_for_order($className) |
||
268 | |||
269 | /** |
||
270 | * This method runs when the OrderModifier is first added to the order. |
||
271 | **/ |
||
272 | public function init() |
||
281 | |||
282 | /* |
||
283 | * all classes extending OrderModifier must have this method if it has more fields |
||
284 | * @param boolean $recalculate - run it, even if it has run already |
||
285 | **/ |
||
286 | public function runUpdate($recalculate = false) |
||
299 | |||
300 | /** |
||
301 | * You can overload this method as canEdit might not be the right indicator. |
||
302 | * |
||
303 | * @return bool |
||
304 | **/ |
||
305 | protected function canBeUpdated() |
||
309 | |||
310 | /** |
||
311 | * standard SS Method. |
||
312 | * |
||
313 | * @return bool |
||
314 | **/ |
||
315 | public function canCreate($member = null) |
||
319 | |||
320 | /** |
||
321 | * standard SS Method. |
||
322 | * |
||
323 | * @return bool |
||
324 | **/ |
||
325 | public function canDelete($member = null) |
||
329 | |||
330 | /** |
||
331 | * This method simply checks if a fields has changed and if it has changed it updates the field. |
||
332 | * |
||
333 | * @param string $fieldName |
||
334 | **/ |
||
335 | protected function checkField($fieldName) |
||
347 | |||
348 | /** |
||
349 | * Provides a modifier total that is positive or negative, depending on whether the modifier is chargable or not. |
||
350 | * This number is used to work out the order Grand Total..... |
||
351 | * It is important to note that this can be positive or negative, while the amount is always positive. |
||
352 | * |
||
353 | * @return float / double |
||
354 | */ |
||
355 | public function CalculationTotal() |
||
363 | |||
364 | // ######################################## *** 6. form functions (Showform and getform) |
||
365 | |||
366 | /** |
||
367 | * This determines whether the OrderModifierForm is shown or not. {@link OrderModifier::get_form()}. |
||
368 | * OrderModifierForms are forms that are added to check out to facilitate the use of the modifier. |
||
369 | * An example would be a form allowing the user to select the delivery option. |
||
370 | * |
||
371 | * @return bool |
||
372 | */ |
||
373 | public function ShowForm() |
||
377 | |||
378 | /** |
||
379 | * Should the form be included in the EDITABLE form |
||
380 | * on the checkout page? |
||
381 | * |
||
382 | * @return bool |
||
383 | */ |
||
384 | public function ShowFormInEditableOrderTable() |
||
389 | |||
390 | /** |
||
391 | * Should the form be shown outside of editable table |
||
392 | * on the checkout page (opposite of ShowFormInEditableOrderTable)? |
||
393 | * |
||
394 | * @return bool |
||
395 | */ |
||
396 | public function ShowFormOutsideEditableOrderTable() |
||
401 | |||
402 | /** |
||
403 | * This function returns a form that allows a user |
||
404 | * to change the modifier to the order. |
||
405 | * |
||
406 | * We have mainly added this function as an example! |
||
407 | * |
||
408 | * @param Controller $optionalController - optional custom controller class |
||
409 | * @param Validator $optionalValidator - optional custom validator class |
||
410 | * |
||
411 | * @return OrderModifierForm or subclass |
||
412 | */ |
||
413 | public function getModifierForm(Controller $optionalController = null, Validator $optionalValidator = null) |
||
423 | |||
424 | /** |
||
425 | * @return object (HeadingField) |
||
426 | */ |
||
427 | protected function headingField() |
||
436 | |||
437 | /** |
||
438 | * @return object (LiteralField) |
||
439 | */ |
||
440 | protected function descriptionField() |
||
449 | |||
450 | // ######################################## *** 7. template functions (e.g. ShowInTable, TableTitle, etc...) |
||
451 | |||
452 | /** |
||
453 | * Casted variable, returns the table title. |
||
454 | * |
||
455 | * @return string |
||
456 | */ |
||
457 | public function TableTitle() |
||
465 | |||
466 | /** |
||
467 | * caching of relevant OrderModifier_Descriptor. |
||
468 | * |
||
469 | * @var OrderModifier_Descriptor |
||
470 | */ |
||
471 | private $orderModifier_Descriptor = null; |
||
472 | |||
473 | /** |
||
474 | * returns the relevant orderModifier_Descriptor. |
||
475 | * |
||
476 | * @return OrderModifier_Descriptor | Null |
||
477 | */ |
||
478 | protected function getOrderModifier_Descriptor() |
||
489 | |||
490 | /** |
||
491 | * returns a heading if there is one. |
||
492 | * |
||
493 | * @return string |
||
494 | **/ |
||
495 | public function Heading() |
||
503 | |||
504 | /** |
||
505 | * returns a description if there is one. |
||
506 | * |
||
507 | * @return string (html) |
||
508 | **/ |
||
509 | public function Description() |
||
517 | |||
518 | /** |
||
519 | * returns a page for a more info link... (if there is one). |
||
520 | * |
||
521 | * @return object (SiteTree) |
||
522 | **/ |
||
523 | public function MoreInfoPage() |
||
531 | |||
532 | /** |
||
533 | * tells you whether the modifier shows up on the checkout / cart form. |
||
534 | * this is also the place where we check if the modifier has been updated. |
||
535 | * |
||
536 | * @return bool |
||
537 | */ |
||
538 | public function ShowInTable() |
||
548 | |||
549 | /** |
||
550 | * Returns the Money object of the Table Value. |
||
551 | * |
||
552 | * @return Money |
||
553 | **/ |
||
554 | public function TableValueAsMoney() |
||
562 | |||
563 | /** |
||
564 | * some modifiers can be hidden after an ajax update (e.g. if someone enters a discount coupon and it does not exist). |
||
565 | * There might be instances where ShowInTable (the starting point) is TRUE and HideInAjaxUpdate return false. |
||
566 | * |
||
567 | *@return bool |
||
568 | **/ |
||
569 | public function HideInAjaxUpdate() |
||
580 | |||
581 | /** |
||
582 | * Checks if the modifier can be removed. |
||
583 | * |
||
584 | * @return bool |
||
585 | **/ |
||
586 | public function CanBeRemoved() |
||
590 | |||
591 | /** |
||
592 | * Checks if the modifier can be added manually. |
||
593 | * |
||
594 | * @return bool |
||
595 | **/ |
||
596 | public function CanAdd() |
||
600 | |||
601 | /** |
||
602 | *Identifier whether a modifier will be added automatically for all new orders. |
||
603 | * |
||
604 | * @return bool |
||
605 | */ |
||
606 | public function DoNotAddAutomatically() |
||
610 | |||
611 | /** |
||
612 | * Actual calculation used. |
||
613 | * |
||
614 | * @return float / Double |
||
615 | **/ |
||
616 | public function CalculatedTotal() |
||
620 | |||
621 | /** |
||
622 | * This link is for modifiers that have been removed and are being put "back". |
||
623 | * |
||
624 | * @return string |
||
625 | **/ |
||
626 | public function AddLink() |
||
638 | |||
639 | /** |
||
640 | * Link that can be used to remove the modifier. |
||
641 | * |
||
642 | * @return string |
||
643 | **/ |
||
644 | public function RemoveLink() |
||
656 | |||
657 | /** |
||
658 | * retursn and array like this: array(Title => "bla", Link => "/doit/now/");. |
||
659 | * |
||
660 | * @return array |
||
661 | */ |
||
662 | public function PostSubmitAction() |
||
666 | |||
667 | // ######################################## *** 8. inner calculations.... |
||
668 | |||
669 | /** |
||
670 | * returns the running total variable. |
||
671 | * |
||
672 | * @see variable definition for more information |
||
673 | * |
||
674 | * @return float |
||
675 | */ |
||
676 | public function getRunningTotal() |
||
680 | |||
681 | // ######################################## *** 9. calculate database fields ( = protected function Live[field name]() { ....} |
||
682 | |||
683 | protected function LiveName() |
||
690 | |||
691 | protected function LiveTableValue() |
||
695 | |||
696 | /** |
||
697 | * This function is always called to determine the |
||
698 | * amount this modifier needs to charge or deduct - if any. |
||
699 | * |
||
700 | * |
||
701 | * @return Currency |
||
702 | */ |
||
703 | protected function LiveCalculatedTotal() |
||
707 | |||
708 | // ######################################## *** 10. Type Functions (IsChargeable, IsDeductable, IsNoChange, IsRemoved) |
||
709 | |||
710 | /** |
||
711 | * should be extended if it is true in child class. |
||
712 | * |
||
713 | * @return bool |
||
714 | */ |
||
715 | public function IsChargeable() |
||
719 | /** |
||
720 | * should be extended if it is true in child class. |
||
721 | * |
||
722 | * @return bool |
||
723 | */ |
||
724 | public function IsDeductable() |
||
728 | |||
729 | /** |
||
730 | * should be extended if it is true in child class. |
||
731 | * |
||
732 | * @return bool |
||
733 | */ |
||
734 | public function IsNoChange() |
||
738 | |||
739 | /** |
||
740 | * should be extended if it is true in child class |
||
741 | * Needs to be a public class. |
||
742 | * |
||
743 | * @return bool |
||
744 | */ |
||
745 | public function IsRemoved() |
||
749 | |||
750 | // ######################################## *** 11. standard database related functions (e.g. onBeforeWrite, onAfterWrite, etc...) |
||
751 | |||
752 | /** |
||
753 | * standard SS method. |
||
754 | */ |
||
755 | public function onBeforeWrite() |
||
759 | |||
760 | /** |
||
761 | * removing the Order Modifier does not delete it |
||
762 | * rather, it ignores it (e.g. remove discount coupon) |
||
763 | * We cant delete it, because we need to have a positive record |
||
764 | * of it being removed. |
||
765 | * Extend on Child Classes. |
||
766 | */ |
||
767 | public function onBeforeRemove() |
||
771 | |||
772 | /** |
||
773 | * removing the Order Modifier does not delete it |
||
774 | * rather, it ignores it (e.g. remove discount coupon) |
||
775 | * We cant delete it, because we need to have a positive record |
||
776 | * of it being removed. |
||
777 | * Extend on Child Classes. |
||
778 | */ |
||
779 | public function onAfterRemove() |
||
783 | |||
784 | // ######################################## *** 11. AJAX related functions |
||
785 | |||
786 | /** |
||
787 | * @param array $js javascript array |
||
788 | * |
||
789 | * @return array for AJAX JSON |
||
790 | **/ |
||
791 | public function updateForAjax(array $js) |
||
852 | |||
853 | // ######################################## *** 12. debug functions |
||
854 | |||
855 | /** |
||
856 | * Debug helper method. |
||
857 | * Access through : /shoppingcart/debug/. |
||
858 | */ |
||
859 | public function debug() |
||
865 | } |
||
866 |