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 |
||
| 51 | class Field {
|
||
| 52 | protected $opt; |
||
| 53 | |||
| 54 | protected $name; |
||
| 55 | |||
| 56 | protected $setValue = null; |
||
| 57 | |||
| 58 | protected $valid = true; |
||
| 59 | |||
| 60 | function __construct($name, $options = array()) {
|
||
| 61 | $this->name = $name; |
||
| 62 | $this->hint = ""; |
||
| 63 | $this->opt = $options + array("label" => "$name", "regex" => "", "required" => false,
|
||
| 64 | "default" => "", "error" => "$name is Required", "help" => "", "test" => null, |
||
| 65 | "form" => "noForm", "readonly" => false, 'hinttext' => '', "disabled" => false); |
||
| 66 | } |
||
| 67 | |||
| 68 | function __call($name, $valarray) {
|
||
| 69 | if (count($valarray) < 1) return $this->__get($name); |
||
| 70 | $val = count($valarray) == 1 ? current($valarray) : $valarray; |
||
| 71 | switch ($name) {
|
||
| 72 | case "name": |
||
| 73 | throw new Exception("Unable to change $name after object is created");
|
||
| 74 | case "valid": |
||
| 75 | return $this->valid; |
||
| 76 | case "val": |
||
| 77 | case "value": |
||
| 78 | $this->setValue = $val; |
||
| 79 | break; |
||
| 80 | default: |
||
| 81 | $this->opt[$name] = $val; |
||
| 82 | } |
||
| 83 | return $this; |
||
| 84 | } |
||
| 85 | |||
| 86 | function __get($name) {
|
||
| 87 | switch ($name) {
|
||
| 88 | case "name": |
||
| 89 | return $this->name; |
||
| 90 | case "valid": |
||
| 91 | return $this->valid; |
||
| 92 | case "val": |
||
| 93 | case "value": |
||
| 94 | return $this->getValue(); |
||
| 95 | default: |
||
| 96 | return isset($this->opt[$name]) ? $this->opt[$name] : null; |
||
| 97 | } |
||
| 98 | } |
||
| 99 | |||
| 100 | function __set($name, $val) {
|
||
| 101 | switch ($name) {
|
||
| 102 | case "name": |
||
| 103 | case "valid": |
||
| 104 | throw new Exception("Unable to change $name after object is created");
|
||
| 105 | case "val": |
||
| 106 | case "value": |
||
| 107 | return $this->setValue = $val; |
||
| 108 | default: |
||
| 109 | return isset($this->opt[$name]) ? $this->opt[$name] : null; |
||
| 110 | } |
||
| 111 | } |
||
| 112 | |||
| 113 | function getValue() {
|
||
| 114 | if (!is_null($this->setValue)) return $this->setValue; |
||
| 115 | if (isset($_REQUEST[$this->form . "_" . $this->name])) {
|
||
| 116 | if (get_magic_quotes_runtime()) |
||
| 117 | return stripslashes($_REQUEST[$this->form . "_" . $this->name]); |
||
| 118 | else |
||
| 119 | return $_REQUEST[$this->form . "_" . $this->name]; |
||
| 120 | } |
||
| 121 | return $this->opt['default']; |
||
| 122 | } |
||
| 123 | |||
| 124 | function getInputAttStatic(&$atts, &$type, &$content) {
|
||
| 125 | $atts['id'] = $atts['name'] = $this->form . "_" . $this->name; |
||
| 126 | $atts['type'] = "text"; |
||
| 127 | $atts['class'][] = str_replace(['Seufert\\','\\'],['','_'],get_class($this)); |
||
| 128 | } |
||
| 129 | |||
| 130 | function getInputAttDynamic(&$atts, &$type, &$content) {
|
||
| 131 | $type = "input"; |
||
| 132 | $atts['value'] = new FormField($this->name); |
||
| 133 | if (!$this->valid) {
|
||
| 134 | $atts['class'][] = "hamleFormError"; |
||
| 135 | } |
||
| 136 | if ($this->opt["disabled"]) |
||
| 137 | $atts['disabled'] = "disabled"; |
||
| 138 | if ($this->opt['required']) |
||
| 139 | $atts['required'] = "required"; |
||
| 140 | if ($this->opt['help']) |
||
| 141 | $atts['title'] = $this->opt['help']; |
||
| 142 | } |
||
| 143 | |||
| 144 | function getLabelAttStatic(&$atts, &$type, &$content) {
|
||
| 145 | $atts['class'][] = str_replace(['Seufert\\','\\'],['','_'],get_class($this)); |
||
| 146 | $atts["for"] = $this->form . "_" . $this->name; |
||
| 147 | $content = array($this->opt['label']); |
||
| 148 | } |
||
| 149 | |||
| 150 | function getLabelAttDynamic(&$atts, &$type, &$content) {
|
||
| 151 | } |
||
| 152 | |||
| 153 | function getHintAttStatic(&$atts, &$type, &$content) {
|
||
| 154 | $atts['class'][] = str_replace(['Seufert\\','\\'],['','_'],get_class($this)); |
||
| 155 | $atts['class'][] = "hamleFormHint"; |
||
| 156 | } |
||
| 157 | |||
| 158 | function getHintAttDynamic(&$atts, &$type, &$content) {
|
||
| 159 | $type = "div"; |
||
| 160 | if (!$this->valid) {
|
||
| 161 | $content = array($this->opt['error']); |
||
| 162 | $atts['class'][] = "hamleFormError"; |
||
| 163 | } |
||
| 164 | } |
||
| 165 | |||
| 166 | function getDynamicAtt($base, &$atts, &$type, &$content) {
|
||
| 167 | if ($base == "input") {
|
||
| 168 | $this->getInputAttDynamic($atts, $type, $content); |
||
| 169 | } elseif ($base == "hint") {
|
||
| 170 | $this->getHintAttDynamic($atts, $type, $content); |
||
| 171 | } elseif ($base == "label") {
|
||
| 172 | $this->getLabelAttDynamic($atts, $type, $contnet); |
||
| 173 | } |
||
| 174 | } |
||
| 175 | |||
| 176 | function doProcess($submit) {
|
||
| 177 | if ($submit) {
|
||
| 178 | $value = $this->getValue(); |
||
| 179 | if ($this->opt['required']) |
||
| 180 | $this->valid = $this->valid && strlen($value); |
||
| 181 | if ($this->opt['regex']) |
||
| 182 | $this->valid = $this->valid && preg_match($this->opt['regex'], $value); |
||
| 183 | } |
||
| 184 | } |
||
| 185 | |||
| 186 | } |
||
| 187 |