1<?php
2
3namespace dokuwiki\plugin\struct\types;
4
5use dokuwiki\plugin\struct\meta\QueryBuilder;
6use dokuwiki\plugin\struct\meta\QueryBuilderWhere;
7use dokuwiki\plugin\struct\meta\StructException;
8use dokuwiki\plugin\struct\meta\ValidationException;
9
10class User extends AbstractMultiBaseType
11{
12    protected $config = array(
13        'existingonly' => true,
14        'autocomplete' => array(
15            'fullname' => true,
16            'mininput' => 2,
17            'maxresult' => 5,
18        ),
19    );
20
21    /**
22     * @param string $rawvalue the user to validate
23     * @return int|string|void
24     */
25    public function validate($rawvalue)
26    {
27        $rawvalue = parent::validate($rawvalue);
28
29        if ($this->config['existingonly']) {
30            /** @var \DokuWiki_Auth_Plugin $auth */
31            global $auth;
32            $info = $auth->getUserData($rawvalue, false);
33            if ($info === false) throw new ValidationException('User not found', $rawvalue);
34        }
35
36        return $rawvalue;
37    }
38
39    /**
40     * @param string $value the user to display
41     * @param \Doku_Renderer $R
42     * @param string $mode
43     * @return bool
44     */
45    public function renderValue($value, \Doku_Renderer $R, $mode)
46    {
47        if ($mode == 'xhtml') {
48            $name = userlink($value);
49            $R->doc .= $name;
50        } else {
51            $name = userlink($value, true);
52            $R->cdata($name);
53        }
54        return true;
55    }
56
57    /**
58     * Autocompletion for user names
59     *
60     * @return array
61     * @todo should we have any security mechanism? Currently everybody can look up users
62     */
63    public function handleAjax()
64    {
65        /** @var \DokuWiki_Auth_Plugin $auth */
66        global $auth;
67        global $INPUT;
68
69        if (!$auth->canDo('getUsers')) {
70            throw new StructException('The user backend can not search for users');
71        }
72
73        // check minimum length
74        $lookup = trim($INPUT->str('search'));
75        if (utf8_strlen($lookup) < $this->config['autocomplete']['mininput']) return array();
76
77        // results wanted?
78        $max = $this->config['autocomplete']['maxresult'];
79        if ($max <= 0) return array();
80
81        // find users by login, fill up with names if wanted
82        $logins = (array)$auth->retrieveUsers(0, $max, array('user' => $lookup));
83        if ((count($logins) < $max) && $this->config['autocomplete']['fullname']) {
84            $logins = array_merge($logins, (array)$auth->retrieveUsers(0, $max, array('name' => $lookup)));
85        }
86
87        // reformat result for jQuery UI Autocomplete
88        $users = array();
89        foreach ($logins as $login => $info) {
90            $users[] = array(
91                'label' => $info['name'] . ' [' . $login . ']',
92                'value' => $login
93            );
94        }
95
96        return $users;
97    }
98
99    /**
100     * When handling `%lasteditor%` get the data from the `titles` table instead the `data_` table.
101     *
102     * @param QueryBuilder $QB
103     * @param string $tablealias
104     * @param string $colname
105     * @param string $alias
106     */
107    public function select(QueryBuilder $QB, $tablealias, $colname, $alias)
108    {
109        if (is_a($this->context, 'dokuwiki\plugin\struct\meta\UserColumn')) {
110            $rightalias = $QB->generateTableAlias();
111            $QB->addLeftJoin($tablealias, 'titles', $rightalias, "$tablealias.pid = $rightalias.pid");
112            $QB->addSelectStatement("$rightalias.lasteditor", $alias);
113            return;
114        }
115
116        parent::select($QB, $tablealias, $colname, $alias);
117    }
118
119    /**
120     * When sorting `%lasteditor%`, then sort the data from the `titles` table instead the `data_` table.
121     *
122     * @param QueryBuilder $QB
123     * @param string $tablealias
124     * @param string $colname
125     * @param string $order
126     */
127    public function sort(QueryBuilder $QB, $tablealias, $colname, $order)
128    {
129        if (is_a($this->context, 'dokuwiki\plugin\struct\meta\UserColumn')) {
130            $rightalias = $QB->generateTableAlias();
131            $QB->addLeftJoin($tablealias, 'titles', $rightalias, "$tablealias.pid = $rightalias.pid");
132            $QB->addOrderBy("$rightalias.lasteditor $order");
133            return;
134        }
135
136        $QB->addOrderBy("$tablealias.$colname $order");
137    }
138
139    /**
140     * When using `%lasteditor%`, we need to compare against the `title` table.
141     *
142     * @param QueryBuilderWhere $add
143     * @param string $tablealias
144     * @param string $colname
145     * @param string $comp
146     * @param string|\string[] $value
147     * @param string $op
148     */
149    public function filter(QueryBuilderWhere $add, $tablealias, $colname, $comp, $value, $op)
150    {
151        if (is_a($this->context, 'dokuwiki\plugin\struct\meta\UserColumn')) {
152            $QB = $add->getQB();
153            $rightalias = $QB->generateTableAlias();
154            $QB->addLeftJoin($tablealias, 'titles', $rightalias, "$tablealias.pid = $rightalias.pid");
155
156            // compare against page and title
157            $sub = $add->where($op);
158            $pl = $QB->addValue($value);
159            $sub->whereOr("$rightalias.lasteditor $comp $pl");
160            return;
161        }
162
163        parent::filter($add, $tablealias, $colname, $comp, $value, $op);
164    }
165}
166