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