14a2883e0SAndreas Gohr<?php 2d6d97f60SAnna Dabrowska 34a2883e0SAndreas Gohrnamespace dokuwiki\plugin\struct\types; 44a2883e0SAndreas Gohr 564cf7cc6SAndreas Gohruse dokuwiki\plugin\struct\meta\DateFormatConverter; 6b92072ddSAndreas Gohruse dokuwiki\plugin\struct\meta\QueryBuilder; 7b92072ddSAndreas Gohruse dokuwiki\plugin\struct\meta\QueryBuilderWhere; 84a2883e0SAndreas Gohruse dokuwiki\plugin\struct\meta\ValidationException; 94a2883e0SAndreas Gohr 10d6d97f60SAnna Dabrowskaclass DateTime extends Date 11d6d97f60SAnna Dabrowska{ 127234bfb1Ssplitbrain protected $config = [ 13*7fe2cdf2SAndreas Gohr 'format' => '', // filled by constructor 14218490cfSAnna Dabrowska 'prefilltoday' => false, 15733fd33bSAnna Dabrowska 'pastonly' => false, 167234bfb1Ssplitbrain 'futureonly' => false, 177234bfb1Ssplitbrain ]; 184a2883e0SAndreas Gohr 194a2883e0SAndreas Gohr /** 2064cf7cc6SAndreas Gohr * DateTime constructor. 2164cf7cc6SAndreas Gohr * 2264cf7cc6SAndreas Gohr * @param array|null $config 2364cf7cc6SAndreas Gohr * @param string $label 2464cf7cc6SAndreas Gohr * @param bool $ismulti 2564cf7cc6SAndreas Gohr * @param int $tid 2664cf7cc6SAndreas Gohr */ 27d6d97f60SAnna Dabrowska public function __construct($config = null, $label = '', $ismulti = false, $tid = 0) 28d6d97f60SAnna Dabrowska { 2964cf7cc6SAndreas Gohr global $conf; 3064cf7cc6SAndreas Gohr $this->config['format'] = DateFormatConverter::toDate($conf['dformat']); 3164cf7cc6SAndreas Gohr 3264cf7cc6SAndreas Gohr parent::__construct($config, $label, $ismulti, $tid); 3364cf7cc6SAndreas Gohr } 3464cf7cc6SAndreas Gohr 3564cf7cc6SAndreas Gohr /** 364a2883e0SAndreas Gohr * Return the editor to edit a single value 374a2883e0SAndreas Gohr * 384a2883e0SAndreas Gohr * @param string $name the form name where this has to be stored 39c0230d2cSAndreas Gohr * @param string $rawvalue the current value 40ee983135SMichael Große * @param string $htmlID 41ee983135SMichael Große * 424a2883e0SAndreas Gohr * @return string html 434a2883e0SAndreas Gohr */ 44d6d97f60SAnna Dabrowska public function valueEditor($name, $rawvalue, $htmlID) 45d6d97f60SAnna Dabrowska { 46c0230d2cSAndreas Gohr if ($this->config['prefilltoday'] && !$rawvalue) { 4716daff3dSAnna Dabrowska $rawvalue = date('Y-m-d\TH:i'); 484a2883e0SAndreas Gohr } 49b80ca5e1SMichael Große $rawvalue = str_replace(' ', 'T', $rawvalue); 507234bfb1Ssplitbrain $params = [ 513e7a5b3cSMichael Große 'name' => $name, 523e7a5b3cSMichael Große 'value' => $rawvalue, 533e7a5b3cSMichael Große 'class' => 'struct_datetime', 54*7fe2cdf2SAndreas Gohr 'type' => 'datetime-local', // HTML5 datetime picker 553e7a5b3cSMichael Große 'id' => $htmlID, 567234bfb1Ssplitbrain ]; 573e7a5b3cSMichael Große $attributes = buildAttributes($params, true); 583e7a5b3cSMichael Große return "<input $attributes />"; 594a2883e0SAndreas Gohr } 604a2883e0SAndreas Gohr 614a2883e0SAndreas Gohr /** 624a2883e0SAndreas Gohr * Validate a single value 634a2883e0SAndreas Gohr * 644a2883e0SAndreas Gohr * This function needs to throw a validation exception when validation fails. 654a2883e0SAndreas Gohr * The exception message will be prefixed by the appropriate field on output 664a2883e0SAndreas Gohr * 6723169abeSAndreas Gohr * @param string|array $rawvalue 684a2883e0SAndreas Gohr * @return string 694a2883e0SAndreas Gohr * @throws ValidationException 704a2883e0SAndreas Gohr */ 71d6d97f60SAnna Dabrowska public function validate($rawvalue) 72d6d97f60SAnna Dabrowska { 7323169abeSAndreas Gohr $rawvalue = trim($rawvalue); 747234bfb1Ssplitbrain [$date, $time] = array_pad(preg_split('/[ |T]/', $rawvalue, 2), 2, ''); 754a2883e0SAndreas Gohr $date = trim($date); 764a2883e0SAndreas Gohr $time = trim($time); 774a2883e0SAndreas Gohr 787234bfb1Ssplitbrain [$year, $month, $day] = explode('-', $date, 3); 794978faf1SAndreas Gohr if (!checkdate((int)$month, (int)$day, (int)$year)) { 804978faf1SAndreas Gohr throw new ValidationException('invalid datetime format'); 814a2883e0SAndreas Gohr } 82733fd33bSAnna Dabrowska if ($this->config['pastonly'] && strtotime($rawvalue) > time()) { 83d8bfcd03SAnna Dabrowska throw new ValidationException('pastonly'); 84218490cfSAnna Dabrowska } 85733fd33bSAnna Dabrowska if ($this->config['futureonly'] && strtotime($rawvalue) < time()) { 86d8bfcd03SAnna Dabrowska throw new ValidationException('futureonly'); 87218490cfSAnna Dabrowska } 884a2883e0SAndreas Gohr 897234bfb1Ssplitbrain [$h, $m] = array_pad(explode(':', $time, 3), 2, ''); // drop seconds 904a2883e0SAndreas Gohr $h = (int)$h; 914a2883e0SAndreas Gohr $m = (int)$m; 92b80ca5e1SMichael Große if ($h < 0 || $h > 23 || $m < 0 || $m > 59) { 934a2883e0SAndreas Gohr throw new ValidationException('invalid datetime format'); 944a2883e0SAndreas Gohr } 954a2883e0SAndreas Gohr 96b80ca5e1SMichael Große return sprintf("%d-%02d-%02d %02d:%02d", $year, $month, $day, $h, $m); 974a2883e0SAndreas Gohr } 984a2883e0SAndreas Gohr 99b92072ddSAndreas Gohr /** 100b92072ddSAndreas Gohr * @param QueryBuilder $QB 101b92072ddSAndreas Gohr * @param string $tablealias 102b92072ddSAndreas Gohr * @param string $colname 103b92072ddSAndreas Gohr * @param string $alias 104b92072ddSAndreas Gohr */ 105d6d97f60SAnna Dabrowska public function select(QueryBuilder $QB, $tablealias, $colname, $alias) 106d6d97f60SAnna Dabrowska { 107b92072ddSAndreas Gohr $col = "$tablealias.$colname"; 108e9259fa1SMichael Grosse 109e9259fa1SMichael Grosse // when accessing the revision column we need to convert from Unix timestamp 110e9259fa1SMichael Grosse if (is_a($this->context, 'dokuwiki\plugin\struct\meta\RevisionColumn')) { 111e9259fa1SMichael Grosse $rightalias = $QB->generateTableAlias(); 112e9259fa1SMichael Grosse $QB->addLeftJoin($tablealias, 'titles', $rightalias, "$tablealias.pid = $rightalias.pid"); 113e9259fa1SMichael Grosse $col = "DATETIME($rightalias.lastrev, 'unixepoch', 'localtime')"; 114b92072ddSAndreas Gohr } 115b92072ddSAndreas Gohr 116b92072ddSAndreas Gohr $QB->addSelectStatement($col, $alias); 117b92072ddSAndreas Gohr } 118b92072ddSAndreas Gohr 119b92072ddSAndreas Gohr /** 120af993d55SMichael Grosse * @param QueryBuilderWhere $add 121b92072ddSAndreas Gohr * @param string $tablealias 122b92072ddSAndreas Gohr * @param string $colname 123b92072ddSAndreas Gohr * @param string $comp 124b92072ddSAndreas Gohr * @param string|\string[] $value 125b92072ddSAndreas Gohr * @param string $op 126b92072ddSAndreas Gohr */ 127d6d97f60SAnna Dabrowska public function filter(QueryBuilderWhere $add, $tablealias, $colname, $comp, $value, $op) 128d6d97f60SAnna Dabrowska { 129b92072ddSAndreas Gohr $col = "$tablealias.$colname"; 13089579610SChris MacMackin $QB = $add->getQB(); 131e9259fa1SMichael Grosse 132e9259fa1SMichael Grosse // when accessing the revision column we need to convert from Unix timestamp 133e9259fa1SMichael Grosse if (is_a($this->context, 'dokuwiki\plugin\struct\meta\RevisionColumn')) { 134e9259fa1SMichael Grosse $rightalias = $QB->generateTableAlias(); 135e9259fa1SMichael Grosse $col = "DATETIME($rightalias.lastrev, 'unixepoch', 'localtime')"; 136e9259fa1SMichael Grosse $QB->addLeftJoin($tablealias, 'titles', $rightalias, "$tablealias.pid = $rightalias.pid"); 137b92072ddSAndreas Gohr } 138b92072ddSAndreas Gohr 1391ca21e17SAnna Dabrowska /** @var QueryBuilderWhere $add Where additional queries are added to */ 140b92072ddSAndreas Gohr if (is_array($value)) { 141af993d55SMichael Grosse $add = $add->where($op); // sub where group 142b92072ddSAndreas Gohr $op = 'OR'; 143b92072ddSAndreas Gohr } 144b92072ddSAndreas Gohr foreach ((array)$value as $item) { 145b92072ddSAndreas Gohr $pl = $QB->addValue($item); 146b92072ddSAndreas Gohr $add->where($op, "$col $comp $pl"); 147b92072ddSAndreas Gohr } 148b92072ddSAndreas Gohr } 149b92072ddSAndreas Gohr 150e9259fa1SMichael Grosse /** 151e9259fa1SMichael Grosse * When sorting `%lastupdated%`, then sort the data from the `titles` table instead the `data_` table. 152e9259fa1SMichael Grosse * 153e9259fa1SMichael Grosse * @param QueryBuilder $QB 154e9259fa1SMichael Grosse * @param string $tablealias 155e9259fa1SMichael Grosse * @param string $colname 156e9259fa1SMichael Grosse * @param string $order 157e9259fa1SMichael Grosse */ 158d6d97f60SAnna Dabrowska public function sort(QueryBuilder $QB, $tablealias, $colname, $order) 159d6d97f60SAnna Dabrowska { 160e9259fa1SMichael Grosse $col = "$tablealias.$colname"; 161e9259fa1SMichael Grosse 162e9259fa1SMichael Grosse if (is_a($this->context, 'dokuwiki\plugin\struct\meta\RevisionColumn')) { 163e9259fa1SMichael Grosse $rightalias = $QB->generateTableAlias(); 164e9259fa1SMichael Grosse $QB->addLeftJoin($tablealias, 'titles', $rightalias, "$tablealias.pid = $rightalias.pid"); 165e9259fa1SMichael Grosse $col = "$rightalias.lastrev"; 166e9259fa1SMichael Grosse } 167e9259fa1SMichael Grosse 168e9259fa1SMichael Grosse $QB->addOrderBy("$col $order"); 169e9259fa1SMichael Grosse } 1704a2883e0SAndreas Gohr} 171