1<?php 2namespace plugin\struct\types; 3 4use dokuwiki\Form\Form; 5use plugin\struct\meta\ValidationException; 6 7/** 8 * Class AbstractBaseType 9 * 10 * This class represents a basic type that can be configured to be used in a Schema. It is the main 11 * part of a column definition as defined in meta\Column 12 * 13 * This defines also how the content of the coulmn will be entered and formatted. 14 * 15 * @package plugin\struct\types 16 * @see Column 17 */ 18abstract class AbstractBaseType { 19 20 /** 21 * @var array current config 22 */ 23 protected $config = array(); 24 25 /** 26 * @var array config keys that should not be cleaned despite not being in $config 27 */ 28 protected $keepconfig = array('translation'); 29 30 /** 31 * @var string label for the field 32 */ 33 protected $label = ''; 34 35 /** 36 * @var bool is this a multivalue field? 37 */ 38 protected $ismulti = false; 39 40 /** 41 * @var int the type ID 42 */ 43 protected $tid = 0; 44 45 /** 46 * AbstractBaseType constructor. 47 * @param array|null $config The configuration, might be null if nothing saved, yet 48 * @param string $label The label for this field (empty for new definitions= 49 * @param bool $ismulti Should this field accept multiple values? 50 * @param int $tid The id of this type if it has been saved, yet 51 */ 52 public function __construct($config = null, $label = '', $ismulti = false, $tid = 0) { 53 // initialize the configuration, ignoring all keys that are not supposed to be here 54 if(!is_null($config)) { 55 foreach($config as $key => $value) { 56 if(isset($this->config[$key]) || in_array($key, $this->keepconfig)) { 57 $this->config[$key] = $value; 58 } 59 } 60 } 61 62 $this->initTransConfig(); 63 $this->label = $label; 64 $this->ismulti = (bool) $ismulti; 65 $this->tid = $tid; 66 } 67 68 /** 69 * Add the translation keys to the configuration 70 * 71 * This checks if a configuration for the translation plugin exists and if so 72 * adds all configured languages to the config array. This ensures all types 73 * can have translatable labels. 74 */ 75 protected function initTransConfig() { 76 global $conf; 77 $lang = $conf['lang']; 78 if(isset($conf['plugin']['translation']['translations'])) { 79 $lang .= ' ' . $conf['plugin']['translation']['translations']; 80 } 81 $langs = explode(' ', $lang); 82 $langs = array_map('trim', $langs); 83 $langs = array_filter($langs); 84 $langs = array_unique($langs); 85 86 if(!isset($this->config['translation'])) $this->config['translation'] = array(); 87 foreach($langs as $lang) { 88 if(!isset($this->config['translation'][$lang])) $this->config['translation'][$lang] = ''; 89 } 90 } 91 92 /** 93 * Returns data as associative array 94 * 95 * @return array 96 */ 97 public function getAsEntry() { 98 return array( 99 'config' => json_encode($this->config), 100 'label' => $this->label, 101 'ismulti' => $this->ismulti, 102 'class' => $this->getClass() 103 ); 104 } 105 106 /** 107 * The class name of this type (no namespace) 108 * @return string 109 */ 110 public function getClass() { 111 return substr(get_class($this), 20); 112 } 113 114 /** 115 * Return the current configuration for this type 116 * 117 * @return array 118 */ 119 public function getConfig() { 120 return $this->config; 121 } 122 123 /** 124 * @return boolean 125 */ 126 public function isMulti() { 127 return $this->ismulti; 128 } 129 130 /** 131 * @return string 132 */ 133 public function getLabel() { 134 return $this->label; 135 } 136 137 /** 138 * Returns the translated label for this type 139 * 140 * Uses the current language as determined by $conf['lang']. Falls back to english 141 * and then to the Schema label 142 * 143 * @return string 144 */ 145 public function getTranslatedLabel() { 146 global $conf; 147 $lang = $conf['lang']; 148 if(!blank($this->config['translation'][$lang])) { 149 return $this->config['translation'][$lang]; 150 } 151 if(!blank($this->config['translation']['en'])) { 152 return $this->config['translation']['en']; 153 } 154 return $this->label; 155 } 156 157 /** 158 * @return int 159 */ 160 public function getTid() { 161 return $this->tid; 162 } 163 164 /** 165 * Split a single value into multiple values 166 * 167 * This function is called on saving data when only a single value instead of an array 168 * was submitted. 169 * 170 * Types implementing their own @see multiValueEditor() will probably want to override this 171 * 172 * @param string $value 173 * @return array 174 */ 175 public function splitValues($value) { 176 return array_map('trim', explode(',', $value)); 177 } 178 179 /** 180 * Return the editor to edit multiple values 181 * 182 * Types can override this to provide a better alternative than multiple entry fields 183 * 184 * @param string $name the form base name where this has to be stored 185 * @param string[] $values the current values 186 * @return string html 187 */ 188 public function multiValueEditor($name, $values) { 189 $html = ''; 190 foreach($values as $value) { 191 $html .= '<div class="multiwrap">'; 192 $html .= $this->valueEditor($name . '[]', $value); 193 $html .= '</div>'; 194 } 195 // empty field to add 196 $html .= '<div class="newtemplate">'; 197 $html .= '<div class="multiwrap">'; 198 $html .= $this->valueEditor($name . '[]', ''); 199 $html .= '</div>'; 200 $html .= '</div>'; 201 202 return $html; 203 } 204 205 /** 206 * Return the editor to edit a single value 207 * 208 * @param string $name the form name where this has to be stored 209 * @param string $value the current value 210 * @return string html 211 */ 212 public function valueEditor($name, $value) { 213 $name = hsc($name); 214 $value = hsc($value); 215 $html = "<input name=\"$name\" value=\"$value\" />"; 216 return "$html"; 217 } 218 219 /** 220 * Output the stored data 221 * 222 * @param string|int $value the value stored in the database 223 * @param \Doku_Renderer $R the renderer currently used to render the data 224 * @param string $mode The mode the output is rendered in (eg. XHTML) 225 * @return bool true if $mode could be satisfied 226 */ 227 public function renderValue($value, \Doku_Renderer $R, $mode) { 228 $R->cdata($value); 229 return true; 230 } 231 232 /** 233 * format and return the data 234 * 235 * @param int[]|string[] $values the values stored in the database 236 * @param \Doku_Renderer $R the renderer currently used to render the data 237 * @param string $mode The mode the output is rendered in (eg. XHTML) 238 * @return bool true if $mode could be satisfied 239 */ 240 public function renderMultiValue($values, \Doku_Renderer $R, $mode) { 241 $len = count($values); 242 for($i = 0; $i < $len; $i++) { 243 $this->renderValue($values[$i], $R, $mode); 244 if($i < $len - 1) { 245 $R->cdata(', '); 246 } 247 } 248 return true; 249 } 250 251 /** 252 * This function builds a where clause for this column, comparing 253 * the current value stored in $column with $value. Types can use it to do 254 * clever things with the comparison. 255 * 256 * This default implementation is probably good enough for most basic types 257 * 258 * @param string $column The column name to us in the SQL 259 * @param string $comp The comparator @see Search::$COMPARATORS 260 * @param string $value 261 * @return array Tuple with the SQL and parameter array 262 */ 263 public function compare($column, $comp, $value) { 264 switch ($comp) { 265 case '~': 266 $sql = "$column LIKE ?"; 267 $opt = array($value); 268 break; 269 case '!~': 270 $sql = "$column NOT LIKE ?"; 271 $opt = array($value); 272 break; 273 default: 274 $sql = "$column $comp ?"; 275 $opt = array($value); 276 } 277 278 return array($sql, $opt); 279 } 280 281 /** 282 * Validate a single value 283 * 284 * This function needs to throw a validation exception when validation fails. 285 * The exception message will be prefixed by the appropriate field on output 286 * 287 * @param string|int $value 288 * @throws ValidationException 289 */ 290 public function validate($value) { 291 // nothing by default - we allow everything 292 } 293} 294