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