1<?php 2 3use dokuwiki\Extension\SyntaxPlugin; 4 5/** 6 * DokuWiki Plugin dbquery (Syntax Component) 7 * 8 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 9 * @author Andreas Gohr <dokuwiki@cosmocode.de> 10 */ 11class syntax_plugin_dbquery_query extends SyntaxPlugin 12{ 13 /** @inheritDoc */ 14 public function getType() 15 { 16 return 'substition'; 17 } 18 19 /** @inheritDoc */ 20 public function getPType() 21 { 22 return 'block'; 23 } 24 25 /** @inheritDoc */ 26 public function getSort() 27 { 28 return 135; 29 } 30 31 /** @inheritDoc */ 32 public function connectTo($mode) 33 { 34 $this->Lexer->addSpecialPattern('{{QUERY:\w+}}', $mode, 'plugin_dbquery_query'); 35 } 36 37 /** @inheritDoc */ 38 public function handle($match, $state, $pos, Doku_Handler $handler) 39 { 40 return ['name' => substr($match, 8, -2)]; 41 } 42 43 /** @inheritDoc */ 44 public function render($mode, Doku_Renderer $renderer, $data) 45 { 46 if ($mode !== 'xhtml') { 47 return false; 48 } 49 50 /** @var helper_plugin_dbquery $hlp */ 51 $hlp = plugin_load('helper', 'dbquery'); 52 try { 53 $qdata = $hlp->loadDataFromPage($data['name']); 54 $result = $hlp->executeQuery($qdata['codeblocks']['_'], $qdata['macros']['dsn'] ?? null); 55 } catch (\Exception $e) { 56 msg(hsc($e->getMessage()), -1); 57 return true; 58 } 59 60 if (count($result) === 1 && isset($result[0]['status']) && isset($qdata['codeblocks'][$result[0]['status']])) { 61 $this->renderStatus($result, $qdata['codeblocks'][$result[0]['status']], $renderer); 62 } elseif ($qdata['macros']['transpose']) { 63 $this->renderTransposedResultTable($result, $renderer); 64 } else { 65 $this->renderResultTable($result, $renderer); 66 } 67 68 return true; 69 } 70 71 /** 72 * Render given result via the given status HTML 73 * 74 * @param string[][] $result 75 * @param string $html 76 * @param Doku_Renderer $R 77 */ 78 public function renderStatus($result, $html, Doku_Renderer $R) 79 { 80 $value = $result[0]['result'] ?? ''; 81 $html = str_replace(':result', hsc($value), $html); 82 $R->doc .= $html; 83 } 84 85 /** 86 * Render the given result as a table 87 * 88 * @param string[][] $result 89 * @param Doku_Renderer $R 90 */ 91 public function renderResultTable($result, Doku_Renderer $R) 92 { 93 global $lang; 94 95 if (!count($result)) { 96 $R->cdata($lang['nothingfound']); 97 return; 98 } 99 100 $R->table_open(); 101 $R->tablethead_open(); 102 $R->tablerow_open(); 103 foreach (array_keys($result[0]) as $header) { 104 $R->tableheader_open(); 105 $R->cdata($header); 106 $R->tableheader_close(); 107 } 108 $R->tablerow_close(); 109 $R->tablethead_close(); 110 111 $R->tabletbody_open(); 112 foreach ($result as $row) { 113 $R->tablerow_open(); 114 foreach ($row as $cell) { 115 $R->tablecell_open(); 116 $this->cellFormat($cell, $R); 117 $R->tablecell_close(); 118 } 119 $R->tablerow_close(); 120 } 121 $R->tabletbody_close(); 122 $R->table_close(); 123 } 124 125 /** 126 * Render the given result as a table, but turned 90 degrees 127 * 128 * @param string[][] $result 129 * @param Doku_Renderer $R 130 */ 131 public function renderTransposedResultTable($result, Doku_Renderer $R) 132 { 133 global $lang; 134 135 if (!count($result)) { 136 $R->cdata($lang['nothingfound']); 137 return; 138 } 139 140 $width = count($result[0]); 141 $height = count($result); 142 143 $R->table_open(); 144 for ($x = 0; $x < $width; $x++) { 145 $R->tablerow_open(); 146 $R->tableheader_open(); 147 $R->cdata(array_keys($result[0])[$x]); 148 $R->tableheader_close(); 149 150 for ($y = 0; $y < $height; $y++) { 151 $R->tablecell_open(); 152 $this->cellFormat(array_values($result[$y])[$x], $R); 153 $R->tablecell_close(); 154 } 155 $R->tablerow_close(); 156 } 157 $R->table_close(); 158 } 159 160 /** 161 * Pass the given cell content to the correct renderer call 162 * 163 * Detects a subset of the wiki link syntax 164 * 165 * @param string $content 166 * @param Doku_Renderer $R 167 * @return void 168 */ 169 protected function cellFormat($content, Doku_Renderer $R) 170 { 171 // external urls 172 if (preg_match('/^\[\[(https?:\/\/[^|\]]+)(|.*?)?]]$/', $content, $m)) { 173 $url = $m[1]; 174 $title = $m[2] ?? ''; 175 $title = trim($title, '|'); 176 $R->externallink($url, $title); 177 return; 178 } 179 180 // internal urls 181 if (preg_match('/^\[\[([^|\]]+)(|.*?)?]]$/', $content, $m)) { 182 $page = cleanID($m[1]); 183 $title = $m[2] ?? ''; 184 $title = trim($title, '|'); 185 $R->internallink($page, $title); 186 return; 187 } 188 189 $R->cdata($content); 190 } 191} 192