1<?php 2 3/** 4 * DokuWiki Plugin struct (Syntax Component) 5 * 6 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 7 * @author Andreas Gohr, Michael Große <dokuwiki@cosmocode.de> 8 */ 9 10use dokuwiki\Extension\SyntaxPlugin; 11use dokuwiki\plugin\struct\meta\Aggregation; 12use dokuwiki\plugin\struct\meta\AggregationTable; 13use dokuwiki\plugin\struct\meta\ConfigParser; 14use dokuwiki\plugin\struct\meta\SearchConfig; 15use dokuwiki\plugin\struct\meta\StructException; 16 17class syntax_plugin_struct_table extends SyntaxPlugin 18{ 19 /** @var string which class to use for output */ 20 protected $tableclass = AggregationTable::class; 21 22 /** @var string Config options that are not allowed for this syntax mode */ 23 protected $illegalOptions = ['nesting', 'index']; 24 25 /** 26 * @return string Syntax mode type 27 */ 28 public function getType() 29 { 30 return 'substition'; 31 } 32 33 /** 34 * @return string Paragraph type 35 */ 36 public function getPType() 37 { 38 return 'block'; 39 } 40 41 /** 42 * @return int Sort order - Low numbers go before high numbers 43 */ 44 public function getSort() 45 { 46 return 155; 47 } 48 49 /** 50 * Connect lookup pattern to lexer. 51 * 52 * @param string $mode Parser mode 53 */ 54 public function connectTo($mode) 55 { 56 $this->Lexer->addSpecialPattern('----+ *struct table *-+\n.*?\n----+', $mode, 'plugin_struct_table'); 57 } 58 59 /** 60 * Handle matches of the struct syntax 61 * 62 * @param string $match The match of the syntax 63 * @param int $state The state of the handler 64 * @param int $pos The position in the document 65 * @param Doku_Handler $handler The handler 66 * @return array Data for the renderer 67 */ 68 public function handle($match, $state, $pos, Doku_Handler $handler) 69 { 70 global $conf; 71 72 $lines = explode("\n", $match); 73 array_shift($lines); 74 array_pop($lines); 75 76 try { 77 $parser = new ConfigParser($lines); 78 $config = $parser->getConfig(); 79 $this->checkForInvalidOptions($config); 80 return $config; 81 } catch (StructException $e) { 82 msg($e->getMessage(), -1, $e->getLine(), $e->getFile()); 83 if ($conf['allowdebug']) msg('<pre>' . hsc($e->getTraceAsString()) . '</pre>', -1); 84 return null; 85 } 86 } 87 88 /** 89 * Render xhtml output or metadata 90 * 91 * @param string $format Renderer mode (supported modes: xhtml) 92 * @param Doku_Renderer $renderer The renderer 93 * @param array $config The parsed config data from the handler() function 94 * @return bool If rendering was successful. 95 */ 96 public function render($format, Doku_Renderer $renderer, $config) 97 { 98 global $INFO; 99 global $conf; 100 101 if (!$config) return false; 102 $config = $this->addTypeFilter($config); // add type specific filters 103 104 // always use the main page's ID @todo might make sense as utility method somewhere 105 if ($INFO !== null) { 106 $mainId = $INFO['id']; 107 } else { 108 $mainId = getID(); 109 } 110 111 try { 112 $search = $this->getSearchConfig($config); 113 if ($format === 'struct_csv') { 114 // no pagination in export 115 $search->setLimit(0); 116 $search->setOffset(0); 117 } 118 119 $table = new $this->tableclass($mainId, $format, $renderer, $search); 120 if (!$table instanceof Aggregation) { 121 // this may happen with plugins that extend struct 122 throw new StructException('Aggregation class does not inherit Aggregation: ' . $this->tableclass); 123 } 124 125 $table->startScope(); 126 $table->render(true); 127 $table->finishScope(); 128 129 if ($format === 'metadata') { 130 /** @var Doku_Renderer_metadata $renderer */ 131 $renderer->meta['plugin']['struct']['hasaggregation'] = $search->getCacheFlag(); 132 } 133 } catch (StructException $e) { 134 msg($e->getMessage(), -1, $e->getLine(), $e->getFile()); 135 if ($conf['allowdebug']) msg('<pre>' . hsc($e->getTraceAsString()) . '</pre>', -1); 136 } 137 138 return true; 139 } 140 141 /** 142 * Initialize a SearchConfig with the given parsed config 143 * 144 * @param array $config 145 * @return SearchConfig 146 */ 147 protected function getSearchConfig($config) 148 { 149 return new SearchConfig($config); 150 } 151 152 153 /** 154 * Filter based on primary key columns, applicable in child classes 155 * 156 * @param array $config 157 * @return array 158 */ 159 protected function addTypeFilter($config) 160 { 161 return $config; 162 } 163 164 /** 165 * Checks for options that do not work in this aggregation 166 * 167 * @param array $config 168 */ 169 protected function checkForInvalidOptions($config) 170 { 171 foreach ($this->illegalOptions as $illegalOption) { 172 if (!empty($config[$illegalOption])) { 173 throw new StructException('illegal option', $illegalOption); 174 } 175 } 176 } 177} 178