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