1549a0837SAndreas Gohr<?php 2549a0837SAndreas Gohr/** 3549a0837SAndreas Gohr * DokuWiki Plugin struct (Syntax Component) 4549a0837SAndreas Gohr * 5549a0837SAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 6549a0837SAndreas Gohr * @author Andreas Gohr, Michael Große <dokuwiki@cosmocode.de> 7549a0837SAndreas Gohr */ 8549a0837SAndreas Gohr 9549a0837SAndreas Gohr// must be run within Dokuwiki 105511bd5bSAndreas Gohruse plugin\struct\meta\ConfigParser; 1115929be2SAndreas Gohruse plugin\struct\meta\Search; 125511bd5bSAndreas Gohruse plugin\struct\meta\SearchConfig; 1315929be2SAndreas Gohruse plugin\struct\meta\SearchException; 145511bd5bSAndreas Gohruse plugin\struct\meta\StructException; 1515929be2SAndreas Gohr 16549a0837SAndreas Gohrif (!defined('DOKU_INC')) die(); 17549a0837SAndreas Gohr 18549a0837SAndreas Gohrclass syntax_plugin_struct_table extends DokuWiki_Syntax_Plugin { 19549a0837SAndreas Gohr /** 20549a0837SAndreas Gohr * @return string Syntax mode type 21549a0837SAndreas Gohr */ 22549a0837SAndreas Gohr public function getType() { 2315929be2SAndreas Gohr return 'substition'; 24549a0837SAndreas Gohr } 25549a0837SAndreas Gohr /** 26549a0837SAndreas Gohr * @return string Paragraph type 27549a0837SAndreas Gohr */ 28549a0837SAndreas Gohr public function getPType() { 2915929be2SAndreas Gohr return 'block'; 30549a0837SAndreas Gohr } 31549a0837SAndreas Gohr /** 32549a0837SAndreas Gohr * @return int Sort order - Low numbers go before high numbers 33549a0837SAndreas Gohr */ 34549a0837SAndreas Gohr public function getSort() { 355511bd5bSAndreas Gohr return 155; 36549a0837SAndreas Gohr } 37549a0837SAndreas Gohr 38549a0837SAndreas Gohr /** 39549a0837SAndreas Gohr * Connect lookup pattern to lexer. 40549a0837SAndreas Gohr * 41549a0837SAndreas Gohr * @param string $mode Parser mode 42549a0837SAndreas Gohr */ 43549a0837SAndreas Gohr public function connectTo($mode) { 445511bd5bSAndreas Gohr $this->Lexer->addSpecialPattern('----+ *struct table *-+\n.*?\n----+', $mode, 'plugin_struct_table'); 45549a0837SAndreas Gohr } 46549a0837SAndreas Gohr 47549a0837SAndreas Gohr 48549a0837SAndreas Gohr /** 49549a0837SAndreas Gohr * Handle matches of the struct syntax 50549a0837SAndreas Gohr * 51549a0837SAndreas Gohr * @param string $match The match of the syntax 52549a0837SAndreas Gohr * @param int $state The state of the handler 53549a0837SAndreas Gohr * @param int $pos The position in the document 54549a0837SAndreas Gohr * @param Doku_Handler $handler The handler 55549a0837SAndreas Gohr * @return array Data for the renderer 56549a0837SAndreas Gohr */ 57ab466032SAndreas Gohr public function handle($match, $state, $pos, Doku_Handler $handler){ 58549a0837SAndreas Gohr 595511bd5bSAndreas Gohr $lines = explode("\n", $match); 605511bd5bSAndreas Gohr array_shift($lines); 615511bd5bSAndreas Gohr array_pop($lines); 625511bd5bSAndreas Gohr 635511bd5bSAndreas Gohr try { 645511bd5bSAndreas Gohr $parser = new ConfigParser($lines); 655511bd5bSAndreas Gohr return $parser->getConfig(); 665511bd5bSAndreas Gohr } catch (StructException $e) { 675511bd5bSAndreas Gohr msg($e->getMessage(), -1, $e->getLine(), $e->getFile()); 685511bd5bSAndreas Gohr return null; 695511bd5bSAndreas Gohr } 70549a0837SAndreas Gohr } 71549a0837SAndreas Gohr 7229877279SMichael Große protected $sums = array(); 7329877279SMichael Große 7429877279SMichael Große /** @var helper_plugin_struct_aggregation $dthlp */ 7529877279SMichael Große protected $dthlp = null; 7629877279SMichael Große 77549a0837SAndreas Gohr /** 78549a0837SAndreas Gohr * Render xhtml output or metadata 79549a0837SAndreas Gohr * 80549a0837SAndreas Gohr * @param string $mode Renderer mode (supported modes: xhtml) 81549a0837SAndreas Gohr * @param Doku_Renderer $renderer The renderer 82549a0837SAndreas Gohr * @param array $data The data from the handler() function 83549a0837SAndreas Gohr * @return bool If rendering was successful. 84549a0837SAndreas Gohr */ 85ab466032SAndreas Gohr public function render($mode, Doku_Renderer $renderer, $data) { 86549a0837SAndreas Gohr if($mode != 'xhtml') return false; 875511bd5bSAndreas Gohr if(!$data) return false; 8829877279SMichael Große $this->dthlp = $this->loadHelper('struct_aggregation'); 8929877279SMichael Große 9029877279SMichael Große $clist = $data['cols']; 9129877279SMichael Große 9229877279SMichael Große //reset counters 9329877279SMichael Große $this->sums = array(); 9429877279SMichael Große 9529877279SMichael Große /** @var \helper_plugin_struct_config $confHlp */ 9629877279SMichael Große $confHlp = plugin_load('helper','struct_config'); 97549a0837SAndreas Gohr 9815929be2SAndreas Gohr try { 9929877279SMichael Große global $INPUT; 10029877279SMichael Große 10129877279SMichael Große $datasrt = $INPUT->str('datasrt'); 10229877279SMichael Große if ($datasrt) { 10329877279SMichael Große $data['sort'] = $confHlp->parseSort($datasrt); 10429877279SMichael Große } 10529877279SMichael Große $dataflt = $INPUT->arr('dataflt'); 10629877279SMichael Große if ($dataflt) { 10729877279SMichael Große foreach ($dataflt as $colcomp => $filter) { 10829877279SMichael Große $data['filter'][] = $confHlp->parseFilterLine('AND', $colcomp . $filter); 10929877279SMichael Große } 11029877279SMichael Große } 1115511bd5bSAndreas Gohr $search = new SearchConfig($data); 11229877279SMichael Große $rows = $search->execute(); 11329877279SMichael Große $cnt = count($rows); 1145511bd5bSAndreas Gohr 11529877279SMichael Große if ($cnt === 0) { 11629877279SMichael Große //$this->nullList($data, $clist, $R); 11729877279SMichael Große //return true; 11829877279SMichael Große } 1195511bd5bSAndreas Gohr 120*93485d71SMichael Große $dataofs = $INPUT->has('dataofs') ? $INPUT->int('dataofs') : 0; 12129877279SMichael Große if ($data['limit'] && $cnt > $data['limit']) { 122*93485d71SMichael Große $rows = array_slice($rows, $dataofs, $data['limit']); 12329877279SMichael Große } 12415929be2SAndreas Gohr 12529877279SMichael Große $this->renderPreTable($mode, $renderer, $clist, $data); 12629877279SMichael Große $this->renderRows($mode, $renderer, $data, $rows); 12729877279SMichael Große $this->renderPostTable($mode, $renderer, $data, $cnt); 12829877279SMichael Große 12929877279SMichael Große $renderer->doc .= ''; 1305511bd5bSAndreas Gohr } catch (StructException $e) { 13115929be2SAndreas Gohr msg($e->getMessage(), -1, $e->getLine(), $e->getFile()); 13215929be2SAndreas Gohr } 13315929be2SAndreas Gohr 134549a0837SAndreas Gohr return true; 135549a0837SAndreas Gohr } 13629877279SMichael Große 13729877279SMichael Große /** 13829877279SMichael Große * create the pretext to the actual table rows 13929877279SMichael Große * 14029877279SMichael Große * @param $mode 14129877279SMichael Große * @param Doku_Renderer $renderer 14229877279SMichael Große * @param $clist 14329877279SMichael Große * @param $data 14429877279SMichael Große */ 14529877279SMichael Große protected function renderPreTable($mode, Doku_Renderer $renderer, $clist, $data) { 14629877279SMichael Große // Save current request params to not loose them 14729877279SMichael Große $cur_params = $this->dthlp->_get_current_param(); 14829877279SMichael Große 14929877279SMichael Große $this->startScope($mode, $renderer); 15029877279SMichael Große $this->showActiveFilters($mode, $renderer, $cur_params); 15129877279SMichael Große $this->startTable($mode, $renderer); 15229877279SMichael Große $renderer->tablethead_open(); 15329877279SMichael Große $this->buildColumnHeaders($mode, $renderer, $clist, $data, $cur_params); 15429877279SMichael Große $this->addDynamicFilters($mode, $renderer, $data, $cur_params); 15529877279SMichael Große $renderer->tablethead_close(); 15629877279SMichael Große } 15729877279SMichael Große 15829877279SMichael Große /** 15929877279SMichael Große * @param array $data 16029877279SMichael Große * @param int $rowcnt 16129877279SMichael Große * 16229877279SMichael Große * @return string 16329877279SMichael Große */ 16429877279SMichael Große private function renderPostTable($mode, Doku_Renderer $renderer, $data, $rowcnt) { 16529877279SMichael Große $this->summarize($mode, $renderer, $data, $this->sums); 16629877279SMichael Große $this->addLimitControls($mode, $renderer, $data, $rowcnt); 16729877279SMichael Große $this->finishTableAndScope($mode, $renderer); 16829877279SMichael Große } 16929877279SMichael Große 17029877279SMichael Große /** 17129877279SMichael Große * if limit was set, add control 17229877279SMichael Große * 173*93485d71SMichael Große * @param $mode 174*93485d71SMichael Große * @param Doku_Renderer $renderer 17529877279SMichael Große * @param $data 17629877279SMichael Große * @param $rowcnt 17729877279SMichael Große */ 17829877279SMichael Große protected function addLimitControls($mode, Doku_Renderer $renderer, $data, $rowcnt) { 17929877279SMichael Große global $ID; 18029877279SMichael Große 18129877279SMichael Große if($data['limit']) { 18229877279SMichael Große $renderer->tablerow_open(); 18329877279SMichael Große $renderer->tableheader_open((count($data['cols']) + ($data['rownumbers'] ? 1 : 0))); 18429877279SMichael Große $offset = (int) $_REQUEST['dataofs']; 18529877279SMichael Große if($offset) { 18629877279SMichael Große $prev = $offset - $data['limit']; 18729877279SMichael Große if($prev < 0) { 18829877279SMichael Große $prev = 0; 18929877279SMichael Große } 19029877279SMichael Große 19129877279SMichael Große // keep url params 19229877279SMichael Große $params = $this->dthlp->_a2ua('dataflt', $_REQUEST['dataflt']); 19329877279SMichael Große if(isset($_REQUEST['datasrt'])) { 19429877279SMichael Große $params['datasrt'] = $_REQUEST['datasrt']; 19529877279SMichael Große } 19629877279SMichael Große $params['dataofs'] = $prev; 19729877279SMichael Große 19829877279SMichael Große if ($mode == 'xhtml') { 19929877279SMichael Große $renderer->doc .= '<a href="' . wl($ID, $params) . 20029877279SMichael Große '" title="' . $this->getLang('prev') . 20129877279SMichael Große '" class="prev">' . $this->getLang('prev') . '</a> '; 20229877279SMichael Große } else { 20329877279SMichael Große $renderer->internallink($ID,$this->getLang('prev')); 20429877279SMichael Große } 20529877279SMichael Große } 20629877279SMichael Große 207*93485d71SMichael Große if($rowcnt > $offset + $data['limit']) { 20829877279SMichael Große $next = $offset + $data['limit']; 20929877279SMichael Große 21029877279SMichael Große // keep url params 21129877279SMichael Große $params = $this->dthlp->_a2ua('dataflt', $_REQUEST['dataflt']); 21229877279SMichael Große if(isset($_REQUEST['datasrt'])) { 21329877279SMichael Große $params['datasrt'] = $_REQUEST['datasrt']; 21429877279SMichael Große } 21529877279SMichael Große $params['dataofs'] = $next; 21629877279SMichael Große 21729877279SMichael Große if ($mode == 'xhtml') { 21829877279SMichael Große $renderer->doc .= '<a href="' . wl($ID, $params) . 21929877279SMichael Große '" title="' . $this->getLang('next') . 22029877279SMichael Große '" class="next">' . $this->getLang('next') . '</a>'; 22129877279SMichael Große } else { 22229877279SMichael Große $renderer->internallink($ID,$this->getLang('next')); 22329877279SMichael Große } 22429877279SMichael Große } 22529877279SMichael Große $renderer->tableheader_close(); 22629877279SMichael Große $renderer->tablerow_close(); 22729877279SMichael Große } 22829877279SMichael Große } 22929877279SMichael Große 23029877279SMichael Große /** 23129877279SMichael Große * @param $mode 23229877279SMichael Große * @param Doku_Renderer $renderer 23329877279SMichael Große * @param $cur_params 23429877279SMichael Große */ 23529877279SMichael Große protected function showActiveFilters($mode, Doku_Renderer $renderer, $cur_params) { 23629877279SMichael Große global $ID, $INPUT; 23729877279SMichael Große 23829877279SMichael Große if($mode == 'xhtml' && $INPUT->has('dataflt')) { 23929877279SMichael Große $filters = $INPUT->arr('dataflt'); 24029877279SMichael Große $confHelper = $this->loadHelper('struct_config'); 24129877279SMichael Große $fltrs = array(); 24229877279SMichael Große foreach($filters as $colcomp => $filter) { 24329877279SMichael Große $filter = $confHelper->parseFilterLine('', $colcomp.$filter); 24429877279SMichael Große if(strpos($filter[1], '~') !== false) { 24529877279SMichael Große if(strpos($filter[1], '!~') !== false) { 24629877279SMichael Große $comparator_value = '!~' . str_replace('%', '*', $filter[2]); 24729877279SMichael Große } else { 24829877279SMichael Große $comparator_value = '~' . str_replace('%', '', $filter[2]); 24929877279SMichael Große } 25029877279SMichael Große $fltrs[] = $filter[0] . $comparator_value; 25129877279SMichael Große } else { 25229877279SMichael Große $fltrs[] = $filter[0] . $filter[1] . $filter[2]; 25329877279SMichael Große } 25429877279SMichael Große } 25529877279SMichael Große 25629877279SMichael Große $renderer->doc .= '<div class="filter">'; 25729877279SMichael Große $renderer->doc .= '<h4>' . sprintf($this->getLang('tablefilteredby'), hsc(implode(' & ', $fltrs))) . '</h4>'; 25829877279SMichael Große $renderer->doc .= '<div class="resetfilter">'; 25929877279SMichael Große $renderer->internallink($ID, $this->getLang('tableresetfilter')); 26029877279SMichael Große $renderer->doc .= '</div>'; 26129877279SMichael Große $renderer->doc .= '</div>'; 26229877279SMichael Große } 26329877279SMichael Große } 26429877279SMichael Große 26529877279SMichael Große /** 26629877279SMichael Große * @param $mode 26729877279SMichael Große * @param Doku_Renderer $renderer 26829877279SMichael Große * @param $data 26929877279SMichael Große * @param $cur_params 27029877279SMichael Große */ 27129877279SMichael Große protected function addDynamicFilters($mode, Doku_Renderer $renderer, $data, $cur_params) { 27229877279SMichael Große if ($mode != 'xhtml') return; 27329877279SMichael Große 27429877279SMichael Große global $conf, $ID; 27529877279SMichael Große 27629877279SMichael Große $html = ''; 27729877279SMichael Große if($data['dynfilters']) { 27829877279SMichael Große $html .= '<tr class="dataflt">'; 27929877279SMichael Große 28029877279SMichael Große if($data['rownumbers']) { 28129877279SMichael Große $html .= '<th></th>'; 28229877279SMichael Große } 28329877279SMichael Große 28429877279SMichael Große foreach($data['headers'] as $num => $head) { 28529877279SMichael Große $html .= '<th>'; 28629877279SMichael Große $form = new Doku_Form(array('method' => 'GET',)); 28729877279SMichael Große $form->_hidden = array(); 28829877279SMichael Große if(!$conf['userewrite']) { 28929877279SMichael Große $form->addHidden('id', $ID); 29029877279SMichael Große } 29129877279SMichael Große 29229877279SMichael Große $key = 'dataflt[' . $data['cols'][$num] . '~' . ']'; 29329877279SMichael Große $val = isset($cur_params[$key]) ? $cur_params[$key] : ''; 29429877279SMichael Große 29529877279SMichael Große // Add current request params 29629877279SMichael Große foreach($cur_params as $c_key => $c_val) { 29729877279SMichael Große if($c_val !== '' && $c_key !== $key) { 29829877279SMichael Große $form->addHidden($c_key, $c_val); 29929877279SMichael Große } 30029877279SMichael Große } 30129877279SMichael Große 30229877279SMichael Große $form->addElement(form_makeField('text', $key, $val, '')); 30329877279SMichael Große $html .= $form->getForm(); 30429877279SMichael Große $html .= '</th>'; 30529877279SMichael Große } 30629877279SMichael Große $html .= '</tr>'; 30729877279SMichael Große $renderer->doc .= $html; 30829877279SMichael Große } 30929877279SMichael Große } 31029877279SMichael Große 31129877279SMichael Große /** 31229877279SMichael Große * @param $mode 31329877279SMichael Große * @param Doku_Renderer $renderer 31429877279SMichael Große */ 31529877279SMichael Große private function startTable($mode, Doku_Renderer $renderer) { 31629877279SMichael Große $renderer->table_open(); 31729877279SMichael Große } 31829877279SMichael Große 31929877279SMichael Große /** 32029877279SMichael Große * @param $mode 32129877279SMichael Große * @param Doku_Renderer $renderer 32229877279SMichael Große * @param $clist 32329877279SMichael Große * @param $data 32429877279SMichael Große * @param $cur_params 32529877279SMichael Große * 32629877279SMichael Große */ 32729877279SMichael Große protected function buildColumnHeaders($mode, Doku_Renderer $renderer, $clist, $data, $cur_params) { 32829877279SMichael Große global $ID; 32929877279SMichael Große 33029877279SMichael Große $renderer->tablerow_open(); 33129877279SMichael Große 33229877279SMichael Große if($data['rownumbers']) { 33329877279SMichael Große $renderer->tableheader_open(); 33429877279SMichael Große $renderer->cdata('#'); 33529877279SMichael Große $renderer->tableheader_close(); 33629877279SMichael Große } 33729877279SMichael Große 33829877279SMichael Große foreach($data['headers'] as $num => $head) { 33929877279SMichael Große $ckey = $clist[$num]; 34029877279SMichael Große 34129877279SMichael Große $width = ''; 34229877279SMichael Große if(isset($data['widths'][$num]) AND $data['widths'][$num] != '-') { 34329877279SMichael Große $width = ' style="width: ' . $data['widths'][$num] . ';"'; 34429877279SMichael Große } 34529877279SMichael Große if ($mode == 'xhmtl') { 34629877279SMichael Große $renderer->doc .= '<th' . $width . '>'; 34729877279SMichael Große } else { 34829877279SMichael Große $renderer->tableheader_open(); 34929877279SMichael Große } 35029877279SMichael Große 35129877279SMichael Große // add sort arrow 35229877279SMichael Große if ($mode == 'xhtml') { 35329877279SMichael Große if(isset($data['sort']) && $ckey == $data['sort'][0]) { 35429877279SMichael Große if($data['sort'][1] == 'ASC') { 35529877279SMichael Große $renderer->doc .= '<span>↓</span> '; 35629877279SMichael Große $ckey = '^' . $ckey; 35729877279SMichael Große } else { 35829877279SMichael Große $renderer->doc .= '<span>↑</span> '; 35929877279SMichael Große } 36029877279SMichael Große } 36129877279SMichael Große } 36229877279SMichael Große 36329877279SMichael Große // Clickable header for dynamic sorting 36429877279SMichael Große if ($mode == 'xhtml') { 36529877279SMichael Große $renderer->doc .= '<a href="' . wl($ID, array('datasrt' => $ckey,) + $cur_params) . 36629877279SMichael Große '" title="' . $this->getLang('sort') . '">' . hsc($head) . '</a>'; 36729877279SMichael Große } else { 36829877279SMichael Große $renderer->internallink($ID . "?datasrt=$ckey", hsc($head)); 36929877279SMichael Große } 37029877279SMichael Große $renderer->tableheader_close(); 37129877279SMichael Große } 37229877279SMichael Große $renderer->tablerow_close(); 37329877279SMichael Große } 37429877279SMichael Große 37529877279SMichael Große 37629877279SMichael Große protected function startScope($mode, \Doku_Renderer $renderer) { 37729877279SMichael Große if ($mode == 'xhtml') { 37829877279SMichael Große $renderer->doc .= '<div class="table structaggegation">'; 37929877279SMichael Große } 38029877279SMichael Große } 38129877279SMichael Große 38229877279SMichael Große /** 38329877279SMichael Große * if summarize was set, add sums 38429877279SMichael Große * 38529877279SMichael Große * @param $mode 38629877279SMichael Große * @param Doku_Renderer $renderer 38729877279SMichael Große * @param $data 38829877279SMichael Große * @param $sums 38929877279SMichael Große */ 39029877279SMichael Große private function summarize($mode, \Doku_Renderer $renderer, $data, $sums) { 39129877279SMichael Große if($data['summarize']) { 39229877279SMichael Große $renderer->tablerow_open(); 39329877279SMichael Große $len = count($data['cols']); 39429877279SMichael Große 39529877279SMichael Große if($data['rownumbers']) { 39629877279SMichael Große $renderer->tablecell_open(); 39729877279SMichael Große $renderer->tablecell_close(); 39829877279SMichael Große } 39929877279SMichael Große 40029877279SMichael Große for($i = 0; $i < $len; $i++) { 40129877279SMichael Große $renderer->tablecell_open(1, $data['align'][$i]); 40229877279SMichael Große if(!empty($sums[$i])) { 40329877279SMichael Große $renderer->cdata('∑ ' . $sums[$i]); 40429877279SMichael Große } else { 40529877279SMichael Große if ($mode == 'xhtml') { 40629877279SMichael Große $renderer->doc .= ' '; 40729877279SMichael Große } 40829877279SMichael Große } 40929877279SMichael Große $renderer->tablecell_close(); 41029877279SMichael Große } 41129877279SMichael Große $renderer->tablerow_close(); 41229877279SMichael Große } 41329877279SMichael Große } 41429877279SMichael Große 41529877279SMichael Große /** 41629877279SMichael Große * @param $mode 41729877279SMichael Große * @param Doku_Renderer $renderer 41829877279SMichael Große * 41929877279SMichael Große */ 42029877279SMichael Große private function finishTableAndScope($mode, Doku_Renderer $renderer) { 42129877279SMichael Große $renderer->table_close(); 42229877279SMichael Große if ($mode == 'xhmtl') { 42329877279SMichael Große $renderer->doc .= '</div>'; 42429877279SMichael Große } 42529877279SMichael Große } 42629877279SMichael Große 42729877279SMichael Große /** 42829877279SMichael Große * @param $mode 42929877279SMichael Große * @param Doku_Renderer $renderer 43029877279SMichael Große * @param $data 43129877279SMichael Große * @param $rows 43229877279SMichael Große * 43329877279SMichael Große */ 43429877279SMichael Große private function renderRows($mode, Doku_Renderer $renderer, $data, $rows) { 43529877279SMichael Große $renderer->tabletbody_open(); 43629877279SMichael Große foreach($rows as $rownum => $row) { 43729877279SMichael Große $renderer->tablerow_open(); 43829877279SMichael Große 43929877279SMichael Große if($data['rownumbers']) { 44029877279SMichael Große $renderer->tablecell_open(); 44129877279SMichael Große $renderer->doc .= $rownum + 1; 44229877279SMichael Große $renderer->tablecell_close(); 44329877279SMichael Große } 44429877279SMichael Große 44529877279SMichael Große /** @var plugin\struct\meta\Value $value */ 44629877279SMichael Große foreach($row as $colnum => $value) { 44729877279SMichael Große $renderer->tablecell_open(); 44829877279SMichael Große $value->render($renderer, $mode); 44929877279SMichael Große $renderer->tablecell_close(); 45029877279SMichael Große 45129877279SMichael Große // summarize 45229877279SMichael Große if($data['summarize'] && is_numeric($value->getValue())) { 45329877279SMichael Große if(!isset($this->sums[$colnum])) { 45429877279SMichael Große $this->sums[$colnum] = 0; 45529877279SMichael Große } 45629877279SMichael Große $this->sums[$colnum] += $value->getValue(); 45729877279SMichael Große } 45829877279SMichael Große } 45929877279SMichael Große $renderer->tablerow_close(); 46029877279SMichael Große } 46129877279SMichael Große $renderer->tabletbody_close(); 46229877279SMichael Große } 463549a0837SAndreas Gohr} 464549a0837SAndreas Gohr 465549a0837SAndreas Gohr// vim:ts=4:sw=4:et: 466