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 BaseField 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 BaseField, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
8 | abstract class BaseField |
||
9 | { |
||
10 | public function __construct($descriptor = null) |
||
14 | |||
15 | public function descriptor() |
||
19 | |||
20 | public function fullDescriptor() |
||
28 | |||
29 | public function name() |
||
33 | |||
34 | public function title() |
||
38 | |||
39 | public function description() |
||
43 | |||
44 | public function rdfType() |
||
48 | |||
49 | public function format() |
||
53 | |||
54 | public function constraints() |
||
62 | |||
63 | public function required() |
||
67 | |||
68 | public function unique() |
||
72 | |||
73 | public function disableConstraints() |
||
79 | |||
80 | public function enum() |
||
88 | |||
89 | /** |
||
90 | * try to create a field object based on the descriptor |
||
91 | * by default uses the type attribute |
||
92 | * return the created field object or false if the descriptor does not match this field. |
||
93 | * |
||
94 | * @param object $descriptor |
||
95 | * |
||
96 | * @return bool|BaseField |
||
97 | */ |
||
98 | public static function inferDescriptor($descriptor) |
||
106 | |||
107 | /** |
||
108 | * try to create a new field object based on the given value. |
||
109 | * |
||
110 | * @param mixed $val |
||
111 | * @param null|object $descriptor |
||
112 | * @param bool @lenient |
||
113 | * |
||
114 | * @return bool|BaseField |
||
115 | */ |
||
116 | public static function infer($val, $descriptor = null, $lenient = false) |
||
128 | |||
129 | public function inferProperties($val, $lenient) |
||
135 | |||
136 | /** |
||
137 | * @param mixed $val |
||
138 | * |
||
139 | * @return mixed |
||
140 | * |
||
141 | * @throws \frictionlessdata\tableschema\Exceptions\FieldValidationException; |
||
142 | */ |
||
143 | final public function castValue($val) |
||
163 | |||
164 | public function validateValue($val) |
||
174 | |||
175 | /** |
||
176 | * get a unique identifier for this field |
||
177 | * used in the inferring process |
||
178 | * this is usually the type, but can be modified to support more advanced inferring process. |
||
179 | * |
||
180 | * @param bool @lenient |
||
181 | * |
||
182 | * @return string |
||
183 | */ |
||
184 | public function getInferIdentifier($lenient = false) |
||
188 | |||
189 | /** |
||
190 | * should be implemented by extending classes to return the table schema type of this field. |
||
191 | * |
||
192 | * @return string |
||
193 | */ |
||
194 | public static function type() |
||
198 | |||
199 | protected $descriptor; |
||
200 | protected $constraintsDisabled = false; |
||
201 | |||
202 | protected function getValidationException($errorMsg = null, $val = null) |
||
212 | |||
213 | protected function isEmptyValue($val) |
||
217 | |||
218 | /** |
||
219 | * @param mixed $val |
||
220 | * |
||
221 | * @return mixed |
||
222 | * |
||
223 | * @throws \frictionlessdata\tableschema\Exceptions\FieldValidationException; |
||
224 | */ |
||
225 | // extending classes should extend this method |
||
226 | // value is guaranteed not to be an empty value, that is handled elsewhere |
||
227 | // should raise FieldValidationException on any validation errors |
||
228 | // can use getValidationException function to get a simple exception with single validation error message |
||
229 | // you can also throw an exception with multiple validation errors manually |
||
230 | abstract protected function validateCastValue($val); |
||
231 | |||
232 | protected function checkConstraints($val) |
||
294 | |||
295 | protected function checkPatternConstraint($val, $pattern) |
||
299 | |||
300 | protected function checkMinimumConstraint($val, $minConstraint) |
||
304 | |||
305 | protected function checkMaximumConstraint($val, $maxConstraint) |
||
309 | |||
310 | protected function getLengthForConstraint($val) |
||
322 | |||
323 | protected function checkMinLengthConstraint($val, $minLength) |
||
327 | |||
328 | protected function checkMaxLengthConstraint($val, $maxLength) |
||
332 | |||
333 | protected function getAllowedValues() |
||
342 | |||
343 | protected function checkAllowedValues($allowedValues, $val) |
||
347 | |||
348 | protected function castValueNoConstraints($val) |
||
356 | } |
||
357 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.