xref: /plugin/struct/types/DateTime.php (revision 0ceefd5c55d49dcf9a9f59c8e57e60eaeea1c187)
1<?php
2namespace dokuwiki\plugin\struct\types;
3
4use dokuwiki\plugin\struct\meta\DateFormatConverter;
5use dokuwiki\plugin\struct\meta\QueryBuilder;
6use dokuwiki\plugin\struct\meta\QueryBuilderWhere;
7use dokuwiki\plugin\struct\meta\ValidationException;
8
9class DateTime extends Date {
10
11    protected $config = array(
12        'format' => '', // filled by constructor
13        'prefilltoday' => false,
14        'pastonly' => false,
15        'futureonly' => false
16    );
17
18    /**
19     * DateTime constructor.
20     *
21     * @param array|null $config
22     * @param string $label
23     * @param bool $ismulti
24     * @param int $tid
25     */
26    public function __construct($config = null, $label = '', $ismulti = false, $tid = 0) {
27        global $conf;
28        $this->config['format'] = DateFormatConverter::toDate($conf['dformat']);
29
30        parent::__construct($config, $label, $ismulti, $tid);
31    }
32
33    /**
34     * Return the editor to edit a single value
35     *
36     * @param string $name     the form name where this has to be stored
37     * @param string $rawvalue the current value
38     * @param string $htmlID
39     *
40     * @return string html
41     */
42    public function valueEditor($name, $rawvalue, $htmlID) {
43        if($this->config['prefilltoday'] && !$rawvalue) {
44            $rawvalue = date('Y-m-d\TH:i');
45        }
46        $rawvalue = str_replace(' ', 'T', $rawvalue);
47        $params = array(
48            'name' => $name,
49            'value' => $rawvalue,
50            'class' => 'struct_datetime',
51            'type' => 'datetime-local', // HTML5 datetime picker
52            'id' => $htmlID,
53        );
54        $attributes = buildAttributes($params, true);
55        return "<input $attributes />";
56    }
57
58    /**
59     * Validate a single value
60     *
61     * This function needs to throw a validation exception when validation fails.
62     * The exception message will be prefixed by the appropriate field on output
63     *
64     * @param string|array $rawvalue
65     * @return string
66     * @throws ValidationException
67     */
68    public function validate($rawvalue) {
69        $rawvalue = trim($rawvalue);
70        list($date, $time) = preg_split('/[ |T]/', $rawvalue, 2);
71        $date = trim($date);
72        $time = trim($time);
73
74        list($year, $month, $day) = explode('-', $date, 3);
75        if(!checkdate((int) $month, (int) $day, (int) $year)) {
76            throw new ValidationException('invalid datetime format');
77        }
78        if ($this->config['pastonly'] && strtotime($rawvalue) > time()) {
79            throw new ValidationException('pastonly');
80        }
81        if ($this->config['futureonly'] && strtotime($rawvalue) < time()) {
82            throw new ValidationException('futureonly');
83        }
84
85        list($h, $m) = explode(':', $time, 3); // drop seconds
86        $h = (int) $h;
87        $m = (int) $m;
88        if($h < 0 || $h > 23 || $m < 0 || $m > 59) {
89            throw new ValidationException('invalid datetime format');
90        }
91
92        return sprintf("%d-%02d-%02d %02d:%02d", $year, $month, $day, $h, $m);
93    }
94
95    /**
96     * @param QueryBuilder $QB
97     * @param string $tablealias
98     * @param string $colname
99     * @param string $alias
100     */
101    public function select(QueryBuilder $QB, $tablealias, $colname, $alias) {
102        $col = "$tablealias.$colname";
103
104        // when accessing the revision column we need to convert from Unix timestamp
105        if(is_a($this->context,'dokuwiki\plugin\struct\meta\RevisionColumn')) {
106            $rightalias = $QB->generateTableAlias();
107            $QB->addLeftJoin($tablealias, 'titles', $rightalias, "$tablealias.pid = $rightalias.pid");
108            $col = "DATETIME($rightalias.lastrev, 'unixepoch', 'localtime')";
109        }
110
111        $QB->addSelectStatement($col, $alias);
112    }
113
114    /**
115     * @param QueryBuilderWhere $add
116     * @param string $tablealias
117     * @param string $colname
118     * @param string $comp
119     * @param string|\string[] $value
120     * @param string $op
121     */
122    public function filter(QueryBuilderWhere $add, $tablealias, $colname, $comp, $value, $op) {
123        $col = "$tablealias.$colname";
124
125        // when accessing the revision column we need to convert from Unix timestamp
126        if(is_a($this->context,'dokuwiki\plugin\struct\meta\RevisionColumn')) {
127            $QB = $add->getQB();
128            $rightalias = $QB->generateTableAlias();
129            $col = "DATETIME($rightalias.lastrev, 'unixepoch', 'localtime')";
130            $QB->addLeftJoin($tablealias, 'titles', $rightalias, "$tablealias.pid = $rightalias.pid");
131        }
132
133        /** @var QueryBuilderWhere $add Where additionional queries are added to*/
134        if(is_array($value)) {
135            $add = $add->where($op); // sub where group
136            $op = 'OR';
137        }
138        foreach((array) $value as $item) {
139            $pl = $QB->addValue($item);
140            $add->where($op, "$col $comp $pl");
141        }
142    }
143
144    /**
145     * When sorting `%lastupdated%`, then sort the data from the `titles` table instead the `data_` table.
146     *
147     * @param QueryBuilder $QB
148     * @param string $tablealias
149     * @param string $colname
150     * @param string $order
151     */
152    public function sort(QueryBuilder $QB, $tablealias, $colname, $order) {
153        $col = "$tablealias.$colname";
154
155        if(is_a($this->context,'dokuwiki\plugin\struct\meta\RevisionColumn')) {
156            $rightalias = $QB->generateTableAlias();
157            $QB->addLeftJoin($tablealias, 'titles', $rightalias, "$tablealias.pid = $rightalias.pid");
158            $col = "$rightalias.lastrev";
159        }
160
161        $QB->addOrderBy("$col $order");
162    }
163
164}
165