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