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 return cleanID($rawvalue); 55 } 56 57 /** 58 * Autocompletion support for pages 59 * 60 * @return array 61 */ 62 public function handleAjax() { 63 global $INPUT; 64 65 // check minimum length 66 $lookup = trim($INPUT->str('search')); 67 if(utf8_strlen($lookup) < $this->config['autocomplete']['mininput']) return array(); 68 69 // results wanted? 70 $max = $this->config['autocomplete']['maxresult']; 71 if($max <= 0) return array(); 72 73 // lookup with namespace and postfix applied 74 $namespace = $this->config['autocomplete']['namespace']; 75 if($namespace) { 76 // namespace may be relative, resolve in current context 77 $namespace .= ':foo'; // resolve expects pageID 78 resolve_pageid($INPUT->str('ns'), $namespace, $exists); 79 $namespace = getNS($namespace); 80 } 81 $postfix = $this->config['postfix']; 82 if($namespace) $lookup .= ' @' . $namespace; 83 84 $data = ft_pageLookup($lookup, true, $this->config['usetitles']); 85 if(!count($data)) return array(); 86 87 // this basically duplicates what we do in ajax_qsearch() 88 $result = array(); 89 $counter = 0; 90 foreach($data as $id => $title) { 91 if($this->config['usetitles']) { 92 $name = $title . ' (' . $id . ')'; 93 } else { 94 $ns = getNS($id); 95 if($ns) { 96 $name = noNS($id) . ' (' . $ns . ')'; 97 } else { 98 $name = $id; 99 } 100 } 101 102 // check suffix 103 if($postfix && !substr($id, -1 * strlen($postfix)) == $postfix) { 104 continue; // page does not end in postfix, don't suggest it 105 } 106 107 $result[] = array( 108 'label' => $name, 109 'value' => $id 110 ); 111 112 $counter++; 113 if($counter > $max) break; 114 } 115 116 return $result; 117 } 118 119 /** 120 * When using titles, we need ot join the titles table 121 * 122 * @param QueryBuilder $QB 123 * @param string $tablealias 124 * @param string $colname 125 * @param string $alias 126 */ 127 public function select(QueryBuilder $QB, $tablealias, $colname, $alias) { 128 if(!$this->config['usetitles']) { 129 parent::select($QB, $tablealias, $colname, $alias); 130 return; 131 } 132 $rightalias = $QB->generateTableAlias(); 133 $QB->addLeftJoin($tablealias, 'titles', $rightalias, "$tablealias.$colname = $rightalias.pid"); 134 $QB->addSelectStatement("JSON($tablealias.$colname, $rightalias.title)", $alias); 135 } 136 137 /** 138 * When using titles, sort by them first 139 * 140 * @param QueryBuilder $QB 141 * @param string $tablealias 142 * @param string $colname 143 * @param string $order 144 */ 145 public function sort(QueryBuilder $QB, $tablealias, $colname, $order) { 146 if(!$this->config['usetitles']) { 147 parent::sort($QB, $tablealias, $colname, $order); 148 return; 149 } 150 151 $rightalias = $QB->generateTableAlias(); 152 $QB->addLeftJoin($tablealias, 'titles', $rightalias, "$tablealias.$colname = $rightalias.pid"); 153 $QB->addOrderBy("$rightalias.title $order"); 154 $QB->addOrderBy("$tablealias.$colname $order"); 155 } 156 157 /** 158 * Return the pageid only 159 * 160 * @param string $value 161 * @return string 162 */ 163 public function rawValue($value) { 164 if($this->config['usetitles']) { 165 list($value) = json_decode($value); 166 } 167 return $value; 168 } 169 170 /** 171 * When using titles, we need to compare against the title table, too 172 * 173 * @param QueryBuilder $QB 174 * @param string $tablealias 175 * @param string $colname 176 * @param string $comp 177 * @param string $value 178 * @param string $op 179 */ 180 public function filter(QueryBuilder $QB, $tablealias, $colname, $comp, $value, $op) { 181 if(!$this->config['usetitles']) { 182 parent::filter($QB, $tablealias, $colname, $comp, $value, $op); 183 return; 184 } 185 186 $rightalias = $QB->generateTableAlias(); 187 $QB->addLeftJoin($tablealias, 'titles', $rightalias, "$tablealias.$colname = $rightalias.pid"); 188 189 // compare against page and title 190 $sub = $QB->filters()->where($op); 191 $pl = $QB->addValue($value); 192 $sub->whereOr("$tablealias.$colname $comp $pl"); 193 $pl = $QB->addValue($value); 194 $sub->whereOr("$rightalias.title $comp $pl"); 195 } 196 197} 198