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\structprogress\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 16class Progress extends AbstractMultiBaseType 17{ 18 19 protected $config = array( 20 'max' => '100', 21 'prefix' => '', 22 'postfix' => '', 23 'type' => 'default', 24 ); 25 26 /** 27 * @inheritDoc 28 */ 29 public function validate($rawvalue) 30 { 31 $rawvalue = parent::validate($rawvalue); 32 $rawvalue = str_replace(',', '.', $rawvalue); // we accept both 33 $minvalue = 0; 34 $maxvalue = 100; 35 if ($this->config['max'] !== '' && floatval($this->config['max']) > 0) { 36 $maxvalue = floatval($this->config['max']); 37 } 38 39 if ((string)$rawvalue != (string)floatval($rawvalue)) { 40 throw new ValidationException('Decimal needed'); 41 } 42 43 if (floatval($rawvalue) < $minvalue) { 44 throw new ValidationException('Decimal min', $minvalue); 45 } 46 47 if ($maxvalue !== 0 && floatval($rawvalue) > $maxvalue) { 48 throw new ValidationException('Decimal max', $maxvalue); 49 } 50 51 return $rawvalue; 52 } 53 54 /** 55 * @inheritDoc 56 */ 57 public function renderValue($value, \Doku_Renderer $R, $mode) 58 { 59 if ($mode == 'xhtml') { 60 $maxvalue = 100; 61 if ($this->config['max'] !== '' && floatval($this->config['max']) > 0) { 62 $maxvalue = floatval($this->config['max']); 63 } 64 $progress = 100 * $value / $maxvalue; 65 $progress = (int)($progress > 0) ? (($progress > 100) ? 100 : $progress) : 0; // Prevents overflow of the bar for imported data (<0 || >max) 66 $R->doc .= '<div title="' . hsc($value) . '" class="struct_progress-background_' . hsc($this->config['type']) . '">'; 67 $R->doc .= '<div title="' . hsc($value) . '" style="width: ' . $progress . '% ;" class="struct_progress_' . hsc($this->config['type']) . '">'; 68 $R->doc .= '<p>' . hsc($this->config['prefix'] . $value . $this->config['postfix']) . '</p>'; 69 $R->doc .= '</div>'; 70 $R->doc .= '</div>'; 71 } else { 72 $R->cdata($value); 73 } 74 75 return true; 76 } 77 78 /** 79 * @inheritDoc 80 */ 81 public function renderMultiValue($values, \Doku_Renderer $R, $mode) 82 { 83 if ($mode == 'xhtml') { 84 $R->doc .= '<div title="Multi-Value" class="struct_progress-multi">'; 85 foreach ($values as $value) { 86 $this->renderValue($value, $R, $mode); 87 } 88 $R->doc .= '</div>'; 89 } else { 90 $R->cdata(join(', ', $values)); 91 } 92 return true; 93 } 94 95 /** 96 * Works like number_format but keeps the decimals as is 97 * 98 * @link http://php.net/manual/en/function.number-format.php#91047 99 * @author info at daniel-marschall dot de 100 * @param float $number 101 * @param string $dec_point 102 * @param string $thousands_sep 103 * @return string 104 */ 105 protected function formatWithoutRounding($number, $dec_point, $thousands_sep) 106 { 107 $was_neg = $number < 0; // Because +0 == -0 108 109 $tmp = explode('.', $number); 110 $out = number_format(abs(floatval($tmp[0])), 0, $dec_point, $thousands_sep); 111 if (isset($tmp[1])) { 112 $out .= $dec_point . $tmp[1]; 113 } 114 115 if ($was_neg) { 116 $out = "-$out"; 117 } 118 119 return $out; 120 } 121 122 /** 123 * Decimals need to be casted to the proper type for sorting 124 * 125 * @param QueryBuilder $QB 126 * @param string $tablealias 127 * @param string $colname 128 * @param string $order 129 */ 130 public function sort(QueryBuilder $QB, $tablealias, $colname, $order) 131 { 132 $QB->addOrderBy("CAST($tablealias.$colname AS DECIMAL) $order"); 133 } 134 135 /** 136 * Decimals need to be casted to proper type for comparison 137 * 138 * @param QueryBuilderWhere $add 139 * @param string $tablealias 140 * @param string $colname 141 * @param string $comp 142 * @param string|\string[] $value 143 * @param string $op 144 */ 145 public function filter(QueryBuilderWhere $add, $tablealias, $colname, $comp, $value, $op) 146 { 147 $add = $add->where($op); // open a subgroup 148 $add->where('AND', "$tablealias.$colname != ''"); // make sure the field isn't empty 149 $op = 'AND'; 150 151 /** @var QueryBuilderWhere $add Where additionional queries are added to */ 152 if (is_array($value)) { 153 $add = $add->where($op); // sub where group 154 $op = 'OR'; 155 } 156 157 foreach ((array)$value as $item) { 158 $pl = $add->getQB()->addValue($item); 159 $add->where($op, "CAST($tablealias.$colname AS DECIMAL) $comp CAST($pl AS DECIMAL)"); 160 } 161 } 162 163 /** 164 * Only exact matches for numbers 165 * 166 * @return string 167 */ 168 public function getDefaultComparator() 169 { 170 return '='; 171 } 172} 173 174