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 Validation_Core 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 Validation_Core, and based on these observations, apply Extract Interface, too.
1 | <?php defined('SYSPATH') or die('No direct access allowed.'); |
||
12 | class Validation_Core extends ArrayObject |
||
13 | { |
||
14 | |||
15 | // Filters |
||
16 | protected $pre_filters = array(); |
||
17 | protected $post_filters = array(); |
||
18 | |||
19 | // Rules and callbacks |
||
20 | protected $rules = array(); |
||
21 | protected $callbacks = array(); |
||
22 | |||
23 | // Rules that are allowed to run on empty fields |
||
24 | protected $empty_rules = array('required', 'matches'); |
||
25 | |||
26 | // Errors |
||
27 | protected $errors = array(); |
||
28 | protected $messages = array(); |
||
29 | |||
30 | // Fields that are expected to be arrays |
||
31 | protected $array_fields = array(); |
||
32 | |||
33 | // Checks if there is data to validate. |
||
34 | protected $submitted; |
||
35 | |||
36 | /** |
||
37 | * Creates a new Validation instance. |
||
38 | * |
||
39 | * @param array array to use for validation |
||
40 | * @return object |
||
|
|||
41 | */ |
||
42 | public static function factory(array $array) |
||
46 | |||
47 | /** |
||
48 | * Sets the unique "any field" key and creates an ArrayObject from the |
||
49 | * passed array. |
||
50 | * |
||
51 | * @param array array to validate |
||
52 | * @return void |
||
53 | */ |
||
54 | public function __construct(array $array) |
||
61 | |||
62 | /** |
||
63 | * Magic clone method, clears errors and messages. |
||
64 | * |
||
65 | * @return void |
||
66 | */ |
||
67 | public function __clone() |
||
72 | |||
73 | /** |
||
74 | * Create a copy of the current validation rules and change the array. |
||
75 | * |
||
76 | * @chainable |
||
77 | * @param array new array to validate |
||
78 | * @return Validation_Core |
||
79 | */ |
||
80 | public function copy(array $array) |
||
88 | |||
89 | /** |
||
90 | * Test if the data has been submitted. |
||
91 | * |
||
92 | * @return boolean |
||
93 | */ |
||
94 | public function submitted($value = null) |
||
102 | |||
103 | /** |
||
104 | * Returns an array of all the field names that have filters, rules, or callbacks. |
||
105 | * |
||
106 | * @return array |
||
107 | */ |
||
108 | public function field_names() |
||
123 | |||
124 | /** |
||
125 | * Returns the array values of the current object. |
||
126 | * |
||
127 | * @return array |
||
128 | */ |
||
129 | public function as_array() |
||
133 | |||
134 | /** |
||
135 | * Returns the ArrayObject values, removing all inputs without rules. |
||
136 | * To choose specific inputs, list the field name as arguments. |
||
137 | * |
||
138 | * @param boolean return only fields with filters, rules, and callbacks |
||
139 | * @return array |
||
140 | */ |
||
141 | public function safe_array() |
||
172 | |||
173 | /** |
||
174 | * Add additional rules that will forced, even for empty fields. All arguments |
||
175 | * passed will be appended to the list. |
||
176 | * |
||
177 | * @chainable |
||
178 | * @param string rule name |
||
179 | * @return Validation_Core |
||
180 | */ |
||
181 | public function allow_empty_rules($rules) |
||
191 | |||
192 | /** |
||
193 | * Converts a filter, rule, or callback into a fully-qualified callback array. |
||
194 | * |
||
195 | * @return callable |
||
196 | */ |
||
197 | protected function callback($callback) |
||
233 | |||
234 | /** |
||
235 | * Add a pre-filter to one or more inputs. Pre-filters are applied before |
||
236 | * rules or callbacks are executed. |
||
237 | * |
||
238 | * @chainable |
||
239 | * @param callback filter |
||
240 | * @param string fields to apply filter to, use TRUE for all fields |
||
241 | * @return Validation_Core |
||
242 | */ |
||
243 | View Code Duplication | public function pre_filter($filter, $field = true) |
|
264 | |||
265 | /** |
||
266 | * Add a post-filter to one or more inputs. Post-filters are applied after |
||
267 | * rules and callbacks have been executed. |
||
268 | * |
||
269 | * @chainable |
||
270 | * @param callback filter |
||
271 | * @param string fields to apply filter to, use TRUE for all fields |
||
272 | * @return Validation_Core |
||
273 | */ |
||
274 | View Code Duplication | public function post_filter($filter, $field = true) |
|
295 | |||
296 | /** |
||
297 | * Add rules to a field. Validation rules may only return TRUE or FALSE and |
||
298 | * can not manipulate the value of a field. |
||
299 | * |
||
300 | * @chainable |
||
301 | * @param string field name |
||
302 | * @param callback rules (one or more arguments) |
||
303 | * @return Validation_Core |
||
304 | */ |
||
305 | public function add_rules($field, $rules) |
||
345 | |||
346 | /** |
||
347 | * Add callbacks to a field. Callbacks must accept the Validation object |
||
348 | * and the input name. Callback returns are not processed. |
||
349 | * |
||
350 | * @chainable |
||
351 | * @param string field name |
||
352 | * @param callbacks callbacks (unlimited number) |
||
353 | * @return Validation_Core |
||
354 | */ |
||
355 | View Code Duplication | public function add_callbacks($field, $callbacks) |
|
376 | |||
377 | /** |
||
378 | * Validate by processing pre-filters, rules, callbacks, and post-filters. |
||
379 | * All fields that have filters, rules, or callbacks will be initialized if |
||
380 | * they are undefined. Validation will only be run if there is data already |
||
381 | * in the array. |
||
382 | * |
||
383 | * @param object Validation object, used only for recursion |
||
384 | * @param object name of field for errors |
||
385 | * @return bool |
||
386 | */ |
||
387 | public function validate($object = null, $field_name = null) |
||
549 | |||
550 | /** |
||
551 | * Add an error to an input. |
||
552 | * |
||
553 | * @chainable |
||
554 | * @param string input name |
||
555 | * @param string unique error name |
||
556 | * @return Validation_Core |
||
557 | */ |
||
558 | public function add_error($field, $name) |
||
564 | |||
565 | /** |
||
566 | * Sets or returns the message for an input. |
||
567 | * |
||
568 | * @chainable |
||
569 | * @param string input key |
||
570 | * @param string message to set |
||
571 | * @return string|object |
||
572 | */ |
||
573 | public function message($input = null, $message = null) |
||
600 | |||
601 | /** |
||
602 | * Return the errors array. |
||
603 | * |
||
604 | * @param boolean load errors from a lang file |
||
605 | * @return array |
||
606 | */ |
||
607 | public function errors($file = null) |
||
626 | |||
627 | /** |
||
628 | * Rule: required. Generates an error if the field has an empty value. |
||
629 | * |
||
630 | * @param mixed input value |
||
631 | * @return bool |
||
632 | */ |
||
633 | public function required($str) |
||
646 | |||
647 | /** |
||
648 | * Rule: matches. Generates an error if the field does not match one or more |
||
649 | * other fields. |
||
650 | * |
||
651 | * @param mixed input value |
||
652 | * @param array input names to match against |
||
653 | * @return bool |
||
654 | */ |
||
655 | public function matches($str, array $inputs) |
||
665 | |||
666 | /** |
||
667 | * Rule: length. Generates an error if the field is too long or too short. |
||
668 | * |
||
669 | * @param mixed input value |
||
670 | * @param array minimum, maximum, or exact length to match |
||
671 | * @return bool |
||
672 | */ |
||
673 | public function length($str, array $length) |
||
694 | |||
695 | /** |
||
696 | * Rule: depends_on. Generates an error if the field does not depend on one |
||
697 | * or more other fields. |
||
698 | * |
||
699 | * @param mixed field name |
||
700 | * @param array field names to check dependency |
||
701 | * @return bool |
||
702 | */ |
||
703 | public function depends_on($field, array $fields) |
||
713 | |||
714 | /** |
||
715 | * Rule: chars. Generates an error if the field contains characters outside of the list. |
||
716 | * |
||
717 | * @param string field value |
||
718 | * @param array allowed characters |
||
719 | * @return bool |
||
720 | */ |
||
721 | public function chars($value, array $chars) |
||
725 | } // End Validation |
||
726 |
This check looks for the generic type
array
as a return type and suggests a more specific type. This type is inferred from the actual code.