Passed
Push — master ( 17bffe...10bee5 )
by Stefan
06:13
created

OptionDisplay::optiontext()   B

Complexity

Conditions 6
Paths 18

Size

Total Lines 26
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 26
c 0
b 0
f 0
rs 8.439
cc 6
eloc 13
nc 18
nop 3
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
use Exception;
14
15
require_once(dirname(dirname(dirname(dirname(__FILE__)))) . "/config/_config.php");
16
17
/**
18
 * We need to display previously set options in various forms. This class covers
19
 * the ways to do that; the generated page content can then be parsed with 
20
 * OptionParser.
21
 * 
22
 * @author Stefan Winter <[email protected]>
23
 */
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) {
78
        $retval = "<table id='expandable_$attributePrefix" . "_options'>";
79
80
        $prepopulate = [];
81
        foreach ($this->listOfOptions as $existingAttribute) {
82
            if ($existingAttribute['level'] == $this->level) {
83
                $prepopulate[] = $existingAttribute;
84
            }
85
        }
86
        $retval .= $this->addOption($attributePrefix, $prepopulate);
87
        $retval .= "</table>";
88
        return $retval;
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:
98
        // this can mean either a new object (list all options with empty values)
99
        // or that an object is to be edited. In that case, $prepopulated has to
100
        // contain the array of existing variables
101
        // we expect the variable $class to contain the class of options
102
        $retval = "";
103
104
        $optioninfo = \core\Options::instance();
105
106
        if (is_array($prepopulate) && ( count($prepopulate) > 1 || $class == "device-specific" || $class == "eap-specific")) { // editing... fill with values
107
            foreach ($prepopulate as $option) {
108
                if (preg_match("/$class:/", $option['name']) && !preg_match("/(user:fedadmin)/", $option['name'])) {
109
                    $optiontypearray = $optioninfo->optionType($option['name']);
110
                    $loggerInstance = new \core\common\Logging();
111
                    $loggerInstance->debug(5, "About to execute optiontext with PREFILL!\n");
112
                    $retval .= $this->optiontext([$option['name']], ($optiontypearray["type"] == "file" ? 'ROWID-' . $option['level'] . '-' . $option['row'] : $option['value']), $option['lang']);
113
                }
114
            }
115
        } else { // not editing exist, this in new: add empty list
116
            $list = $optioninfo->availableOptions($class);
117
            switch ($class) {
118
                case "general":
119
                    $blacklistItem = array_search("general:geo_coordinates", $list);
120
                    break;
121
                case "profile":
122
                    $blacklistItem = array_search("profile:QR-user", $list);
123
                    break;
124
                case "user":
125
                    $blacklistItem = array_search("user:fedadmin", $list);
126
                    break;
127
                default:
128
                    $blacklistItem = FALSE;
129
            }
130
            if ($blacklistItem !== FALSE) {
131
                unset($list[$blacklistItem]);
132
                $list = array_values($list);
133
            }
134
135
            // add as many options as there are different option types
136
            $numberOfOptions = count($list);
137
            for ($this->optionIterator = 0; $this->optionIterator < $numberOfOptions; $this->optionIterator++) {
138
                $retval .= $this->optiontext($list);
139
            }
140
        }
141
        return $retval;
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) {
323
        $rowid = mt_rand();
0 ignored issues
show
Bug introduced by
The call to mt_rand() has too few arguments starting with min. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

323
        $rowid = /** @scrutinizer ignore-call */ mt_rand();

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.

Loading history...
324
325
        $retval = "<tr id='option-S$rowid' style='vertical-align:top'>";
326
327
        $item = "MULTIPLE";
328
        if ($prefillValue === NULL) {
329
            $retval .= $this->noPrefillText($rowid, $list);
330
        }
331
332
        if ($prefillValue !== NULL) {
333
            // prefill is always only called with a list with exactly one element.
334
            // if we see anything else here, get excited.
335
            if (count($list) != 1) {
336
                throw new Exception("Optiontext prefilled display only can work with exactly one option!");
337
            }
338
            $item = array_pop($list);
339
            $retval .= $this->prefillText($rowid, $item, $prefillValue, $prefillLang);
340
        }
341
        $retval .= "
342
343
       <td>
344
          <button type='button' class='delete' onclick='deleteOption(" . ( $prefillValue !== NULL && $item == "general:geo_coordinates" ? $this->allLocationCount : 0 ) . ",\"option-S" . $rowid . "\")'>-</button>
345
       </td>
346
    </tr>";
347
        return $retval;
348
    }
349
350
}
351