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