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