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