1<?php 2/** 3 * DokuWiki Plugin structprogress 4 * Most Code is taken from decimal Type: https://github.com/cosmocode/dokuwiki-plugin-struct/blob/5c37a46b990a9bc0e314c8faa228db6012387b5f/types/Decimal.php 5 * 6 * @author: saggi <saggi@gmx.de> 7 */ 8 9namespace dokuwiki\plugin\structnumber\types; 10 11use dokuwiki\plugin\struct\meta\QueryBuilder; 12use dokuwiki\plugin\struct\meta\QueryBuilderWhere; 13use dokuwiki\plugin\struct\meta\ValidationException; 14use dokuwiki\plugin\struct\types\AbstractMultiBaseType; 15 16/** 17 * Class Number 18 * 19 * A field accepting decimal numbers 20 * 21 */ 22class Number extends AbstractMultiBaseType 23{ 24 protected $config = array( 25 'min' => '', 26 'max' => '', 27 'format' => "%01.2f", 28 'prefix' => '', 29 'postfix' => '' 30 ); 31 32 /** 33 * Output the stored data 34 * 35 * @param string|int $value the value stored in the database 36 * @param \Doku_Renderer $R the renderer currently used to render the data 37 * @param string $mode The mode the output is rendered in (eg. XHTML) 38 * @return bool true if $mode could be satisfied 39 */ 40 public function renderValue($value, \Doku_Renderer $R, $mode) 41 { 42 $value = $this->checkFormat($value, $this->config['format']); 43 44 $R->cdata($this->config['prefix'] . $value . $this->config['postfix']); 45 return true; 46 } 47 48 /** 49 * @param int|string $rawvalue 50 * @return int|string 51 * @throws ValidationException 52 */ 53 public function validate($rawvalue) 54 { 55 $rawvalue = parent::validate($rawvalue); 56 $rawvalue = str_replace(',', '.', $rawvalue); // we accept both 57 58 if ((string)$rawvalue != (string)floatval($rawvalue)) { 59 throw new ValidationException('Decimal needed'); 60 } 61 62 if ($this->config['min'] !== '' && floatval($rawvalue) < floatval($this->config['min'])) { 63 throw new ValidationException('Decimal min', floatval($this->config['min'])); 64 } 65 66 if ($this->config['max'] !== '' && floatval($rawvalue) > floatval($this->config['max'])) { 67 throw new ValidationException('Decimal max', floatval($this->config['max'])); 68 } 69 70 return $rawvalue; 71 } 72 73 /** 74 * Check the format config 75 * 76 * @param $number 77 * @param $format 78 * @return string 79 */ 80 protected function checkFormat($number, $format) 81 { 82 // heck if its a valid sprintf format 83 if (preg_match("/^%(?:['+-:\.]?\D?\d*\.?\d*)?[bdeEfFu]$/",$format)===0) { 84 $format = '%01.2f'; 85 } 86 return sprintf($format, $number); 87 } 88 89 /** 90 * Decimals need to be casted to the proper type for sorting 91 * 92 * @param QueryBuilder $QB 93 * @param string $tablealias 94 * @param string $colname 95 * @param string $order 96 */ 97 public function sort(QueryBuilder $QB, $tablealias, $colname, $order) 98 { 99 $QB->addOrderBy("CAST($tablealias.$colname AS DECIMAL) $order"); 100 } 101 102 /** 103 * Decimals need to be casted to proper type for comparison 104 * 105 * @param QueryBuilderWhere $add 106 * @param string $tablealias 107 * @param string $colname 108 * @param string $comp 109 * @param string|\string[] $value 110 * @param string $op 111 */ 112 public function filter(QueryBuilderWhere $add, $tablealias, $colname, $comp, $value, $op) 113 { 114 $add = $add->where($op); // open a subgroup 115 $add->where('AND', "$tablealias.$colname != ''"); // make sure the field isn't empty 116 $op = 'AND'; 117 118 /** @var QueryBuilderWhere $add Where additionional queries are added to */ 119 if (is_array($value)) { 120 $add = $add->where($op); // sub where group 121 $op = 'OR'; 122 } 123 124 foreach ((array)$value as $item) { 125 $pl = $add->getQB()->addValue($item); 126 $add->where($op, "CAST($tablealias.$colname AS DECIMAL) $comp CAST($pl AS DECIMAL)"); 127 } 128 } 129 130 /** 131 * Only exact matches for numbers 132 * 133 * @return string 134 */ 135 public function getDefaultComparator() 136 { 137 return '='; 138 } 139} 140