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