1083afc55SAndreas Gohr<?php 2d6d97f60SAnna Dabrowska 3ba766201SAndreas Gohrnamespace dokuwiki\plugin\struct\types; 42350b48eSAndreas Gohr 57234bfb1Ssplitbrainuse dokuwiki\Extension\Plugin; 6ba766201SAndreas Gohruse dokuwiki\plugin\struct\meta\Column; 7384e59cbSAndreas Gohruse dokuwiki\plugin\struct\meta\QueryBuilder; 853528ecfSAndreas Gohruse dokuwiki\plugin\struct\meta\QueryBuilderWhere; 9ba766201SAndreas Gohruse dokuwiki\plugin\struct\meta\StructException; 10f800af69SMichael Großeuse dokuwiki\plugin\struct\meta\TranslationUtilities; 11ba766201SAndreas Gohruse dokuwiki\plugin\struct\meta\ValidationException; 12d560ea13SMichael Grosseuse dokuwiki\plugin\struct\meta\Value; 13083afc55SAndreas Gohr 141c502704SAndreas Gohr/** 151c502704SAndreas Gohr * Class AbstractBaseType 161c502704SAndreas Gohr * 171c502704SAndreas Gohr * This class represents a basic type that can be configured to be used in a Schema. It is the main 181c502704SAndreas Gohr * part of a column definition as defined in meta\Column 191c502704SAndreas Gohr * 207182938bSAndreas Gohr * This defines also how the content of the coulmn will be entered and formatted. 217182938bSAndreas Gohr * 22ba766201SAndreas Gohr * @package dokuwiki\plugin\struct\types 237182938bSAndreas Gohr * @see Column 241c502704SAndreas Gohr */ 25d6d97f60SAnna Dabrowskaabstract class AbstractBaseType 26d6d97f60SAnna Dabrowska{ 27f800af69SMichael Große use TranslationUtilities; 28f800af69SMichael Große 29083afc55SAndreas Gohr /** 30083afc55SAndreas Gohr * @var array current config 31083afc55SAndreas Gohr */ 327234bfb1Ssplitbrain protected $config = []; 33083afc55SAndreas Gohr 34083afc55SAndreas Gohr /** 354d19af58SAndreas Gohr * @var array config keys that should not be cleaned despite not being in $config 364d19af58SAndreas Gohr */ 377234bfb1Ssplitbrain protected $keepconfig = ['label', 'hint', 'visibility']; 384d19af58SAndreas Gohr 394d19af58SAndreas Gohr /** 40083afc55SAndreas Gohr * @var string label for the field 41083afc55SAndreas Gohr */ 42083afc55SAndreas Gohr protected $label = ''; 43083afc55SAndreas Gohr 44083afc55SAndreas Gohr /** 45083afc55SAndreas Gohr * @var bool is this a multivalue field? 46083afc55SAndreas Gohr */ 47083afc55SAndreas Gohr protected $ismulti = false; 48083afc55SAndreas Gohr 49083afc55SAndreas Gohr /** 5004eb61a6SAndreas Gohr * @var int the type ID 5104eb61a6SAndreas Gohr */ 5204eb61a6SAndreas Gohr protected $tid = 0; 5304eb61a6SAndreas Gohr 5404eb61a6SAndreas Gohr /** 55bbf3d6aaSAndreas Gohr * @var null|Column the column context this type is part of 56bbf3d6aaSAndreas Gohr */ 577234bfb1Ssplitbrain protected $context; 58bbf3d6aaSAndreas Gohr 59bbf3d6aaSAndreas Gohr /** 607234bfb1Ssplitbrain * @var Plugin 6153c92fe4SAndreas Gohr */ 627234bfb1Ssplitbrain protected $hlp; 6353c92fe4SAndreas Gohr 6453c92fe4SAndreas Gohr /** 65083afc55SAndreas Gohr * AbstractBaseType constructor. 66083afc55SAndreas Gohr * @param array|null $config The configuration, might be null if nothing saved, yet 67083afc55SAndreas Gohr * @param string $label The label for this field (empty for new definitions= 68083afc55SAndreas Gohr * @param bool $ismulti Should this field accept multiple values? 6904eb61a6SAndreas Gohr * @param int $tid The id of this type if it has been saved, yet 70083afc55SAndreas Gohr */ 71d6d97f60SAnna Dabrowska public function __construct($config = null, $label = '', $ismulti = false, $tid = 0) 72d6d97f60SAnna Dabrowska { 732350b48eSAndreas Gohr // general config options 747fe2cdf2SAndreas Gohr $baseconfig = [ 757fe2cdf2SAndreas Gohr 'visibility' => [ 767fe2cdf2SAndreas Gohr 'inpage' => true, 777fe2cdf2SAndreas Gohr 'ineditor' => true 787fe2cdf2SAndreas Gohr ] 797fe2cdf2SAndreas Gohr ]; 802350b48eSAndreas Gohr 812350b48eSAndreas Gohr // use previously saved configuration, ignoring all keys that are not supposed to be here 824d19af58SAndreas Gohr if (!is_null($config)) { 83ace65259SAndreas Gohr $this->mergeConfig($config, $this->config); 844d19af58SAndreas Gohr } 854d19af58SAndreas Gohr 869e9bee91SAndreas Gohr $this->initTransConfig(); 872350b48eSAndreas Gohr $this->config = array_merge($baseconfig, $this->config); 88083afc55SAndreas Gohr $this->label = $label; 89083afc55SAndreas Gohr $this->ismulti = (bool)$ismulti; 9004eb61a6SAndreas Gohr $this->tid = $tid; 911c502704SAndreas Gohr } 921c502704SAndreas Gohr 931c502704SAndreas Gohr /** 94ace65259SAndreas Gohr * Merge the current config with the base config of the type 95ace65259SAndreas Gohr * 96ace65259SAndreas Gohr * Ignores all keys that are not supposed to be there. Recurses into sub keys 97ace65259SAndreas Gohr * 98ace65259SAndreas Gohr * @param array $current Current configuration 99ace65259SAndreas Gohr * @param array $config Base Type configuration 100ace65259SAndreas Gohr */ 101d6d97f60SAnna Dabrowska protected function mergeConfig($current, &$config) 102d6d97f60SAnna Dabrowska { 103ace65259SAndreas Gohr foreach ($current as $key => $value) { 104ace65259SAndreas Gohr if (isset($config[$key]) || in_array($key, $this->keepconfig)) { 1059007da58SMichael Große if (isset($config[$key]) && is_array($config[$key])) { 106ace65259SAndreas Gohr $this->mergeConfig($value, $config[$key]); 107ace65259SAndreas Gohr } else { 108ace65259SAndreas Gohr $config[$key] = $value; 109ace65259SAndreas Gohr } 110ace65259SAndreas Gohr } 111ace65259SAndreas Gohr } 112ace65259SAndreas Gohr } 113ace65259SAndreas Gohr 114ace65259SAndreas Gohr /** 1151c502704SAndreas Gohr * Returns data as associative array 1161c502704SAndreas Gohr * 1171c502704SAndreas Gohr * @return array 1181c502704SAndreas Gohr */ 119d6d97f60SAnna Dabrowska public function getAsEntry() 120d6d97f60SAnna Dabrowska { 1217fe2cdf2SAndreas Gohr return [ 122*5e29103aSannda 'config' => json_encode($this->config, JSON_THROW_ON_ERROR), 1237fe2cdf2SAndreas Gohr 'label' => $this->label, 1247fe2cdf2SAndreas Gohr 'ismulti' => $this->ismulti, 1257fe2cdf2SAndreas Gohr 'class' => $this->getClass() 1267fe2cdf2SAndreas Gohr ]; 1271c502704SAndreas Gohr } 1281c502704SAndreas Gohr 1291c502704SAndreas Gohr /** 1301c502704SAndreas Gohr * The class name of this type (no namespace) 1311c502704SAndreas Gohr * @return string 1321c502704SAndreas Gohr */ 133d6d97f60SAnna Dabrowska public function getClass() 134d6d97f60SAnna Dabrowska { 135ba766201SAndreas Gohr $class = get_class($this); 136ba766201SAndreas Gohr return substr($class, strrpos($class, "\\") + 1); 137083afc55SAndreas Gohr } 138083afc55SAndreas Gohr 139083afc55SAndreas Gohr /** 140083afc55SAndreas Gohr * Return the current configuration for this type 141083afc55SAndreas Gohr * 142083afc55SAndreas Gohr * @return array 143083afc55SAndreas Gohr */ 144d6d97f60SAnna Dabrowska public function getConfig() 145d6d97f60SAnna Dabrowska { 146083afc55SAndreas Gohr return $this->config; 147083afc55SAndreas Gohr } 148083afc55SAndreas Gohr 149083afc55SAndreas Gohr /** 150083afc55SAndreas Gohr * @return boolean 151083afc55SAndreas Gohr */ 152d6d97f60SAnna Dabrowska public function isMulti() 153d6d97f60SAnna Dabrowska { 154083afc55SAndreas Gohr return $this->ismulti; 155083afc55SAndreas Gohr } 156083afc55SAndreas Gohr 157083afc55SAndreas Gohr /** 158083afc55SAndreas Gohr * @return string 159083afc55SAndreas Gohr */ 160d6d97f60SAnna Dabrowska public function getLabel() 161d6d97f60SAnna Dabrowska { 162083afc55SAndreas Gohr return $this->label; 163083afc55SAndreas Gohr } 164083afc55SAndreas Gohr 165083afc55SAndreas Gohr /** 1669e9bee91SAndreas Gohr * Returns the translated label for this type 1679e9bee91SAndreas Gohr * 1689e9bee91SAndreas Gohr * Uses the current language as determined by $conf['lang']. Falls back to english 169f800af69SMichael Große * and then to the type label 1709e9bee91SAndreas Gohr * 1719e9bee91SAndreas Gohr * @return string 1729e9bee91SAndreas Gohr */ 173d6d97f60SAnna Dabrowska public function getTranslatedLabel() 174d6d97f60SAnna Dabrowska { 175f800af69SMichael Große return $this->getTranslatedKey('label', $this->label); 1769e9bee91SAndreas Gohr } 1779e9bee91SAndreas Gohr 1789e9bee91SAndreas Gohr /** 1793a717675SAndreas Gohr * Returns the translated hint for this type 1803a717675SAndreas Gohr * 1813a717675SAndreas Gohr * Uses the current language as determined by $conf['lang']. Falls back to english. 1823a717675SAndreas Gohr * Returns empty string if no hint is configured 1833a717675SAndreas Gohr * 1843a717675SAndreas Gohr * @return string 1853a717675SAndreas Gohr */ 186d6d97f60SAnna Dabrowska public function getTranslatedHint() 187d6d97f60SAnna Dabrowska { 188f800af69SMichael Große return $this->getTranslatedKey('hint', ''); 1893a717675SAndreas Gohr } 1903a717675SAndreas Gohr 1913a717675SAndreas Gohr /** 19204eb61a6SAndreas Gohr * @return int 19304eb61a6SAndreas Gohr */ 194d6d97f60SAnna Dabrowska public function getTid() 195d6d97f60SAnna Dabrowska { 19604eb61a6SAndreas Gohr return $this->tid; 19704eb61a6SAndreas Gohr } 19804eb61a6SAndreas Gohr 19904eb61a6SAndreas Gohr /** 200bbf3d6aaSAndreas Gohr * @return Column 2010549dcc5SAndreas Gohr * @throws StructException 202bbf3d6aaSAndreas Gohr */ 203d6d97f60SAnna Dabrowska public function getContext() 204d6d97f60SAnna Dabrowska { 20517a3a578SAndreas Gohr if (is_null($this->context)) { 20617a3a578SAndreas Gohr throw new StructException( 20717a3a578SAndreas Gohr 'Empty column context requested. Type was probably initialized outside of Schema.' 20817a3a578SAndreas Gohr ); 20917a3a578SAndreas Gohr } 210bbf3d6aaSAndreas Gohr return $this->context; 211bbf3d6aaSAndreas Gohr } 212bbf3d6aaSAndreas Gohr 213bbf3d6aaSAndreas Gohr /** 214bbf3d6aaSAndreas Gohr * @param Column $context 215bbf3d6aaSAndreas Gohr */ 216d6d97f60SAnna Dabrowska public function setContext($context) 217d6d97f60SAnna Dabrowska { 218bbf3d6aaSAndreas Gohr $this->context = $context; 219bbf3d6aaSAndreas Gohr } 220bbf3d6aaSAndreas Gohr 221bbf3d6aaSAndreas Gohr /** 2222350b48eSAndreas Gohr * @return bool 2232350b48eSAndreas Gohr */ 224d6d97f60SAnna Dabrowska public function isVisibleInEditor() 225d6d97f60SAnna Dabrowska { 2262350b48eSAndreas Gohr return $this->config['visibility']['ineditor']; 2272350b48eSAndreas Gohr } 2282350b48eSAndreas Gohr 2292350b48eSAndreas Gohr /** 2302350b48eSAndreas Gohr * @return bool 2312350b48eSAndreas Gohr */ 232d6d97f60SAnna Dabrowska public function isVisibleInPage() 233d6d97f60SAnna Dabrowska { 2342350b48eSAndreas Gohr return $this->config['visibility']['inpage']; 2352350b48eSAndreas Gohr } 2362350b48eSAndreas Gohr 2372350b48eSAndreas Gohr /** 238899b86acSAndreas Gohr * Split a single value into multiple values 239899b86acSAndreas Gohr * 240899b86acSAndreas Gohr * This function is called on saving data when only a single value instead of an array 241899b86acSAndreas Gohr * was submitted. 242899b86acSAndreas Gohr * 2430549dcc5SAndreas Gohr * Types implementing their own @param string $value 244899b86acSAndreas Gohr * @return array 2450549dcc5SAndreas Gohr * @see multiValueEditor() will probably want to override this 2460549dcc5SAndreas Gohr * 247899b86acSAndreas Gohr */ 248d6d97f60SAnna Dabrowska public function splitValues($value) 249d6d97f60SAnna Dabrowska { 250899b86acSAndreas Gohr return array_map('trim', explode(',', $value)); 251899b86acSAndreas Gohr } 252899b86acSAndreas Gohr 253899b86acSAndreas Gohr /** 254899b86acSAndreas Gohr * Return the editor to edit multiple values 255899b86acSAndreas Gohr * 256899b86acSAndreas Gohr * Types can override this to provide a better alternative than multiple entry fields 257899b86acSAndreas Gohr * 258899b86acSAndreas Gohr * @param string $name the form base name where this has to be stored 259c0230d2cSAndreas Gohr * @param string[] $rawvalues the current values 260ee983135SMichael Große * @param string $htmlID a unique id to be referenced by the label 261899b86acSAndreas Gohr * @return string html 262899b86acSAndreas Gohr */ 263d6d97f60SAnna Dabrowska public function multiValueEditor($name, $rawvalues, $htmlID) 264d6d97f60SAnna Dabrowska { 265899b86acSAndreas Gohr $html = ''; 266c0230d2cSAndreas Gohr foreach ($rawvalues as $value) { 26768da1619SAndreas Gohr $html .= '<div class="multiwrap">'; 268ee983135SMichael Große $html .= $this->valueEditor($name . '[]', $value, ''); 26968da1619SAndreas Gohr $html .= '</div>'; 270899b86acSAndreas Gohr } 271899b86acSAndreas Gohr // empty field to add 272a187dd5eSAndreas Gohr $html .= '<div class="newtemplate">'; 27368da1619SAndreas Gohr $html .= '<div class="multiwrap">'; 274ee983135SMichael Große $html .= $this->valueEditor($name . '[]', '', $htmlID); 275a187dd5eSAndreas Gohr $html .= '</div>'; 27668da1619SAndreas Gohr $html .= '</div>'; 277899b86acSAndreas Gohr 278899b86acSAndreas Gohr return $html; 279899b86acSAndreas Gohr } 280899b86acSAndreas Gohr 281899b86acSAndreas Gohr /** 28231263897SAndreas Gohr * Return the editor to edit a single value 283083afc55SAndreas Gohr * 28431263897SAndreas Gohr * @param string $name the form name where this has to be stored 285c0230d2cSAndreas Gohr * @param string $rawvalue the current value 286ee983135SMichael Große * @param string $htmlID a unique id to be referenced by the label 287ee983135SMichael Große * 28831263897SAndreas Gohr * @return string html 289083afc55SAndreas Gohr */ 290d6d97f60SAnna Dabrowska public function valueEditor($name, $rawvalue, $htmlID) 291d6d97f60SAnna Dabrowska { 292e6a35dceSAndreas Gohr $class = 'struct_' . strtolower($this->getClass()); 293dacfa997SAndreas Gohr 294dacfa997SAndreas Gohr // support the autocomplete configurations out of the box 295dacfa997SAndreas Gohr if (isset($this->config['autocomplete']['maxresult']) && $this->config['autocomplete']['maxresult']) { 296dacfa997SAndreas Gohr $class .= ' struct_autocomplete'; 297dacfa997SAndreas Gohr } 298dacfa997SAndreas Gohr 2997fe2cdf2SAndreas Gohr $params = [ 3007fe2cdf2SAndreas Gohr 'name' => $name, 3017fe2cdf2SAndreas Gohr 'value' => $rawvalue, 3027fe2cdf2SAndreas Gohr 'class' => $class, 3037fe2cdf2SAndreas Gohr 'id' => $htmlID 3047fe2cdf2SAndreas Gohr ]; 3053e7a5b3cSMichael Große $attributes = buildAttributes($params, true); 3063e7a5b3cSMichael Große return "<input $attributes>"; 3072249c4d2SAndreas Gohr } 308083afc55SAndreas Gohr 309083afc55SAndreas Gohr /** 310083afc55SAndreas Gohr * Output the stored data 311083afc55SAndreas Gohr * 312083afc55SAndreas Gohr * @param string|int $value the value stored in the database 313797f0dfeSAndreas Gohr * @param \Doku_Renderer $R the renderer currently used to render the data 314797f0dfeSAndreas Gohr * @param string $mode The mode the output is rendered in (eg. XHTML) 315797f0dfeSAndreas Gohr * @return bool true if $mode could be satisfied 316083afc55SAndreas Gohr */ 317d6d97f60SAnna Dabrowska public function renderValue($value, \Doku_Renderer $R, $mode) 318d6d97f60SAnna Dabrowska { 31934ffb347SAndreas Gohr $value = $this->displayValue($value); 320797f0dfeSAndreas Gohr $R->cdata($value); 321797f0dfeSAndreas Gohr return true; 3222249c4d2SAndreas Gohr } 3239d7a36f9SAndreas Gohr 3249d7a36f9SAndreas Gohr /** 325dbaaf815SMichael Große * format and return the data 326dbaaf815SMichael Große * 327dbaaf815SMichael Große * @param int[]|string[] $values the values stored in the database 328797f0dfeSAndreas Gohr * @param \Doku_Renderer $R the renderer currently used to render the data 329797f0dfeSAndreas Gohr * @param string $mode The mode the output is rendered in (eg. XHTML) 330797f0dfeSAndreas Gohr * @return bool true if $mode could be satisfied 331dbaaf815SMichael Große */ 332d6d97f60SAnna Dabrowska public function renderMultiValue($values, \Doku_Renderer $R, $mode) 333d6d97f60SAnna Dabrowska { 334797f0dfeSAndreas Gohr $len = count($values); 335797f0dfeSAndreas Gohr for ($i = 0; $i < $len; $i++) { 336797f0dfeSAndreas Gohr $this->renderValue($values[$i], $R, $mode); 337797f0dfeSAndreas Gohr if ($i < $len - 1) { 338797f0dfeSAndreas Gohr $R->cdata(', '); 339dbaaf815SMichael Große } 340797f0dfeSAndreas Gohr } 341797f0dfeSAndreas Gohr return true; 342dbaaf815SMichael Große } 343dbaaf815SMichael Große 344dbaaf815SMichael Große /** 345262c0fc6SMichael Grosse * Render a link in a struct cloud. This should be good for most types, but can be overwritten if necessary. 346262c0fc6SMichael Grosse * 347262c0fc6SMichael Grosse * @param string|int $value the value stored in the database 348262c0fc6SMichael Grosse * @param \Doku_Renderer $R the renderer currently used to render the data 349262c0fc6SMichael Grosse * @param string $mode The mode the output is rendered in (eg. XHTML) 350262c0fc6SMichael Grosse * @param string $page the target to which should be linked 351262c0fc6SMichael Grosse * @param string $filter the filter to apply to the aggregations on $page 35217a3a578SAndreas Gohr * @param int $weight the scaled weight of the item. implemented as css font-size on the outside container 3537a256bc0SAnna Dabrowska * @param int|null $showCount count for the tag, only passed if summarize was set in config 354262c0fc6SMichael Grosse */ 3557a256bc0SAnna Dabrowska public function renderTagCloudLink($value, \Doku_Renderer $R, $mode, $page, $filter, $weight, $showCount = null) 356d6d97f60SAnna Dabrowska { 357bfb78ce3SAnna Dabrowska $value = $this->displayValue($value); 358bfb78ce3SAnna Dabrowska if ($showCount) { 359bfb78ce3SAnna Dabrowska $value .= " ($showCount)"; 360bfb78ce3SAnna Dabrowska } 361bfb78ce3SAnna Dabrowska $R->internallink("$page?$filter", $value); 362262c0fc6SMichael Grosse } 363262c0fc6SMichael Grosse 364262c0fc6SMichael Grosse /** 365384e59cbSAndreas Gohr * This function is used to modify an aggregation query to add a filter 366384e59cbSAndreas Gohr * for the given column matching the given value. A type should add at 367384e59cbSAndreas Gohr * least a filter here but could do additional things like joining more 368384e59cbSAndreas Gohr * tables needed to handle more complex filters 369384e59cbSAndreas Gohr * 37053528ecfSAndreas Gohr * Important: $value might be an array. If so, the filter should check against 37153528ecfSAndreas Gohr * all provided values ORed together 37253528ecfSAndreas Gohr * 373af993d55SMichael Grosse * @param QueryBuilderWhere $add The where clause where statements can be added 3744e4e3ad2SAndreas Gohr * @param string $tablealias The table the currently saved value(s) are stored in 3754e4e3ad2SAndreas Gohr * @param string $colname The column name on above table to use in the SQL 3767da1a0fdSAndreas Gohr * @param string $comp The SQL comparator (LIKE, NOT LIKE, =, !=, etc) 37753528ecfSAndreas Gohr * @param string|string[] $value this is the user supplied value to compare against. might be multiple 3784e4e3ad2SAndreas Gohr * @param string $op the logical operator this filter should use (AND|OR) 379384e59cbSAndreas Gohr */ 380d6d97f60SAnna Dabrowska public function filter(QueryBuilderWhere $add, $tablealias, $colname, $comp, $value, $op) 381d6d97f60SAnna Dabrowska { 38253528ecfSAndreas Gohr /** @var QueryBuilderWhere $add Where additionional queries are added to */ 38353528ecfSAndreas Gohr if (is_array($value)) { 384af993d55SMichael Grosse $add = $add->where($op); // sub where group 38553528ecfSAndreas Gohr $op = 'OR'; 38653528ecfSAndreas Gohr } 38753528ecfSAndreas Gohr foreach ((array)$value as $item) { 388af993d55SMichael Grosse $pl = $add->getQB()->addValue($item); 38953528ecfSAndreas Gohr $add->where($op, "$tablealias.$colname $comp $pl"); 39053528ecfSAndreas Gohr } 391384e59cbSAndreas Gohr } 392384e59cbSAndreas Gohr 393384e59cbSAndreas Gohr /** 394578407b2SAndreas Gohr * Add the proper selection for this type to the current Query 395578407b2SAndreas Gohr * 396578407b2SAndreas Gohr * The default implementation here should be good for nearly all types, it simply 397578407b2SAndreas Gohr * passes the given parameters to the query builder. But type may do more fancy 398578407b2SAndreas Gohr * stuff here, eg. join more tables or select multiple values and combine them to 399e7ee2b64SAndreas Gohr * JSON. If you do, be sure implement a fitting rawValue() method. 400578407b2SAndreas Gohr * 401578407b2SAndreas Gohr * The passed $tablealias.$columnname might be a data_* table (referencing a single 402578407b2SAndreas Gohr * row) or a multi_* table (referencing multiple rows). In the latter case the 403578407b2SAndreas Gohr * multi table has already been joined with the proper conditions. 404578407b2SAndreas Gohr * 405578407b2SAndreas Gohr * You may assume a column alias named 'PID' to be available, should you need the 406578407b2SAndreas Gohr * current page context for a join or sub select. 407578407b2SAndreas Gohr * 408578407b2SAndreas Gohr * @param QueryBuilder $QB 409578407b2SAndreas Gohr * @param string $tablealias The table the currently saved value(s) are stored in 4104e4e3ad2SAndreas Gohr * @param string $colname The column name on above table 411578407b2SAndreas Gohr * @param string $alias The added selection *has* to use this column alias 412578407b2SAndreas Gohr */ 413d6d97f60SAnna Dabrowska public function select(QueryBuilder $QB, $tablealias, $colname, $alias) 414d6d97f60SAnna Dabrowska { 4154e4e3ad2SAndreas Gohr $QB->addSelectColumn($tablealias, $colname, $alias); 416578407b2SAndreas Gohr } 417578407b2SAndreas Gohr 418578407b2SAndreas Gohr /** 4197e06fb39SAndreas Gohr * Sort results by this type 4207e06fb39SAndreas Gohr * 4217e06fb39SAndreas Gohr * The default implementation should be good for nearly all types. However some 4227e06fb39SAndreas Gohr * types may need to do proper SQLite type casting to have the right order. 4237e06fb39SAndreas Gohr * 4240549dcc5SAndreas Gohr * Generally if you implemented @param QueryBuilder $QB 4257e06fb39SAndreas Gohr * @param string $tablealias The table the currently saved value is stored in 4267e06fb39SAndreas Gohr * @param string $colname The column name on above table (always single column!) 4277e06fb39SAndreas Gohr * @param string $order either ASC or DESC 4280549dcc5SAndreas Gohr * @see select() you probably want to implement this, 4290549dcc5SAndreas Gohr * too. 4300549dcc5SAndreas Gohr * 4317e06fb39SAndreas Gohr */ 432d6d97f60SAnna Dabrowska public function sort(QueryBuilder $QB, $tablealias, $colname, $order) 433d6d97f60SAnna Dabrowska { 434f0be5277SAnna Dabrowska $QB->addOrderBy("$tablealias.$colname COLLATE NOCASE $order"); 4357e06fb39SAndreas Gohr } 4367e06fb39SAndreas Gohr 4377e06fb39SAndreas Gohr /** 438d560ea13SMichael Grosse * Get the string by which to sort values of this type 439d560ea13SMichael Grosse * 440d560ea13SMichael Grosse * This implementation is designed to work both as registered function in sqlite 441d560ea13SMichael Grosse * and to provide a string to be used in sorting values of this type in PHP. 442d560ea13SMichael Grosse * 443db9b8745SAndreas Gohr * @param string|Value $value The string by which the types would usually be sorted 4449e7e1786SMichael Grosse * 4459e7e1786SMichael Grosse * @return string 446d560ea13SMichael Grosse */ 447d6d97f60SAnna Dabrowska public function getSortString($value) 448d6d97f60SAnna Dabrowska { 449d560ea13SMichael Grosse if (is_string($value)) { 450d560ea13SMichael Grosse return $value; 451d560ea13SMichael Grosse } 452d560ea13SMichael Grosse $display = $value->getDisplayValue(); 453d560ea13SMichael Grosse if (is_array($display)) { 454d560ea13SMichael Grosse return blank($display[0]) ? "" : $display[0]; 455d560ea13SMichael Grosse } 456d560ea13SMichael Grosse return $display; 457d560ea13SMichael Grosse } 458d560ea13SMichael Grosse 459d560ea13SMichael Grosse /** 460e7ee2b64SAndreas Gohr * This allows types to apply a transformation to the value read by select() 461e7ee2b64SAndreas Gohr * 462e7ee2b64SAndreas Gohr * The returned value should always be a single, non-complex string. In general 463e7ee2b64SAndreas Gohr * it is the identifier a type stores in the database. 464e7ee2b64SAndreas Gohr * 465e7ee2b64SAndreas Gohr * This value will be used wherever the raw saved data is needed for comparisons. 466e7ee2b64SAndreas Gohr * The default implementations of renderValue() and valueEditor() will call this 467e7ee2b64SAndreas Gohr * function as well. 468e7ee2b64SAndreas Gohr * 469e7ee2b64SAndreas Gohr * @param string $value The value as returned by select() 470e7ee2b64SAndreas Gohr * @return string The value as saved in the database 471e7ee2b64SAndreas Gohr */ 472d6d97f60SAnna Dabrowska public function rawValue($value) 473d6d97f60SAnna Dabrowska { 474e7ee2b64SAndreas Gohr return $value; 475e7ee2b64SAndreas Gohr } 476e7ee2b64SAndreas Gohr 477e7ee2b64SAndreas Gohr /** 4785241ca30SAndreas Gohr * This is called when a single string is needed to represent this Type's current 4795241ca30SAndreas Gohr * value as a single (non-HTML) string. Eg. in a dropdown or in autocompletion. 4805241ca30SAndreas Gohr * 4815241ca30SAndreas Gohr * @param string $value 4825241ca30SAndreas Gohr * @return string 4835241ca30SAndreas Gohr */ 484d6d97f60SAnna Dabrowska public function displayValue($value) 485d6d97f60SAnna Dabrowska { 4865241ca30SAndreas Gohr return $this->rawValue($value); 4875241ca30SAndreas Gohr } 4885241ca30SAndreas Gohr 4895241ca30SAndreas Gohr /** 4907717c082SMichael Große * This is the value to be used as argument to a filter for another column. 4917717c082SMichael Große * 4920549dcc5SAndreas Gohr * In a sense this is the counterpart to the @param string $value 4937717c082SMichael Große * 4947717c082SMichael Große * @return string 4950549dcc5SAndreas Gohr * @see filter() function 4960549dcc5SAndreas Gohr * 4977717c082SMichael Große */ 498d6d97f60SAnna Dabrowska public function compareValue($value) 499d6d97f60SAnna Dabrowska { 5007717c082SMichael Große return $this->rawValue($value); 5017717c082SMichael Große } 5027717c082SMichael Große 5037717c082SMichael Große /** 504806eec82SAndreas Gohr * Validate and optionally clean a single value 50517560ecbSAndreas Gohr * 50617560ecbSAndreas Gohr * This function needs to throw a validation exception when validation fails. 50717560ecbSAndreas Gohr * The exception message will be prefixed by the appropriate field on output 50817560ecbSAndreas Gohr * 509806eec82SAndreas Gohr * The function should return the value as it should be saved later on. 510806eec82SAndreas Gohr * 51123169abeSAndreas Gohr * @param string|int $rawvalue 512806eec82SAndreas Gohr * @return int|string the cleaned value 51317560ecbSAndreas Gohr * @throws ValidationException 51417560ecbSAndreas Gohr */ 515d6d97f60SAnna Dabrowska public function validate($rawvalue) 516d6d97f60SAnna Dabrowska { 51723169abeSAndreas Gohr return trim($rawvalue); 51817560ecbSAndreas Gohr } 519914921fbSAndreas Gohr 520914921fbSAndreas Gohr /** 521914921fbSAndreas Gohr * Overwrite to handle Ajax requests 522914921fbSAndreas Gohr * 523914921fbSAndreas Gohr * A call to DOKU_BASE/lib/exe/ajax.php?call=plugin_struct&column=schema.name will 524914921fbSAndreas Gohr * be redirected to this function on a fully initialized type. The result is 525914921fbSAndreas Gohr * JSON encoded and returned to the caller. Access additional parameter via $INPUT 526914921fbSAndreas Gohr * as usual 527914921fbSAndreas Gohr * 528914921fbSAndreas Gohr * @return mixed 5290549dcc5SAndreas Gohr * @throws StructException when something goes wrong 530914921fbSAndreas Gohr */ 531d6d97f60SAnna Dabrowska public function handleAjax() 532d6d97f60SAnna Dabrowska { 533914921fbSAndreas Gohr throw new StructException('not implemented'); 534914921fbSAndreas Gohr } 53553c92fe4SAndreas Gohr 53653c92fe4SAndreas Gohr /** 53753c92fe4SAndreas Gohr * Convenience method to access plugin language strings 53853c92fe4SAndreas Gohr * 53953c92fe4SAndreas Gohr * @param string $string 54053c92fe4SAndreas Gohr * @return string 54153c92fe4SAndreas Gohr */ 542d6d97f60SAnna Dabrowska public function getLang($string) 543d6d97f60SAnna Dabrowska { 544ba766201SAndreas Gohr if (is_null($this->hlp)) $this->hlp = plugin_load('helper', 'struct'); 54553c92fe4SAndreas Gohr return $this->hlp->getLang($string); 54653c92fe4SAndreas Gohr } 547db9b8745SAndreas Gohr 548db9b8745SAndreas Gohr /** 549db9b8745SAndreas Gohr * With what comparator should dynamic filters filter this type? 550db9b8745SAndreas Gohr * 551db9b8745SAndreas Gohr * This default does a LIKE operation 552db9b8745SAndreas Gohr * 553db9b8745SAndreas Gohr * @return string 5540549dcc5SAndreas Gohr * @see Search::$COMPARATORS 555db9b8745SAndreas Gohr */ 556d6d97f60SAnna Dabrowska public function getDefaultComparator() 557d6d97f60SAnna Dabrowska { 558db9b8745SAndreas Gohr return '*~'; 559db9b8745SAndreas Gohr } 560083afc55SAndreas Gohr} 561