Complex classes like View 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 View, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
57 | class View |
||
58 | { |
||
59 | /** |
||
60 | * The business object that will be rendered. |
||
61 | * |
||
62 | * @var \Alpha\Model\ActiveRecord |
||
63 | * |
||
64 | * @since 1.0 |
||
65 | */ |
||
66 | protected $record; |
||
67 | |||
68 | /** |
||
69 | * The rendering provider that will be used to render the active record. |
||
70 | * |
||
71 | * @var \Alpha\View\Renderer\RendererProviderInterface |
||
72 | * |
||
73 | * @since 1.2 |
||
74 | */ |
||
75 | private static $provider; |
||
76 | |||
77 | /** |
||
78 | * Trace logger. |
||
79 | * |
||
80 | * @var Logger |
||
81 | * |
||
82 | * @since 1.0 |
||
83 | */ |
||
84 | private static $logger = null; |
||
85 | |||
86 | /** |
||
87 | * Constructor for the View. As this is protected, use the View::getInstance method from a public scope. |
||
88 | * |
||
89 | * @param ActiveRecord $record The main business object that this view is going to render |
||
90 | * @param string $acceptHeader Optionally pass the HTTP Accept header to select the correct renderer provider. |
||
91 | * |
||
92 | * @throws \Alpha\Exception\IllegalArguementException |
||
93 | * |
||
94 | * @since 1.0 |
||
95 | */ |
||
96 | protected function __construct($record, $acceptHeader = null) |
||
114 | |||
115 | /** |
||
116 | * Static method which returns a View object or a custom child view for the Record specified |
||
117 | * if one exists. |
||
118 | * |
||
119 | * @param ActiveRecord $record The main business object that this view is going to render |
||
120 | * @param bool $returnParent Flag to enforce the return of this object instead of a child (defaults to false) |
||
121 | * @param string $acceptHeader Optionally pass the HTTP Accept header to select the correct renderer provider. |
||
122 | * |
||
123 | * @return View Returns a View object, or a child view object if one exists for this record |
||
124 | * |
||
125 | * @since 1.0 |
||
126 | */ |
||
127 | public static function getInstance($record, $returnParent = false, $acceptHeader = null) |
||
169 | |||
170 | /** |
||
171 | * Simple setter for the view business object. |
||
172 | * |
||
173 | * @param \Alpha\Model\ActiveRecord $record |
||
174 | * |
||
175 | * @throws \Alpha\Exception\IllegalArguementException |
||
176 | * |
||
177 | * @since 1.0 |
||
178 | */ |
||
179 | public function setRecord($record) |
||
192 | |||
193 | /** |
||
194 | * Gets the Record attached to this view (if any). |
||
195 | * |
||
196 | * @return \Alpha\Model\ActiveRecord |
||
197 | * |
||
198 | * @since 1.0 |
||
199 | */ |
||
200 | public function getRecord() |
||
204 | |||
205 | /** |
||
206 | * Renders the default create view. |
||
207 | * |
||
208 | * @param array $fields Hash array of fields to pass to the template |
||
209 | * |
||
210 | * @return string |
||
211 | * |
||
212 | * @since 1.0 |
||
213 | */ |
||
214 | public function createView($fields = array()) |
||
232 | |||
233 | /** |
||
234 | * Renders a form to enable object editing. |
||
235 | * |
||
236 | * @param array $fields Hash array of fields to pass to the template |
||
237 | * |
||
238 | * @return string |
||
239 | * |
||
240 | * @since 1.0 |
||
241 | */ |
||
242 | public function editView($fields = array()) |
||
260 | |||
261 | /** |
||
262 | * Renders the list view. |
||
263 | * |
||
264 | * @param array $fields Hash array of fields to pass to the template |
||
265 | * |
||
266 | * @return string |
||
267 | * |
||
268 | * @since 1.0 |
||
269 | */ |
||
270 | public function listView($fields = array()) |
||
288 | |||
289 | /** |
||
290 | * Renders a detailed view of the object (read-only). |
||
291 | * |
||
292 | * @param array $fields Hash array of fields to pass to the template |
||
293 | * |
||
294 | * @return string |
||
295 | * |
||
296 | * @since 1.0 |
||
297 | */ |
||
298 | public function detailedView($fields = array()) |
||
316 | |||
317 | /** |
||
318 | * Renders the admin view for the business object screen. |
||
319 | * |
||
320 | * @param array $fields Hash array of fields to pass to the template |
||
321 | * |
||
322 | * @return string |
||
323 | * |
||
324 | * @since 1.0 |
||
325 | */ |
||
326 | public function adminView($fields = array()) |
||
344 | |||
345 | /** |
||
346 | * Method to render the page header content. |
||
347 | * |
||
348 | * @param \Alpha\Controller\Controller $controller |
||
349 | * |
||
350 | * @return string |
||
351 | * |
||
352 | * @throws \Alpha\Exception\IllegalArguementException |
||
353 | * |
||
354 | * @since 1.0 |
||
355 | */ |
||
356 | public static function displayPageHead($controller) |
||
384 | |||
385 | /** |
||
386 | * Method to render the page footer content. |
||
387 | * |
||
388 | * @param \Alpha\Controller\Controller $controller |
||
389 | * |
||
390 | * @return string |
||
391 | * |
||
392 | * @since 1.0 |
||
393 | */ |
||
394 | public static function displayPageFoot($controller) |
||
425 | |||
426 | /** |
||
427 | * Method for rendering the pagination links. |
||
428 | * |
||
429 | * @param \Alpha\Controller\Controller $controller |
||
430 | * |
||
431 | * @return string |
||
432 | * |
||
433 | * @since 3.0 |
||
434 | */ |
||
435 | public static function displayPageLinks($controller) |
||
512 | |||
513 | /** |
||
514 | * Renders the content for an update (e.g. successful save) message. |
||
515 | * |
||
516 | * @param string $message |
||
517 | * |
||
518 | * @return string |
||
519 | * |
||
520 | * @since 1.0 |
||
521 | */ |
||
522 | public static function displayUpdateMessage($message) |
||
542 | |||
543 | /** |
||
544 | * Renders the content for an error (e.g. save failed) message. |
||
545 | * |
||
546 | * @param string $message |
||
547 | * |
||
548 | * @return string |
||
549 | * |
||
550 | * @since 1.0 |
||
551 | */ |
||
552 | public static function displayErrorMessage($message) |
||
572 | |||
573 | /** |
||
574 | * Renders an error page with the supplied error code (typlically a HTTP code) and a message. |
||
575 | * |
||
576 | * @param string $code |
||
577 | * @param string $message |
||
578 | * |
||
579 | * @return string |
||
580 | * |
||
581 | * @since 1.0 |
||
582 | */ |
||
583 | public static function renderErrorPage($code, $message) |
||
603 | |||
604 | /** |
||
605 | * Method to render a hidden HTML form for posting the ID of an object to be deleted. |
||
606 | * |
||
607 | * @param string $URI The URI that the form will point to |
||
608 | * |
||
609 | * @return string |
||
610 | * |
||
611 | * @since 1.0 |
||
612 | */ |
||
613 | public static function renderDeleteForm($URI) |
||
633 | |||
634 | /** |
||
635 | * Method to render a HTML form with two hidden, hashed (MD5) form fields to be used as |
||
636 | * a check to ensure that a post to the controller is being sent from the same server |
||
637 | * as hosting it. |
||
638 | * |
||
639 | * @return string |
||
640 | * |
||
641 | * @since 1.0 |
||
642 | */ |
||
643 | public static function renderSecurityFields() |
||
663 | |||
664 | /** |
||
665 | * Method to render the default Integer HTML. |
||
666 | * |
||
667 | * @param string $name The field name |
||
668 | * @param string $label The label to apply to the field |
||
669 | * @param string $mode The field mode (create/edit/view) |
||
670 | * @param string $value The field value (optional) |
||
671 | * |
||
672 | * @return string |
||
673 | * |
||
674 | * @since 1.0 |
||
675 | */ |
||
676 | public function renderIntegerField($name, $label, $mode, $value = '') |
||
686 | |||
687 | /** |
||
688 | * Method to render the default Double HTML. |
||
689 | * |
||
690 | * @param string $name The field name |
||
691 | * @param string $label The label to apply to the field |
||
692 | * @param string $mode The field mode (create/edit/view) |
||
693 | * @param string $value The field value (optional) |
||
694 | * |
||
695 | * @return string |
||
696 | * |
||
697 | * @since 1.0 |
||
698 | */ |
||
699 | public function renderDoubleField($name, $label, $mode, $value = '') |
||
709 | |||
710 | /** |
||
711 | * Method to render the default Boolean HTML. |
||
712 | * |
||
713 | * @param string $name The field name |
||
714 | * @param string $label The label to apply to the field |
||
715 | * @param string $mode The field mode (create/edit/view) |
||
716 | * @param string $value The field value (optional) |
||
717 | * |
||
718 | * @return string |
||
719 | * |
||
720 | * @since 1.0 |
||
721 | */ |
||
722 | public function renderBooleanField($name, $label, $mode, $value = '') |
||
732 | |||
733 | /** |
||
734 | * Method to render the default Enum HTML. |
||
735 | * |
||
736 | * @param string $name The field name |
||
737 | * @param string $label The label to apply to the field |
||
738 | * @param string $mode The field mode (create/edit/view) |
||
739 | * @param array $options The Enum options |
||
740 | * @param string $value The field value (optional) |
||
741 | * |
||
742 | * @return string |
||
743 | * |
||
744 | * @since 1.0 |
||
745 | */ |
||
746 | public function renderEnumField($name, $label, $mode, $options, $value = '') |
||
756 | |||
757 | /** |
||
758 | * Method to render the default DEnum HTML. |
||
759 | * |
||
760 | * @param string $name The field name |
||
761 | * @param string $label The label to apply to the field |
||
762 | * @param string $mode The field mode (create/edit/view) |
||
763 | * @param array $options The DEnum options |
||
764 | * @param string $value The field value (optional) |
||
765 | * |
||
766 | * @return string |
||
767 | * |
||
768 | * @since 1.0 |
||
769 | */ |
||
770 | public function renderDEnumField($name, $label, $mode, $options, $value = '') |
||
780 | |||
781 | /** |
||
782 | * Method to render the default field HTML when type is not known. |
||
783 | * |
||
784 | * @param string $name The field name |
||
785 | * @param string $label The label to apply to the field |
||
786 | * @param string $mode The field mode (create/edit/view) |
||
787 | * @param string $value The field value (optional) |
||
788 | * |
||
789 | * @return string |
||
790 | * |
||
791 | * @since 1.0 |
||
792 | */ |
||
793 | public function renderDefaultField($name, $label, $mode, $value = '') |
||
803 | |||
804 | /** |
||
805 | * render the default Text HTML. |
||
806 | * |
||
807 | * @param string $name The field name |
||
808 | * @param string $label The label to apply to the field |
||
809 | * @param string $mode The field mode (create/edit/view) |
||
810 | * @param string $value The field value (optional) |
||
811 | * |
||
812 | * @return string |
||
813 | * |
||
814 | * @since 1.0 |
||
815 | */ |
||
816 | public function renderTextField($name, $label, $mode, $value = '') |
||
826 | |||
827 | /** |
||
828 | * render the default Relation HTML. |
||
829 | * |
||
830 | * @param string $name The field name |
||
831 | * @param string $label The label to apply to the field |
||
832 | * @param string $mode The field mode (create/edit/view) |
||
833 | * @param string $value The field value (optional) |
||
834 | * @param bool $expanded Render the related fields in expanded format or not (optional) |
||
835 | * @param bool $buttons Render buttons for expanding/contacting the related fields (optional) |
||
836 | * |
||
837 | * @return string |
||
838 | * |
||
839 | * @since 1.0 |
||
840 | */ |
||
841 | public function renderRelationField($name, $label, $mode, $value = '', $expanded = false, $buttons = true) |
||
851 | |||
852 | /** |
||
853 | * Renders all fields for the current Record in edit/create/view mode. |
||
854 | * |
||
855 | * @param string $mode (view|edit|create) |
||
856 | * @param array $filterFields Optional list of field names to exclude from rendering |
||
857 | * @param array $readOnlyFields Optional list of fields to render in a readonly fashion when rendering in create or edit mode |
||
858 | * |
||
859 | * @return string |
||
860 | * |
||
861 | * @since 1.0 |
||
862 | */ |
||
863 | public function renderAllFields($mode, $filterFields = array(), $readOnlyFields = array()) |
||
873 | |||
874 | /** |
||
875 | * Loads a template for the Record specified if one exists. Lower level custom templates |
||
876 | * take precedence. |
||
877 | * |
||
878 | * @param \Alpha\Model\ActiveRecord $record |
||
879 | * @param string $mode |
||
880 | * @param array $fields |
||
881 | * |
||
882 | * @return string |
||
883 | * |
||
884 | * @since 1.0 |
||
885 | * |
||
886 | * @throws \Alpha\Exception\IllegalArguementException |
||
887 | */ |
||
888 | public static function loadTemplate($record, $mode, $fields = array()) |
||
972 | |||
973 | /** |
||
974 | * Loads a template fragment from the Renderer/[type]/Fragments/[filename.ext] location. |
||
975 | * |
||
976 | * @param string $type Currently only html supported, later json and xml. |
||
977 | * @param string $fileName The name of the fragment file |
||
978 | * @param array $fields A hash array of field values to pass to the template fragment. |
||
979 | * |
||
980 | * @return string |
||
981 | * |
||
982 | * @since 1.2 |
||
983 | * |
||
984 | * @throws \Alpha\Exception\IllegalArguementException |
||
985 | */ |
||
986 | public static function loadTemplateFragment($type, $fileName, $fields = array()) |
||
1034 | |||
1035 | /** |
||
1036 | * Enables you to set an explicit type of RendererProviderInterface implementation to use for rendering the records |
||
1037 | * attached to this view. |
||
1038 | * |
||
1039 | * @param string $ProviderClassName The name of the RendererProviderInterface implementation to use in this view object |
||
1040 | * @param string $acceptHeader Optional pass the HTTP Accept header to select the correct renderer provider. |
||
1041 | * |
||
1042 | * @since 1.2 |
||
1043 | * |
||
1044 | * @throws \Alpha\Exception\IllegalArguementException |
||
1045 | */ |
||
1046 | public static function setProvider($ProviderClassName, $acceptHeader = null) |
||
1070 | |||
1071 | /** |
||
1072 | * Get the current view renderer provider. |
||
1073 | * |
||
1074 | * @return \Alpha\View\Renderer\RendererProviderInterface |
||
1075 | * |
||
1076 | * @since 2.0 |
||
1077 | */ |
||
1078 | public static function getProvider() |
||
1090 | } |
||
1091 |
Let’s take a look at an example:
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.
Available Fixes
Change the type-hint for the parameter:
Add an additional type-check:
Add the method to the parent class: