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 Field 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 Field, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
23 | abstract class Field |
||
24 | { |
||
25 | /** |
||
26 | * The description text for the form field. Usually used in tooltips. |
||
27 | * |
||
28 | * @var string |
||
29 | * @since 1.0 |
||
30 | */ |
||
31 | protected $description; |
||
32 | |||
33 | /** |
||
34 | * The SimpleXMLElement object of the <field /> XML element that describes the form field. |
||
35 | * |
||
36 | * @var SimpleXMLElement |
||
37 | * @since 1.0 |
||
38 | */ |
||
39 | protected $element; |
||
40 | |||
41 | /** |
||
42 | * The Form object of the form attached to the form field. |
||
43 | * |
||
44 | * @var Form |
||
45 | * @since 1.0 |
||
46 | */ |
||
47 | protected $form; |
||
48 | |||
49 | /** |
||
50 | * The form control prefix for field names from the Form object attached to the form field. |
||
51 | * |
||
52 | * @var string |
||
53 | * @since 1.0 |
||
54 | */ |
||
55 | protected $formControl; |
||
56 | |||
57 | /** |
||
58 | * The hidden state for the form field. |
||
59 | * |
||
60 | * @var boolean |
||
61 | * @since 1.0 |
||
62 | */ |
||
63 | protected $hidden = false; |
||
64 | |||
65 | /** |
||
66 | * True to translate the field label string. |
||
67 | * |
||
68 | * @var boolean |
||
69 | * @since 1.0 |
||
70 | */ |
||
71 | protected $translateLabel = true; |
||
72 | |||
73 | /** |
||
74 | * True to translate the field description string. |
||
75 | * |
||
76 | * @var boolean |
||
77 | * @since 1.0 |
||
78 | */ |
||
79 | protected $translateDescription = true; |
||
80 | |||
81 | /** |
||
82 | * The document id for the form field. |
||
83 | * |
||
84 | * @var string |
||
85 | * @since 1.0 |
||
86 | */ |
||
87 | protected $id; |
||
88 | |||
89 | /** |
||
90 | * The input for the form field. |
||
91 | * |
||
92 | * @var string |
||
93 | * @since 1.0 |
||
94 | */ |
||
95 | protected $input; |
||
96 | |||
97 | /** |
||
98 | * The label for the form field. |
||
99 | * |
||
100 | * @var string |
||
101 | * @since 1.0 |
||
102 | */ |
||
103 | protected $label; |
||
104 | |||
105 | /** |
||
106 | * The multiple state for the form field. If true then multiple values are allowed for the |
||
107 | * field. Most often used for list field types. |
||
108 | * |
||
109 | * @var boolean |
||
110 | * @since 1.0 |
||
111 | */ |
||
112 | protected $multiple = false; |
||
113 | |||
114 | /** |
||
115 | * The name of the form field. |
||
116 | * |
||
117 | * @var string |
||
118 | * @since 1.0 |
||
119 | */ |
||
120 | protected $name; |
||
121 | |||
122 | /** |
||
123 | * The name of the field. |
||
124 | * |
||
125 | * @var string |
||
126 | * @since 1.0 |
||
127 | */ |
||
128 | protected $fieldname; |
||
129 | |||
130 | /** |
||
131 | * The group of the field. |
||
132 | * |
||
133 | * @var string |
||
134 | * @since 1.0 |
||
135 | */ |
||
136 | protected $group; |
||
137 | |||
138 | /** |
||
139 | * The required state for the form field. If true then there must be a value for the field to |
||
140 | * be considered valid. |
||
141 | * |
||
142 | * @var boolean |
||
143 | * @since 1.0 |
||
144 | */ |
||
145 | protected $required = false; |
||
146 | |||
147 | /** |
||
148 | * The disabled state for the form field. If true then there must not be a possibility |
||
149 | * to change the pre-selected value, and the value must not be submitted by the browser. |
||
150 | * |
||
151 | * @var boolean |
||
152 | * @since 1.0 |
||
153 | */ |
||
154 | protected $disabled = false; |
||
155 | |||
156 | /** |
||
157 | * The readonly state for the form field. If true then there must not be a possibility |
||
158 | * to change the pre-selected value, and the value must submitted by the browser. |
||
159 | * |
||
160 | * @var boolean |
||
161 | * @since 1.0 |
||
162 | */ |
||
163 | protected $readonly = false; |
||
164 | |||
165 | /** |
||
166 | * The form field type. |
||
167 | * |
||
168 | * @var string |
||
169 | * @since 1.0 |
||
170 | */ |
||
171 | protected $type; |
||
172 | |||
173 | /** |
||
174 | * The validation method for the form field. This value will determine which method is used |
||
175 | * to validate the value for a field. |
||
176 | * |
||
177 | * @var string |
||
178 | * @since 1.0 |
||
179 | */ |
||
180 | protected $validate; |
||
181 | |||
182 | /** |
||
183 | * The value of the form field. |
||
184 | * |
||
185 | * @var mixed |
||
186 | * @since 1.0 |
||
187 | */ |
||
188 | protected $value; |
||
189 | |||
190 | /** |
||
191 | * The label's CSS class of the form field |
||
192 | * |
||
193 | * @var mixed |
||
194 | * @since 1.0 |
||
195 | */ |
||
196 | protected $labelClass; |
||
197 | |||
198 | /** |
||
199 | * The count value for generated name field |
||
200 | * |
||
201 | * @var integer |
||
202 | * @since 1.0 |
||
203 | */ |
||
204 | protected static $count = 0; |
||
205 | |||
206 | /** |
||
207 | * The string used for generated fields names |
||
208 | * |
||
209 | * @var string |
||
210 | * @since 1.0 |
||
211 | */ |
||
212 | protected static $generated_fieldname = '__field'; |
||
213 | |||
214 | /** |
||
215 | * Method to instantiate the form field object. |
||
216 | * |
||
217 | * @param Form $form The form to attach to the form field object. |
||
218 | * |
||
219 | * @since 1.0 |
||
220 | */ |
||
221 | public function __construct(Form $form = null) |
||
245 | |||
246 | /** |
||
247 | * Method to get certain otherwise inaccessible properties from the form field object. |
||
248 | * |
||
249 | * @param string $name The property name for which to the the value. |
||
250 | * |
||
251 | * @return mixed The property value or null. |
||
252 | * |
||
253 | * @since 1.0 |
||
254 | */ |
||
255 | public function __get($name) |
||
300 | |||
301 | /** |
||
302 | * Method to attach a Form object to the field. |
||
303 | * |
||
304 | * @param Form $form The Form object to attach to the form field. |
||
305 | * |
||
306 | * @return Field The form field object so that the method can be used in a chain. |
||
307 | * |
||
308 | * @since 1.0 |
||
309 | */ |
||
310 | public function setForm(Form $form) |
||
317 | |||
318 | /** |
||
319 | * Method to attach a Form object to the field. |
||
320 | * |
||
321 | * @param SimpleXMLElement $element The SimpleXMLElement object representing the <field /> tag for the form field object. |
||
322 | * @param mixed $value The form field value to validate. |
||
323 | * @param string $group The field name group control value. This acts as as an array container for the field. |
||
324 | * For example if the field has name="foo" and the group value is set to "bar" then the |
||
325 | * full field name would end up being "bar[foo]". |
||
326 | * |
||
327 | * @return boolean True on success. |
||
328 | * |
||
329 | * @since 1.0 |
||
330 | */ |
||
331 | public function setup(SimpleXMLElement $element, $value, $group = null) |
||
413 | |||
414 | /** |
||
415 | * Method to get the id used for the field input tag. |
||
416 | * |
||
417 | * @param string $fieldId The field element id. |
||
418 | * @param string $fieldName The field element name. |
||
419 | * |
||
420 | * @return string The id to be used for the field input tag. |
||
421 | * |
||
422 | * @since 1.0 |
||
423 | */ |
||
424 | protected function getId($fieldId, $fieldName) |
||
463 | |||
464 | /** |
||
465 | * Method to get the field input markup. |
||
466 | * |
||
467 | * @return string The field input markup. |
||
468 | * |
||
469 | * @since 1.0 |
||
470 | */ |
||
471 | abstract protected function getInput(); |
||
472 | |||
473 | /** |
||
474 | * Method to get the field title. |
||
475 | * |
||
476 | * @return string The field title. |
||
477 | * |
||
478 | * @since 1.0 |
||
479 | */ |
||
480 | protected function getTitle() |
||
495 | |||
496 | /** |
||
497 | * Method to get the field label markup. |
||
498 | * |
||
499 | * @return string The field label markup. |
||
500 | * |
||
501 | * @since 1.0 |
||
502 | */ |
||
503 | protected function getLabel() |
||
546 | |||
547 | /** |
||
548 | * Method to get the name used for the field input tag. |
||
549 | * |
||
550 | * @param string $fieldName The field element name. |
||
551 | * |
||
552 | * @return string The name to be used for the field input tag. |
||
553 | * |
||
554 | * @since 1.0 |
||
555 | */ |
||
556 | protected function getName($fieldName) |
||
608 | |||
609 | /** |
||
610 | * Method to get the field name used. |
||
611 | * |
||
612 | * @param string $fieldName The field element name. |
||
613 | * |
||
614 | * @return string The field name |
||
615 | * |
||
616 | * @since 1.0 |
||
617 | */ |
||
618 | protected function getFieldName($fieldName) |
||
631 | } |
||
632 |
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.