xref: /plugin/struct/types/Page.php (revision f5df16ddb9f8ba8bd1c70590453952f130624475)
1<?php
2namespace dokuwiki\plugin\struct\types;
3
4use dokuwiki\plugin\struct\meta\QueryBuilder;
5use dokuwiki\plugin\struct\meta\QueryBuilderWhere;
6
7/**
8 * Class Page
9 *
10 * Represents a single page in the wiki. Will be linked in output.
11 *
12 * @package dokuwiki\plugin\struct\types
13 */
14class Page extends AbstractMultiBaseType {
15
16    protected $config = array(
17        'usetitles' => false,
18        'autocomplete' => array(
19            'mininput' => 2,
20            'maxresult' => 5,
21            'namespace' => '',
22            'postfix' => '',
23        ),
24    );
25
26    /**
27     * Output the stored data
28     *
29     * @param string $value the value stored in the database - JSON when titles are used
30     * @param \Doku_Renderer $R the renderer currently used to render the data
31     * @param string $mode The mode the output is rendered in (eg. XHTML)
32     * @return bool true if $mode could be satisfied
33     */
34    public function renderValue($value, \Doku_Renderer $R, $mode) {
35        if($this->config['usetitles']) {
36            list($id, $title) = json_decode($value);
37        } else {
38            $id = $value;
39            $title = null;
40        }
41
42        if(!$id) return true;
43
44        $R->internallink(":$id", $title);
45        return true;
46    }
47
48    /**
49     * Cleans the link
50     *
51     * @param string $rawvalue
52     * @return string
53     */
54    public function validate($rawvalue) {
55        list($page, $fragment) = explode('#', $rawvalue, 2);
56        return cleanID($page) . (strlen(cleanID($fragment)) > 0 ? '#' . cleanID($fragment) : '');
57    }
58
59    /**
60     * Autocompletion support for pages
61     *
62     * @return array
63     */
64    public function handleAjax() {
65        global $INPUT;
66
67        // check minimum length
68        $lookup = trim($INPUT->str('search'));
69        if(utf8_strlen($lookup) < $this->config['autocomplete']['mininput']) return array();
70
71        // results wanted?
72        $max = $this->config['autocomplete']['maxresult'];
73        if($max <= 0) return array();
74
75        // lookup with namespace and postfix applied
76        $namespace = $this->config['autocomplete']['namespace'];
77        if($namespace) {
78            // namespace may be relative, resolve in current context
79            $namespace .= ':foo'; // resolve expects pageID
80            resolve_pageid($INPUT->str('ns'), $namespace, $exists);
81            $namespace = getNS($namespace);
82        }
83        $postfix = $this->config['autocomplete']['postfix'];
84        if($namespace) $lookup .= ' @' . $namespace;
85
86        $data = ft_pageLookup($lookup, true, $this->config['usetitles']);
87        if(!count($data)) return array();
88
89        // this basically duplicates what we do in ajax_qsearch()
90        $result = array();
91        $counter = 0;
92        foreach($data as $id => $title) {
93            if($this->config['usetitles']) {
94                $name = $title . ' (' . $id . ')';
95            } else {
96                $ns = getNS($id);
97                if($ns) {
98                    $name = noNS($id) . ' (' . $ns . ')';
99                } else {
100                    $name = $id;
101                }
102            }
103
104            // check suffix
105            if($postfix && substr($id, -1 * strlen($postfix)) != $postfix) {
106                continue; // page does not end in postfix, don't suggest it
107            }
108
109            $result[] = array(
110                'label' => $name,
111                'value' => $id
112            );
113
114            $counter++;
115            if($counter > $max) break;
116        }
117
118        return $result;
119    }
120
121    /**
122     * When using titles, we need ot join the titles table
123     *
124     * @param QueryBuilder $QB
125     * @param string $tablealias
126     * @param string $colname
127     * @param string $alias
128     */
129    public function select(QueryBuilder $QB, $tablealias, $colname, $alias) {
130        if(!$this->config['usetitles']) {
131            parent::select($QB, $tablealias, $colname, $alias);
132            return;
133        }
134        $rightalias = $QB->generateTableAlias();
135        $QB->addLeftJoin($tablealias, 'titles', $rightalias, "$tablealias.$colname = $rightalias.pid");
136        $QB->addSelectStatement("STRUCT_JSON($tablealias.$colname, $rightalias.title)", $alias);
137    }
138
139    /**
140     * When using titles, sort by them first
141     *
142     * @param QueryBuilder $QB
143     * @param string $tablealias
144     * @param string $colname
145     * @param string $order
146     */
147    public function sort(QueryBuilder $QB, $tablealias, $colname, $order) {
148        if(!$this->config['usetitles']) {
149            parent::sort($QB, $tablealias, $colname, $order);
150            return;
151        }
152
153        $rightalias = $QB->generateTableAlias();
154        $QB->addLeftJoin($tablealias, 'titles', $rightalias, "$tablealias.$colname = $rightalias.pid");
155        $QB->addOrderBy("$rightalias.title $order");
156        $QB->addOrderBy("$tablealias.$colname $order");
157    }
158
159    /**
160     * Return the pageid only
161     *
162     * @param string $value
163     * @return string
164     */
165    public function rawValue($value) {
166        if($this->config['usetitles']) {
167            list($value) = json_decode($value);
168        }
169        return $value;
170    }
171
172    /**
173     * Return the title only
174     *
175     * @param string $value
176     * @return string
177     */
178    public function displayValue($value) {
179        if($this->config['usetitles']) {
180            list($pageid, $value) = json_decode($value);
181            if (blank($value)) {
182                $value = $pageid;
183            }
184        }
185        return $value;
186    }
187
188    /**
189     * When using titles, we need to compare against the title table, too
190     *
191     * @param QueryBuilderWhere $add
192     * @param string $tablealias
193     * @param string $colname
194     * @param string $comp
195     * @param string $value
196     * @param string $op
197     */
198    public function filter(QueryBuilderWhere $add, $tablealias, $colname, $comp, $value, $op) {
199        if(!$this->config['usetitles']) {
200            parent::filter($add, $tablealias, $colname, $comp, $value, $op);
201            return;
202        }
203
204        $QB = $add->getQB();
205        $rightalias = $QB->generateTableAlias();
206        $QB->addLeftJoin($tablealias, 'titles', $rightalias, "$tablealias.$colname = $rightalias.pid");
207
208        // compare against page and title
209        $sub = $add->where($op);
210        $pl = $QB->addValue($value);
211        $sub->whereOr("$tablealias.$colname $comp $pl");
212        $pl = $QB->addValue($value);
213        $sub->whereOr("$rightalias.title $comp $pl");
214    }
215
216}
217