Lines Matching +full:comparator +full:* +(+path:plugin +path:struct) -(+path:plugin +path:struct +path:lang)

1 <?php
3 namespace dokuwiki\plugin\struct\types;
5 use dokuwiki\Extension\Plugin;
6 use dokuwiki\plugin\struct\meta\Column;
7 use dokuwiki\plugin\struct\meta\QueryBuilder;
8 use dokuwiki\plugin\struct\meta\QueryBuilderWhere;
9 use dokuwiki\plugin\struct\meta\StructException;
10 use dokuwiki\plugin\struct\meta\TranslationUtilities;
11 use dokuwiki\plugin\struct\meta\ValidationException;
12 use dokuwiki\plugin\struct\meta\Value;
15 * Class AbstractBaseType
17 * This class represents a basic type that can be configured to be used in a Schema. It is the main
18 * part of a column definition as defined in meta\Column
20 * This defines also how the content of the coulmn will be entered and formatted.
22 * @package dokuwiki\plugin\struct\types
23 * @see Column
25 abstract class AbstractBaseType
27 use TranslationUtilities;
30 * @var array current config
32 protected $config = [];
35 * @var array config keys that should not be cleaned despite not being in $config
37 protected $keepconfig = ['label', 'hint', 'visibility'];
40 * @var string label for the field
42 protected $label = '';
45 * @var bool is this a multivalue field?
47 protected $ismulti = false;
50 * @var int the type ID
52 protected $tid = 0;
55 * @var null|Column the column context this type is part of
57 protected $context;
60 * @var Plugin
62 protected $hlp;
65 * AbstractBaseType constructor.
66 * @param array|null $config The configuration, might be null if nothing saved, yet
67 * @param string $label The label for this field (empty for new definitions=
68 * @param bool $ismulti Should this field accept multiple values?
69 * @param int $tid The id of this type if it has been saved, yet
71 public function __construct($config = null, $label = '', $ismulti = false, $tid = 0)
73 // general config options
74 $baseconfig = [
75 'visibility' => [
76 'inpage' => true,
77 'ineditor' => true
81 // use previously saved configuration, ignoring all keys that are not supposed to be here
82 if (!is_null($config)) {
83 $this->mergeConfig($config, $this->config);
86 $this->initTransConfig();
87 $this->config = array_merge($baseconfig, $this->config);
88 $this->label = $label;
89 $this->ismulti = (bool)$ismulti;
90 $this->tid = $tid;
94 * Merge the current config with the base config of the type
96 * Ignores all keys that are not supposed to be there. Recurses into sub keys
98 * @param array $current Current configuration
99 * @param array $config Base Type configuration
101 protected function mergeConfig($current, &$config)
103 foreach ($current as $key => $value) {
104 if (isset($config[$key]) || in_array($key, $this->keepconfig)) {
105 if (isset($config[$key]) && is_array($config[$key])) {
106 $this->mergeConfig($value, $config[$key]);
107 } else {
108 $config[$key] = $value;
115 * Returns data as associative array
117 * @return array
119 public function getAsEntry()
121 return [
122 'config' => json_encode($this->config, JSON_THROW_ON_ERROR),
123 'label' => $this->label,
124 'ismulti' => $this->ismulti,
125 'class' => $this->getClass()
130 * The class name of this type (no namespace)
131 * @return string
133 public function getClass()
135 $class = get_class($this);
136 return substr($class, strrpos($class, "\\") + 1);
140 * Return the current configuration for this type
142 * @return array
144 public function getConfig()
146 return $this->config;
150 * @return boolean
152 public function isMulti()
154 return $this->ismulti;
158 * @return string
160 public function getLabel()
162 return $this->label;
166 * Returns the translated label for this type
168 * Uses the current language as determined by $conf['lang']. Falls back to english
169 * and then to the type label
171 * @return string
173 public function getTranslatedLabel()
175 return $this->getTranslatedKey('label', $this->label);
179 * Returns the translated hint for this type
181 * Uses the current language as determined by $conf['lang']. Falls back to english.
182 * Returns empty string if no hint is configured
184 * @return string
186 public function getTranslatedHint()
188 return $this->getTranslatedKey('hint', '');
192 * @return int
194 public function getTid()
196 return $this->tid;
200 * @return Column
201 * @throws StructException
203 public function getContext()
205 if (is_null($this->context)) {
206 throw new StructException(
207 'Empty column context requested. Type was probably initialized outside of Schema.'
210 return $this->context;
214 * @param Column $context
216 public function setContext($context)
218 $this->context = $context;
222 * @return bool
224 public function isVisibleInEditor()
226 return $this->config['visibility']['ineditor'];
230 * @return bool
232 public function isVisibleInPage()
234 return $this->config['visibility']['inpage'];
238 * Split a single value into multiple values
240 * This function is called on saving data when only a single value instead of an array
241 * was submitted.
243 * Types implementing their own @param string $value
244 * @return array
245 * @see multiValueEditor() will probably want to override this
248 public function splitValues($value)
250 return array_map('trim', explode(',', $value));
254 * Return the editor to edit multiple values
256 * Types can override this to provide a better alternative than multiple entry fields
258 * @param string $name the form base name where this has to be stored
259 * @param string[] $rawvalues the current values
260 * @param string $htmlID a unique id to be referenced by the label
261 * @return string html
263 public function multiValueEditor($name, $rawvalues, $htmlID)
265 $html = '';
266 foreach ($rawvalues as $value) {
267 $html .= '<div class="multiwrap">';
268 $html .= $this->valueEditor($name . '[]', $value, '');
269 $html .= '</div>';
271 // empty field to add
272 $html .= '<div class="newtemplate">';
273 $html .= '<div class="multiwrap">';
274 $html .= $this->valueEditor($name . '[]', '', $htmlID);
275 $html .= '</div>';
276 $html .= '</div>';
278 return $html;
282 * Return the editor to edit a single value
284 * @param string $name the form name where this has to be stored
285 * @param string $rawvalue the current value
286 * @param string $htmlID a unique id to be referenced by the label
288 * @return string html
290 public function valueEditor($name, $rawvalue, $htmlID)
292 $class = 'struct_' . strtolower($this->getClass());
294 // support the autocomplete configurations out of the box
295 if (isset($this->config['autocomplete']['maxresult']) && $this->config['autocomplete']['maxresult']) {
296 $class .= ' struct_autocomplete';
299 $params = [
300 'name' => $name,
301 'value' => $rawvalue,
302 'class' => $class,
303 'id' => $htmlID
305 $attributes = buildAttributes($params, true);
306 return "<input $attributes>";
310 * Output the stored data
312 * @param string|int $value the value stored in the database
313 * @param \Doku_Renderer $R the renderer currently used to render the data
314 * @param string $mode The mode the output is rendered in (eg. XHTML)
315 * @return bool true if $mode could be satisfied
317 public function renderValue($value, \Doku_Renderer $R, $mode)
319 $value = $this->displayValue($value);
320 $R->cdata($value);
321 return true;
325 * format and return the data
327 * @param int[]|string[] $values the values stored in the database
328 * @param \Doku_Renderer $R the renderer currently used to render the data
329 * @param string $mode The mode the output is rendered in (eg. XHTML)
330 * @return bool true if $mode could be satisfied
332 public function renderMultiValue($values, \Doku_Renderer $R, $mode)
334 $len = count($values);
335 for ($i = 0; $i < $len; $i++) {
336 $this->renderValue($values[$i], $R, $mode);
337 if ($i < $len - 1) {
338 $R->cdata(', ');
341 return true;
345 * Render a link in a struct cloud. This should be good for most types, but can be overwritten if necessary.
347 * @param string|int $value the value stored in the database
348 * @param \Doku_Renderer $R the renderer currently used to render the data
349 * @param string $mode The mode the output is rendered in (eg. XHTML)
350 * @param string $page the target to which should be linked
351 * @param string $filter the filter to apply to the aggregations on $page
352 * @param int $weight the scaled weight of the item. implemented as css font-size on the outside container
353 * @param int|null $showCount count for the tag, only passed if summarize was set in config
355 public function renderTagCloudLink($value, \Doku_Renderer $R, $mode, $page, $filter, $weight, $showCount = null)
357 $value = $this->displayValue($value);
358 if ($showCount) {
359 $value .= " ($showCount)";
361 $R->internallink("$page?$filter", $value);
365 * This function is used to modify an aggregation query to add a filter
366 * for the given column matching the given value. A type should add at
367 * least a filter here but could do additional things like joining more
368 * tables needed to handle more complex filters
370 * Important: $value might be an array. If so, the filter should check against
371 * all provided values ORed together
373 * @param QueryBuilderWhere $add The where clause where statements can be added
374 * @param string $tablealias The table the currently saved value(s) are stored in
375 * @param string $colname The column name on above table to use in the SQL
376 * @param string $comp The SQL comparator (LIKE, NOT LIKE, =, !=, etc)
377 * @param string|string[] $value this is the user supplied value to compare against. might be multiple
378 * @param string $op the logical operator this filter should use (AND|OR)
380 public function filter(QueryBuilderWhere $add, $tablealias, $colname, $comp, $value, $op)
382 /** @var QueryBuilderWhere $add Where additionional queries are added to */
383 if (is_array($value)) {
384 $add = $add->where($op); // sub where group
385 $op = 'OR';
387 foreach ((array)$value as $item) {
388 $pl = $add->getQB()->addValue($item);
389 $add->where($op, "$tablealias.$colname $comp $pl");
394 * Add the proper selection for this type to the current Query
396 * The default implementation here should be good for nearly all types, it simply
397 * passes the given parameters to the query builder. But type may do more fancy
398 * stuff here, eg. join more tables or select multiple values and combine them to
399 * JSON. If you do, be sure implement a fitting rawValue() method.
401 * The passed $tablealias.$columnname might be a data_* table (referencing a single
402 * row) or a multi_* table (referencing multiple rows). In the latter case the
403 * multi table has already been joined with the proper conditions.
405 * You may assume a column alias named 'PID' to be available, should you need the
406 * current page context for a join or sub select.
408 * @param QueryBuilder $QB
409 * @param string $tablealias The table the currently saved value(s) are stored in
410 * @param string $colname The column name on above table
411 * @param string $alias The added selection *has* to use this column alias
413 public function select(QueryBuilder $QB, $tablealias, $colname, $alias)
415 $QB->addSelectColumn($tablealias, $colname, $alias);
419 * Sort results by this type
421 * The default implementation should be good for nearly all types. However some
422 * types may need to do proper SQLite type casting to have the right order.
424 * Generally if you implemented @param QueryBuilder $QB
425 * @param string $tablealias The table the currently saved value is stored in
426 * @param string $colname The column name on above table (always single column!)
427 * @param string $order either ASC or DESC
428 * @see select() you probably want to implement this,
429 * too.
432 public function sort(QueryBuilder $QB, $tablealias, $colname, $order)
434 $QB->addOrderBy("$tablealias.$colname COLLATE NOCASE $order");
438 * Get the string by which to sort values of this type
440 * This implementation is designed to work both as registered function in sqlite
441 * and to provide a string to be used in sorting values of this type in PHP.
443 * @param string|Value $value The string by which the types would usually be sorted
445 * @return string
447 public function getSortString($value)
449 if (is_string($value)) {
450 return $value;
452 $display = $value->getDisplayValue();
453 if (is_array($display)) {
454 return blank($display[0]) ? "" : $display[0];
456 return $display;
460 * This allows types to apply a transformation to the value read by select()
462 * The returned value should always be a single, non-complex string. In general
463 * it is the identifier a type stores in the database.
465 * This value will be used wherever the raw saved data is needed for comparisons.
466 * The default implementations of renderValue() and valueEditor() will call this
467 * function as well.
469 * @param string $value The value as returned by select()
470 * @return string The value as saved in the database
472 public function rawValue($value)
474 return $value;
478 * This is called when a single string is needed to represent this Type's current
479 * value as a single (non-HTML) string. Eg. in a dropdown or in autocompletion.
481 * @param string $value
482 * @return string
484 public function displayValue($value)
486 return $this->rawValue($value);
490 * This is the value to be used as argument to a filter for another column.
492 * In a sense this is the counterpart to the @param string $value
494 * @return string
495 * @see filter() function
498 public function compareValue($value)
500 return $this->rawValue($value);
504 * Validate and optionally clean a single value
506 * This function needs to throw a validation exception when validation fails.
507 * The exception message will be prefixed by the appropriate field on output
509 * The function should return the value as it should be saved later on.
511 * @param string|int $rawvalue
512 * @return int|string the cleaned value
513 * @throws ValidationException
515 public function validate($rawvalue)
517 return trim($rawvalue);
521 * Overwrite to handle Ajax requests
523 * A call to DOKU_BASE/lib/exe/ajax.php?call=plugin_struct&column=schema.name will
524 * be redirected to this function on a fully initialized type. The result is
525 * JSON encoded and returned to the caller. Access additional parameter via $INPUT
526 * as usual
528 * @return mixed
529 * @throws StructException when something goes wrong
531 public function handleAjax()
533 throw new StructException('not implemented');
537 * Convenience method to access plugin language strings
539 * @param string $string
540 * @return string
542 public function getLang($string)
544 if (is_null($this->hlp)) $this->hlp = plugin_load('helper', 'struct');
545 return $this->hlp->getLang($string);
549 * With what comparator should dynamic filters filter this type?
551 * This default does a LIKE operation
553 * @return string
554 * @see Search::$COMPARATORS
556 public function getDefaultComparator()
558 return '*~';