xref: /dokuwiki/lib/plugins/config/core/Setting/SettingMulticheckbox.php (revision f90148d34a91c706a0028485431212698fcf8cc6)
1<?php
2
3namespace dokuwiki\plugin\config\core\Setting;
4
5/**
6 * Class setting_multicheckbox
7 */
8class SettingMulticheckbox extends SettingString {
9
10    protected $choices = [];
11    protected $combine = [];
12    protected $other = 'always';
13
14    /** @inheritdoc */
15    public function update($input) {
16        if($this->isProtected()) return false;
17
18        // split any combined values + convert from array to comma separated string
19        $input = $input ?: [];
20        $input = $this->array2str($input);
21
22        $value = is_null($this->local) ? $this->default : $this->local;
23        if($value == $input) return false;
24
25        if($this->pattern && !preg_match($this->pattern, $input)) {
26            $this->error = true;
27            $this->input = $input;
28            return false;
29        }
30
31        $this->local = $input;
32        return true;
33    }
34
35    /** @inheritdoc */
36    public function html(\admin_plugin_config $plugin, $echo = false) {
37
38        $disable = '';
39
40        if ($this->isProtected()) {
41            $value = $this->protected;
42            $disable = 'disabled="disabled"';
43        } elseif ($echo && $this->error) {
44            $value = $this->input;
45        } else {
46            $value = is_null($this->local) ? $this->default : $this->local;
47        }
48
49        $key = htmlspecialchars($this->key);
50
51        // convert from comma separated list into array + combine complimentary actions
52        $value = $this->str2array($value);
53        $default = $this->str2array($this->default);
54
55        $input = '';
56        foreach($this->choices as $choice) {
57            $idx = array_search($choice, $value);
58            $idx_default = array_search($choice, $default);
59
60            $checked = ($idx !== false) ? 'checked="checked"' : '';
61
62            // @todo ideally this would be handled using a second class of "default"
63            $class = (($idx !== false) === (false !== $idx_default)) ? " selectiondefault" : "";
64
65            $prompt = ($plugin->getLang($this->key . '_' . $choice) ?: htmlspecialchars($choice));
66
67            $input .= '<div class="selection' . $class . '">' . "\n";
68            $input .= '<label for="config___' . $key . '_' . $choice . '">' . $prompt . "</label>\n";
69            $input .= '<input id="config___' . $key . '_' . $choice . '" name="config[' . $key .
70                '][]" type="checkbox" class="checkbox" value="' . $choice . '" ' . $disable . ' ' . $checked . "/>\n";
71            $input .= "</div>\n";
72
73            // remove this action from the disabledactions array
74            if($idx !== false) unset($value[$idx]);
75            if($idx_default !== false) unset($default[$idx_default]);
76        }
77
78        // handle any remaining values
79        if($this->other != 'never') {
80            $other = implode(',', $value);
81            // test equivalent to ($this->_other == 'always' || ($other && $this->_other == 'exists')
82            // use != 'exists' rather than == 'always' to ensure invalid values default to 'always'
83            if($this->other != 'exists' || $other) {
84
85                $class = (
86                    (count($default) === count($value)) &&
87                    (count($value) === count(array_intersect($value, $default)))
88                ) ?
89                    " selectiondefault" : "";
90
91                $input .= '<div class="other' . $class . '">' . "\n";
92                $input .= '<label for="config___' . $key . '_other">' .
93                    $plugin->getLang($key . '_other') .
94                    "</label>\n";
95                $input .= '<input id="config___' . $key . '_other" name="config[' . $key .
96                    '][other]" type="text" class="edit" value="' . htmlspecialchars($other) .
97                    '" ' . $disable . " />\n";
98                $input .= "</div>\n";
99            }
100        }
101        $label = '<label>' . $this->prompt($plugin) . '</label>';
102        return [$label, $input];
103    }
104
105    /**
106     * convert comma separated list to an array and combine any complimentary values
107     *
108     * @param string $str
109     * @return array
110     */
111    protected function str2array($str) {
112        $array = explode(',', $str);
113
114        if(!empty($this->combine)) {
115            foreach($this->combine as $key => $combinators) {
116                $idx = [];
117                foreach($combinators as $val) {
118                    if(($idx[] = array_search($val, $array)) === false) break;
119                }
120
121                if(count($idx) && $idx[count($idx) - 1] !== false) {
122                    foreach($idx as $i) unset($array[$i]);
123                    $array[] = $key;
124                }
125            }
126        }
127
128        return $array;
129    }
130
131    /**
132     * convert array of values + other back to a comma separated list, incl. splitting any combined values
133     *
134     * @param array $input
135     * @return string
136     */
137    protected function array2str($input) {
138
139        // handle other
140        $other = trim($input['other']);
141        $other = empty($other) ? [] : explode(',', str_replace(' ', '', $input['other']));
142        unset($input['other']);
143
144        $array = array_unique(array_merge($input, $other));
145
146        // deconstruct any combinations
147        if(!empty($this->combine)) {
148            foreach($this->combine as $key => $combinators) {
149
150                $idx = array_search($key, $array);
151                if($idx !== false) {
152                    unset($array[$idx]);
153                    $array = array_merge($array, $combinators);
154                }
155            }
156        }
157
158        return implode(',', array_unique($array));
159    }
160}
161