| Total Complexity | 60 |
| Total Lines | 324 |
| Duplicated Lines | 0 % |
| Changes | 0 | ||
Complex classes like OptionDisplay 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.
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 OptionDisplay, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 24 | class OptionDisplay { |
||
| 25 | |||
| 26 | /** |
||
| 27 | * stores all the options we are caring about |
||
| 28 | * |
||
| 29 | * @var array |
||
| 30 | */ |
||
| 31 | private $listOfOptions; |
||
| 32 | |||
| 33 | /** |
||
| 34 | * on which level are we operating? |
||
| 35 | * |
||
| 36 | * @var string |
||
| 37 | */ |
||
| 38 | private $level; |
||
| 39 | |||
| 40 | /** |
||
| 41 | * a counter storing how many locations are to be displayed |
||
| 42 | * |
||
| 43 | * @var int |
||
| 44 | */ |
||
| 45 | private $allLocationCount; |
||
| 46 | |||
| 47 | /** |
||
| 48 | * When "fresh" options are displayed (HTML select/otion fields, optionally |
||
| 49 | * with language, and of varying data types) we want to give each option |
||
| 50 | * the same prominence and iterate over all options in the list. This |
||
| 51 | * variable keeps track how many option HTML code we've already sent, so |
||
| 52 | * that we can iterate correctly. |
||
| 53 | * |
||
| 54 | * Only used inside noPrefillText variant of the optiontext() call |
||
| 55 | * |
||
| 56 | * @var int |
||
| 57 | */ |
||
| 58 | private $optionIterator; |
||
| 59 | |||
| 60 | /** |
||
| 61 | * Which attributes are we talking about? |
||
| 62 | * @param array $options the options of interest |
||
| 63 | * @param string $level the level on which these options were defined by the user |
||
| 64 | */ |
||
| 65 | public function __construct(array $options, string $level) { |
||
| 66 | $this->listOfOptions = $options; |
||
| 67 | $this->level = $level; |
||
| 68 | $this->allLocationCount = 0; |
||
| 69 | } |
||
| 70 | |||
| 71 | /** |
||
| 72 | * creates a table with all the set options prefilled. Only displays options |
||
| 73 | * of the category indicated. |
||
| 74 | * @param string $attributePrefix category of option to display |
||
| 75 | * @return string HTML code <table> |
||
| 76 | */ |
||
| 77 | public function prefilledOptionTable(string $attributePrefix) { |
||
| 89 | } |
||
| 90 | |||
| 91 | /** |
||
| 92 | * Displays options for a given option class. |
||
| 93 | * |
||
| 94 | * @param string $class the class of options that is to be displayed |
||
| 95 | * @param array $prepopulate should an empty set of fillable options be displayed, or do we have existing data to prefill with |
||
| 96 | */ |
||
| 97 | private function addOption(string $class, array $prepopulate = []) { // no GET class ? we've been called directly: |
||
| 142 | } |
||
| 143 | |||
| 144 | /** |
||
| 145 | * HTML code to display a "fresh" option (including type selector and JavaScript to show/hide relevant input fields) |
||
| 146 | * @param int $rowid the HTML field base name of the option to be displayed |
||
| 147 | * @param array $list the list of option names to include in the type selector |
||
| 148 | * @return string HTML code |
||
| 149 | * @throws Exception |
||
| 150 | */ |
||
| 151 | private function noPrefillText(int $rowid, array $list) { |
||
| 152 | $retval = ""; |
||
| 153 | $optioninfo = \core\Options::instance(); |
||
| 154 | $jsmagic = "onchange=' |
||
| 155 | if (/#ML#/.test(document.getElementById(\"option-S" . $rowid . "-select\").value)) { |
||
| 156 | document.getElementById(\"S$rowid-input-langselect\").style.display = \"block\"; |
||
| 157 | } else { |
||
| 158 | document.getElementById(\"S$rowid-input-langselect\").style.display = \"none\"; |
||
| 159 | }"; |
||
| 160 | $dataTypes = ["file", "text", "string", "boolean", "integer"]; |
||
| 161 | foreach ($dataTypes as $oneDataType) { |
||
| 162 | // TODO make this a $jsmagic .= after the update of cat-pilot |
||
| 163 | $jsmagic .= "if (/#$oneDataType#/.test(document.getElementById(\"option-S" . $rowid . "-select\").value)) { |
||
| 164 | document.getElementById(\"S$rowid-input-file\").style.display = \"" . ($oneDataType == "file" ? "block" : "none") . "\"; |
||
| 165 | document.getElementById(\"S$rowid-input-text\").style.display = \"" . ($oneDataType == "text" ? "block" : "none") . "\"; |
||
| 166 | document.getElementById(\"S$rowid-input-string\").style.display = \"" . ($oneDataType == "string" ? "block" : "none") . "\"; |
||
| 167 | document.getElementById(\"S$rowid-input-boolean\").style.display = \"" . ($oneDataType == "boolean" ? "block" : "none") . "\"; |
||
| 168 | document.getElementById(\"S$rowid-input-integer\").style.display = \"" . ($oneDataType == "integer" ? "block" : "none") . "\"; |
||
| 169 | } |
||
| 170 | "; |
||
| 171 | } |
||
| 172 | $jsmagic .= "'"; |
||
| 173 | $retval .= "<td><select id='option-S$rowid-select' name='option[S$rowid]' $jsmagic>"; |
||
| 174 | $iterator = 0; |
||
| 175 | $uiElements = new UIElements(); |
||
| 176 | $activelisttype = []; |
||
| 177 | foreach ($list as $value) { |
||
| 178 | $listtype = $optioninfo->optionType($value); |
||
| 179 | $retval .= "<option id='option-S$rowid-v-$value' value='$value#" . $listtype["type"] . "#" . $listtype["flag"] . "#' "; |
||
| 180 | if ($iterator == $this->optionIterator) { |
||
| 181 | $retval .= "selected='selected'"; |
||
| 182 | $activelisttype = $listtype; |
||
| 183 | } |
||
| 184 | $retval .= ">" . $uiElements->displayName($value) . "</option>"; |
||
| 185 | $iterator++; |
||
| 186 | } |
||
| 187 | if (count($activelisttype) == 0) { |
||
| 188 | throw new \Exception("We should have found the active list type by now!"); |
||
| 189 | } |
||
| 190 | $retval .= "</select></td>"; |
||
| 191 | $retval .= "<td> |
||
| 192 | <select style='display:" . ($activelisttype["flag"] == "ML" ? "block" : "none") . "' name='value[S$rowid-lang]' id='S" . $rowid . "-input-langselect'> |
||
| 193 | <option value='' name='select_language' selected>" . _("select language") . "</option> |
||
| 194 | <option value='C' name='all_languages'>" . _("default/other languages") . "</option>"; |
||
| 195 | foreach (CONFIG['LANGUAGES'] as $langindex => $possibleLang) { |
||
| 196 | $thislang = $possibleLang['display']; |
||
| 197 | $retval .= "<option value='$langindex' name='$langindex'>$thislang</option>"; |
||
| 198 | } |
||
| 199 | $retval .= "</select></td><td> |
||
| 200 | <input type='text' style='display:" . ($activelisttype["type"] == "string" ? "block" : "none") . "' name='value[S$rowid-0]' id='S" . $rowid . "-input-string'> |
||
| 201 | <textarea cols='30' rows='3' style='display:" . ($activelisttype["type"] == "text" ? "block" : "none") . "' name='value[S$rowid-1]' id='S" . $rowid . "-input-text'></textarea> |
||
| 202 | <input type='file' style='display:" . ($activelisttype["type"] == "file" ? "block" : "none") . "' name='value[S$rowid-2]' id='S" . $rowid . "-input-file' size='10'> |
||
| 203 | <input type='checkbox' style='display:" . ($activelisttype["type"] == "boolean" ? "block" : "none") . "' name='value[S$rowid-3]' id='S" . $rowid . "-input-boolean'> |
||
| 204 | <input type='number' style='display:" . ($activelisttype["type"] == "integer" ? "block" : "none") . "' name='value[S$rowid-4]' id='S" . $rowid . "-input-integer'>"; |
||
| 205 | $retval .= "</td>"; |
||
| 206 | |||
| 207 | return $retval; |
||
| 208 | } |
||
| 209 | |||
| 210 | const TYPECODE_STRING = 0; |
||
| 211 | const TYPECODE_INTEGER = 4; |
||
| 212 | const TYPECODE_TEXT = 1; |
||
| 213 | const TYPECODE_BOOLEAN = 3; |
||
| 214 | |||
| 215 | /** |
||
| 216 | * generates HTML code that displays an already set option. |
||
| 217 | * |
||
| 218 | * @param int $rowid the HTML field base name of the option to be displayed |
||
| 219 | * @param string $optionName the name of the option to display |
||
| 220 | * @param string $optionValue the value of the option to display |
||
| 221 | * @param mixed $optionLang the language of the option to display |
||
| 222 | * @return string HTML code |
||
| 223 | * @throws Exception |
||
| 224 | */ |
||
| 225 | private function prefillText(int $rowid, string $optionName, string $optionValue, $optionLang) { |
||
| 226 | $retval = ""; |
||
| 227 | $optioninfo = \core\Options::instance(); |
||
| 228 | $loggerInstance = new \core\common\Logging(); |
||
| 229 | $loggerInstance->debug(5, "Executed with PREFILL $optionValue!\n"); |
||
| 230 | $retval .= "<td>"; |
||
| 231 | $uiElements = new UIElements(); |
||
| 232 | $listtype = $optioninfo->optionType($optionName); |
||
| 233 | $retval .= $uiElements->displayName($optionName); |
||
| 234 | $retval .= $uiElements->tooltip($optionName); |
||
| 235 | $retval .= "<input type='hidden' id='option-S$rowid-select' name='option[S$rowid]' value='$optionName#" . $listtype["type"] . "#" . $listtype["flag"] . "#' ></td>"; |
||
| 236 | |||
| 237 | // language tag if any |
||
| 238 | $retval .= "<td>"; |
||
| 239 | if ($listtype["flag"] == "ML") { |
||
| 240 | |||
| 241 | $language = "(" . strtoupper($optionLang) . ")"; |
||
| 242 | if ($optionLang == 'C') { |
||
| 243 | $language = _("(default/other languages)"); |
||
| 244 | } |
||
| 245 | $retval .= $language; |
||
| 246 | $retval .= "<input type='hidden' name='value[S$rowid-lang]' id='S" . $rowid . "-input-langselect' value='" . $optionLang . "' style='display:block'>"; |
||
| 247 | } |
||
| 248 | $retval .= "</td>"; |
||
| 249 | // attribute content |
||
| 250 | $retval .= "<td>"; |
||
| 251 | $intCode = -1; |
||
| 252 | $displayedVariant = ""; |
||
| 253 | switch ($listtype["type"]) { |
||
| 254 | case "coordinates": |
||
| 255 | $this->allLocationCount = $this->allLocationCount + 1; |
||
| 256 | $link = "<button id='location_b_" . $this->allLocationCount . "' class='location_button'>" . _("Click to see location") . " $this->allLocationCount</button>"; |
||
| 257 | $retval .= "<input readonly style='display:none' type='text' name='value[S$rowid-" . self::TYPECODE_TEXT . "]' id='S$rowid-input-text' value='$optionValue'>$link"; |
||
| 258 | break; |
||
| 259 | case "file": |
||
| 260 | $retval .= "<input readonly type='text' name='value[S$rowid-1]' id='S" . $rowid . "-input-string' style='display:none' value='" . urlencode($optionValue) . "'>"; |
||
| 261 | $uiElements = new UIElements(); |
||
| 262 | switch ($optionName) { |
||
| 263 | case "eap:ca_file": |
||
| 264 | $retval .= $uiElements->previewCAinHTML($optionValue); |
||
| 265 | break; |
||
| 266 | case "general:logo_file": |
||
| 267 | case "fed:logo_file": |
||
| 268 | $retval .= $uiElements->previewImageinHTML($optionValue); |
||
| 269 | break; |
||
| 270 | case "support:info_file": |
||
| 271 | $retval .= $uiElements->previewInfoFileinHTML($optionValue); |
||
| 272 | break; |
||
| 273 | default: |
||
| 274 | $retval .= _("file content"); |
||
| 275 | } |
||
| 276 | break; |
||
| 277 | case "string": |
||
| 278 | if ($intCode == -1) { |
||
| 279 | $intCode = self::TYPECODE_STRING; |
||
| 280 | } |
||
| 281 | // fall-thorugh is intentional; mostly identical HTML code for the three types |
||
| 282 | case "integer": |
||
| 283 | if ($intCode == -1) { |
||
| 284 | $intCode = self::TYPECODE_INTEGER; |
||
| 285 | } |
||
| 286 | // fall-thorugh is intentional; mostly identical HTML code for the three types |
||
| 287 | case "text": |
||
| 288 | if ($intCode == -1) { |
||
| 289 | $intCode = self::TYPECODE_TEXT; |
||
| 290 | } |
||
| 291 | $displayedVariant = $optionValue; // for all three types, value tag and actual display are identical |
||
| 292 | case "boolean": |
||
| 293 | if ($intCode == -1) { |
||
| 294 | $intCode = self::TYPECODE_BOOLEAN; |
||
| 295 | } |
||
| 296 | if ($displayedVariant == "") { // a fall-through has set this before |
||
| 297 | $displayedVariant = _("off"); |
||
| 298 | if ($optionValue == "on") { |
||
| 299 | /// Device assessment is "on" |
||
| 300 | $displayedVariant = _("on"); |
||
| 301 | } |
||
| 302 | } |
||
| 303 | $retval .= "<strong>$displayedVariant</strong><input type='hidden' name='value[S$rowid-$intCode]' id='S" . $rowid . "-input-" . $listtype["type"] . "' value=\"" . htmlspecialchars($optionValue) . "\" style='display:block'>"; |
||
| 304 | break; |
||
| 305 | default: |
||
| 306 | // this should never happen! |
||
| 307 | throw new Exception("Internal Error: unknown attribute type $listtype!"); |
||
| 308 | } |
||
| 309 | $retval .= "</td>"; |
||
| 310 | return $retval; |
||
| 311 | } |
||
| 312 | |||
| 313 | /** |
||
| 314 | * Displays a container for options. Either with prefilled data or empty; if |
||
| 315 | * empty then has HTML <input> tags with clever javaScript to allow selection |
||
| 316 | * of different option names and types |
||
| 317 | * @param array $list options which should be displayed; can be only exactly one if existing option, or multiple if new option type |
||
| 318 | * @param string $prefillValue for an existing option, it's value to be displayed |
||
| 319 | * @param string $prefillLang for an existing option, the language of the value to be displayed |
||
| 320 | * @return string HTML code <tr> |
||
| 321 | */ |
||
| 322 | public function optiontext(array $list, string $prefillValue = NULL, string $prefillLang = NULL) { |
||
| 348 | } |
||
| 349 | |||
| 350 | } |
||
| 351 |
This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.