Passed
Push — master ( 86c8ba...4a8f0a )
by Tomasz
20:05 queued 07:20
created

OptionDisplay::prefillText()   C

Complexity

Conditions 14
Paths 45

Size

Total Lines 67
Code Lines 55

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 14
eloc 55
nc 45
nop 4
dl 0
loc 67
rs 5.8135
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * ******************************************************************************
5
 * Copyright 2011-2017 DANTE Ltd. and GÉANT on behalf of the GN3, GN3+, GN4-1 
6
 * and GN4-2 consortia
7
 *
8
 * License: see the web/copyright.php file in the file structure
9
 * ******************************************************************************
10
 */
11
12
namespace web\lib\admin;
13
14
use Exception;
15
16
require_once(dirname(dirname(dirname(dirname(__FILE__)))) . "/config/_config.php");
17
18
/**
19
 * We need to display previously set options in various forms. This class covers
20
 * the ways to do that; the generated page content can then be parsed with 
21
 * OptionParser.
22
 * 
23
 * @author Stefan Winter <[email protected]>
24
 */
25
class OptionDisplay {
26
27
    /**
28
     * stores all the options we are caring about
29
     * 
30
     * @var array
31
     */
32
    private $listOfOptions;
33
34
    /**
35
     * on which level are we operating?
36
     * 
37
     * @var string
38
     */
39
    private $level;
40
41
    /**
42
     * a counter storing how many locations are to be displayed
43
     * 
44
     * @var int
45
     */
46
    private $allLocationCount;
47
48
    /**
49
     * When "fresh" options are displayed (HTML select/otion fields, optionally
50
     * with language, and of varying data types) we want to give each option
51
     * the same prominence and iterate over all options in the list. This
52
     * variable keeps track how many option HTML code we've already sent, so
53
     * that we can iterate correctly.
54
     * 
55
     * Only used inside noPrefillText variant of the optiontext() call
56
     * 
57
     * @var int
58
     */
59
    private $optionIterator;
60
61
    /**
62
     * Which attributes are we talking about?
63
     * @param array $options the options of interest
64
     * @param string $level the level on which these options were defined by the user
65
     */
66
    public function __construct(array $options, string $level) {
67
        $this->listOfOptions = $options;
68
        $this->level = $level;
69
        $this->allLocationCount = 0;
70
    }
71
72
    /**
73
     * creates a table with all the set options prefilled. Only displays options
74
     * of the category indicated.
75
     * @param string $attributePrefix category of option to display
76
     * @return string HTML code <table>
77
     */
78
    public function prefilledOptionTable(string $attributePrefix) {
79
        $retval = "<table id='expandable_$attributePrefix" . "_options'>";
80
81
        $prepopulate = [];
82
        foreach ($this->listOfOptions as $existingAttribute) {
83
            if ($existingAttribute['level'] == $this->level) {
84
                $prepopulate[] = $existingAttribute;
85
            }
86
        }
87
        $retval .= $this->addOption($attributePrefix, $prepopulate);
88
        $retval .= "</table>";
89
        return $retval;
90
    }
91
92
    /**
93
     * Displays options for a given option class.
94
     * 
95
     * @param string $class the class of options that is to be displayed
96
     * @param array $prepopulate should an empty set of fillable options be displayed, or do we have existing data to prefill with
97
     */
98
    private function addOption(string $class, array $prepopulate = []) { // no GET class ? we've been called directly:
99
        // this can mean either a new object (list all options with empty values)
100
        // or that an object is to be edited. In that case, $prepopulated has to
101
        // contain the array of existing variables
102
        // we expect the variable $class to contain the class of options
103
        $retval = "";
104
105
        $optioninfo = \core\Options::instance();
106
107
        if (is_array($prepopulate) && ( count($prepopulate) > 1 || $class == "device-specific" || $class == "eap-specific")) { // editing... fill with values
108
            foreach ($prepopulate as $option) {
109
                if (preg_match("/$class:/", $option['name']) && !preg_match("/(user:fedadmin)/", $option['name'])) {
110
                    $optiontypearray = $optioninfo->optionType($option['name']);
111
                    $loggerInstance = new \core\common\Logging();
112
                    $loggerInstance->debug(5, "About to execute optiontext with PREFILL!\n");
113
                    $retval .= $this->optiontext([$option['name']], ($optiontypearray["type"] == "file" ? 'ROWID-' . $option['level'] . '-' . $option['row'] : $option['value']), $option['lang']);
114
                }
115
            }
116
        } else { // not editing exist, this in new: add empty list
117
            $list = $optioninfo->availableOptions($class);
118
            switch ($class) {
119
                case "general":
120
                    $blacklistItem = array_search("general:geo_coordinates", $list);
121
                    break;
122
                case "profile":
123
                    $blacklistItem = array_search("profile:QR-user", $list);
124
                    break;
125
                case "user":
126
                    $blacklistItem = array_search("user:fedadmin", $list);
127
                    break;
128
                default:
129
                    $blacklistItem = FALSE;
130
            }
131
            if ($blacklistItem !== FALSE) {
132
                unset($list[$blacklistItem]);
133
                $list = array_values($list);
134
            }
135
136
            // add as many options as there are different option types
137
            $numberOfOptions = count($list);
138
            for ($this->optionIterator = 0; $this->optionIterator < $numberOfOptions; $this->optionIterator++) {
139
                $retval .= $this->optiontext($list);
140
            }
141
        }
142
        return $retval;
143
    }
144
145
    private function selectElement($rowid, $list) {
146
        $jsmagic = "onchange='
147
                               if (/#ML#/.test(document.getElementById(\"option-S" . $rowid . "-select\").value)) {
148
                                   document.getElementById(\"S$rowid-input-langselect\").style.display = \"block\";
149
                                   } else {
150
                                   document.getElementById(\"S$rowid-input-langselect\").style.display = \"none\";
151
                                   }";
152
        foreach (array_keys(OptionDisplay::HTML_DATATYPE_TEXTS) as $key) {
153
            $jsmagic .= "if (/#" . $key . "#/.test(document.getElementById(\"option-S" . $rowid . "-select\").value)) {
154
                                  document.getElementById(\"S$rowid-input-file\").style.display = \"" . ($key == \core\Options::TYPECODE_FILE ? "block" : "none") . "\";
155
                                  document.getElementById(\"S$rowid-input-text\").style.display = \"" . ($key == \core\Options::TYPECODE_TEXT ? "block" : "none") . "\";
156
                                  document.getElementById(\"S$rowid-input-string\").style.display = \"" . ($key == \core\Options::TYPECODE_STRING ? "block" : "none") . "\";
157
                                  document.getElementById(\"S$rowid-input-boolean\").style.display = \"" . ($key == \core\Options::TYPECODE_BOOLEAN ? "block" : "none") . "\";
158
                                  document.getElementById(\"S$rowid-input-integer\").style.display = \"" . ($key == \core\Options::TYPECODE_INTEGER ? "block" : "none") . "\";
159
                             }
160
                             ";
161
        }
162
        $jsmagic .= "'";
163
164
        $optioninfo = \core\Options::instance();
165
        $retval = "<select id='option-S$rowid-select' name='option[S$rowid]' $jsmagic>";
166
        $iterator = 0;
167
        $uiElements = new UIElements();
168
        $activelisttype = [];
169
        foreach ($list as $value) {
170
            $listtype = $optioninfo->optionType($value);
171
            $retval .= "<option id='option-S$rowid-v-$value' value='$value#" . $listtype["type"] . "#" . $listtype["flag"] . "#' ";
172
            if ($iterator == $this->optionIterator) {
173
                $retval .= "selected='selected'";
174
                $activelisttype = $listtype;
175
            }
176
            $retval .= ">" . $uiElements->displayName($value) . "</option>";
177
            $iterator++;
178
        }
179
        if (count($activelisttype) == 0) {
180
            throw new \Exception("We should have found the active list type by now!");
181
        }
182
        $retval .= "</select>";
183
        return ["TEXT" => $retval, "ACTIVE" => $activelisttype];
184
    }
185
186
    private function selectLanguage($rowid, $makeVisible) {
187
        $retval = "<select style='display:" . ($makeVisible ? "block" : "none") . "' name='value[S$rowid-lang]' id='S" . $rowid . "-input-langselect'>
188
            <option value='' name='select_language' selected>" . _("select language") . "</option>
189
            <option value='C' name='all_languages'>" . _("default/other languages") . "</option>";
190
        foreach (CONFIG['LANGUAGES'] as $langindex => $possibleLang) {
191
            $thislang = $possibleLang['display'];
192
            $retval .= "<option value='$langindex' name='$langindex'>$thislang</option>";
193
        }
194
        $retval .= "</select>";
195
        return $retval;
196
    }
197
198
    const HTML_DATATYPE_TEXTS = [
199
        \core\Options::TYPECODE_FILE => ["html" => "input type='file'", "tail" => ' size=\'10\''],
200
        \core\Options::TYPECODE_BOOLEAN => ["html" => "input type='checkbox'", "tail" => ''],
201
        \core\Options::TYPECODE_INTEGER => ["html" => "input type='number'", "tail" => ''],
202
        \core\Options::TYPECODE_STRING => ["html" => "input type='string'", "tail" => ''],
203
        \core\Options::TYPECODE_TEXT => ["html" => "textarea cols='30' rows='3'", "tail" => '></textarea'],
204
    ];
205
206
    private function inputFields($rowid, $activetype) {
207
        $retval = "";
208
        foreach (OptionDisplay::HTML_DATATYPE_TEXTS as $key => $type) {
209
            $retval .= "<" . $type['html'] . " style='display:" . ($activetype['type'] == $key ? "block" : "none") . "' name='value[S$rowid-$key]' id='S" . $rowid . "-input-" . $key . "'" . $type['tail'] . ">";
210
        }
211
        return $retval;
212
    }
213
214
    /**
215
     * HTML code to display a "fresh" option (including type selector and JavaScript to show/hide relevant input fields)
216
     * @param int $rowid the HTML field base name of the option to be displayed
217
     * @param array $list the list of option names to include in the type selector
218
     * @return string HTML code
219
     * @throws Exception
220
     */
221
    private function noPrefillText(int $rowid, array $list) {
222
        // first column: the <select> element with the names of options and their field-toggling JS magic
223
        $selectorInfo = $this->selectElement($rowid, $list);
224
        $retval = "<td>" . $selectorInfo["TEXT"] . "</td>";
225
        // second column: the <select> element for language selection - only visible if the active option is multi-lang
226
        $retval .= "<td>" . $this->selectLanguage($rowid, $selectorInfo['ACTIVE']['flag'] == "ML") . "</td>";
227
        // third column: the actual input fields; the data type of the active option is visible, all others hidden
228
        $retval .= "<td>" . $this->inputFields($rowid, $selectorInfo['ACTIVE']) . "</td>";
229
        return $retval;
230
    }
231
232
    /**
233
     * generates HTML code that displays an already set option.
234
     * 
235
     * @param int $rowid the HTML field base name of the option to be displayed
236
     * @param string $optionName the name of the option to display
237
     * @param string $optionValue the value of the option to display
238
     * @param mixed $optionLang the language of the option to display
239
     * @return string HTML code
240
     * @throws Exception
241
     */
242
    private function prefillText(int $rowid, string $optionName, string $optionValue, $optionLang) {
243
        $retval = "";
244
        $optioninfo = \core\Options::instance();
245
        $loggerInstance = new \core\common\Logging();
246
        $loggerInstance->debug(5, "Executed with PREFILL $optionValue!\n");
247
        $retval .= "<td>";
248
        $uiElements = new UIElements();
249
        $listtype = $optioninfo->optionType($optionName);
250
        $retval .= $uiElements->displayName($optionName);
251
        $retval .= $uiElements->tooltip($optionName);
252
        $retval .= "<input type='hidden' id='option-S$rowid-select' name='option[S$rowid]' value='$optionName#" . $listtype["type"] . "#" . $listtype["flag"] . "#' ></td>";
253
254
        // language tag if any
255
        $retval .= "<td>";
256
        if ($listtype["flag"] == "ML") {
257
258
            $language = "(" . strtoupper($optionLang) . ")";
259
            if ($optionLang == 'C') {
260
                $language = _("(default/other languages)");
261
            }
262
            $retval .= $language;
263
            $retval .= "<input type='hidden' name='value[S$rowid-lang]' id='S" . $rowid . "-input-langselect' value='" . $optionLang . "' style='display:block'>";
264
        }
265
        $retval .= "</td>";
266
// attribute content
267
        $retval .= "<td>";
268
        switch ($listtype["type"]) {
269
            case \core\Options::TYPECODE_COORDINATES:
270
                $this->allLocationCount = $this->allLocationCount + 1;
271
                $link = "<button id='location_b_" . $this->allLocationCount . "' class='location_button'>" . _("Click to see location") . " $this->allLocationCount</button>";
272
                $retval .= "<input readonly style='display:none' type='text' name='value[S$rowid-" . \core\Options::TYPECODE_TEXT . "]' id='S$rowid-input-text' value='$optionValue'>$link";
273
                break;
274
            case \core\Options::TYPECODE_FILE:
275
                $retval .= "<input readonly type='text' name='value[S$rowid-1]' id='S" . $rowid . "-input-string' style='display:none' value='" . urlencode($optionValue) . "'>";
276
                $uiElements = new UIElements();
277
                switch ($optionName) {
278
                    case "eap:ca_file":
279
                        $retval .= $uiElements->previewCAinHTML($optionValue);
280
                        break;
281
                    case "general:logo_file":
282
                    case "fed:logo_file":
283
                        $retval .= $uiElements->previewImageinHTML($optionValue);
284
                        break;
285
                    case "support:info_file":
286
                        $retval .= $uiElements->previewInfoFileinHTML($optionValue);
287
                        break;
288
                    default:
289
                        $retval .= _("file content");
290
                }
291
                break;
292
            case \core\Options::TYPECODE_STRING:
293
            // fall-thorugh is intentional; mostly identical HTML code for the three types
294
            case \core\Options::TYPECODE_INTEGER:
295
            // fall-thorugh is intentional; mostly identical HTML code for the three types
296
            case \core\Options::TYPECODE_TEXT:
297
                $displayedVariant = $optionValue; // for all three types, value tag and actual display are identical
0 ignored issues
show
Unused Code introduced by
$displayedVariant is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
298
            case \core\Options::TYPECODE_BOOLEAN:
299
                $displayedVariant = ($optionValue == "on" ? _("on") : _("off"));
300
                $retval .= "<strong>$displayedVariant</strong><input type='hidden' name='value[S$rowid-".$listtype['type']."]' id='S" . $rowid . "-input-" . $listtype["type"] . "' value=\"" . htmlspecialchars($optionValue) . "\" style='display:block'>";
301
                break;
302
            default:
303
                // this should never happen!
304
                throw new Exception("Internal Error: unknown attribute type $listtype!");
305
        }
306
        $retval .= "</td>";
307
        return $retval;
308
    }
309
310
    /**
311
     * Displays a container for options. Either with prefilled data or empty; if
312
     * empty then has HTML <input> tags with clever javaScript to allow selection
313
     * of different option names and types
314
     * @param array $list options which should be displayed; can be only exactly one if existing option, or multiple if new option type
315
     * @param string $prefillValue for an existing option, it's value to be displayed
316
     * @param string $prefillLang for an existing option, the language of the value to be displayed
317
     * @return string HTML code <tr>
318
     */
319
    public function optiontext(array $list, string $prefillValue = NULL, string $prefillLang = NULL) {
320
        $rowid = mt_rand();
321
322
        $retval = "<tr id='option-S$rowid' style='vertical-align:top'>";
323
324
        $item = "MULTIPLE";
325
        if ($prefillValue === NULL) {
326
            $retval .= $this->noPrefillText($rowid, $list);
327
        }
328
329
        if ($prefillValue !== NULL) {
330
            // prefill is always only called with a list with exactly one element.
331
            // if we see anything else here, get excited.
332
            if (count($list) != 1) {
333
                throw new Exception("Optiontext prefilled display only can work with exactly one option!");
334
            }
335
            $item = array_pop($list);
336
            $retval .= $this->prefillText($rowid, $item, $prefillValue, $prefillLang);
337
        }
338
        $retval .= "
339
340
       <td>
341
          <button type='button' class='delete' onclick='deleteOption(" . ( $prefillValue !== NULL && $item == "general:geo_coordinates" ? $this->allLocationCount : 0 ) . ",\"option-S" . $rowid . "\")'>-</button>
342
       </td>
343
    </tr>";
344
        return $retval;
345
    }
346
347
}
348