107993756SAndreas Gohr<?php 207993756SAndreas Gohr 3ba766201SAndreas Gohrnamespace dokuwiki\plugin\struct\meta; 407993756SAndreas Gohr 5d60f71efSAndreas Gohr/** 6d60f71efSAndreas Gohr * Creates the table aggregation output 7d60f71efSAndreas Gohr * 8ba766201SAndreas Gohr * @package dokuwiki\plugin\struct\meta 9d60f71efSAndreas Gohr */ 10d6d97f60SAnna Dabrowskaclass AggregationTable 11d6d97f60SAnna Dabrowska{ 1207993756SAndreas Gohr /** 1307993756SAndreas Gohr * @var string the page id of the page this is rendered to 1407993756SAndreas Gohr */ 1507993756SAndreas Gohr protected $id; 1607993756SAndreas Gohr /** 1707993756SAndreas Gohr * @var string the Type of renderer used 1807993756SAndreas Gohr */ 1907993756SAndreas Gohr protected $mode; 2007993756SAndreas Gohr /** 2107993756SAndreas Gohr * @var \Doku_Renderer the DokuWiki renderer used to create the output 2207993756SAndreas Gohr */ 2307993756SAndreas Gohr protected $renderer; 2407993756SAndreas Gohr /** 2507993756SAndreas Gohr * @var SearchConfig the configured search - gives access to columns etc. 2607993756SAndreas Gohr */ 2707993756SAndreas Gohr protected $searchConfig; 2807993756SAndreas Gohr 2907993756SAndreas Gohr /** 3007993756SAndreas Gohr * @var Column[] the list of columns to be displayed 3107993756SAndreas Gohr */ 3207993756SAndreas Gohr protected $columns; 3307993756SAndreas Gohr 3407993756SAndreas Gohr /** 3507993756SAndreas Gohr * @var Value[][] the search result 3607993756SAndreas Gohr */ 3707993756SAndreas Gohr protected $result; 3807993756SAndreas Gohr 3907993756SAndreas Gohr /** 4007993756SAndreas Gohr * @var int number of all results 4107993756SAndreas Gohr */ 4207993756SAndreas Gohr protected $resultCount; 4307993756SAndreas Gohr 4407993756SAndreas Gohr /** 45d4b5a17cSAndreas Gohr * @var string[] the result PIDs for each row 46d4b5a17cSAndreas Gohr */ 47d4b5a17cSAndreas Gohr protected $resultPIDs; 480ceefd5cSAnna Dabrowska protected $resultRids; 496fd73b4bSAnna Dabrowska protected $resultRevs; 50d4b5a17cSAndreas Gohr 51d4b5a17cSAndreas Gohr /** 5207993756SAndreas Gohr * @var array for summing up columns 5307993756SAndreas Gohr */ 5407993756SAndreas Gohr protected $sums; 5507993756SAndreas Gohr 5607993756SAndreas Gohr /** 576b5e52fdSAndreas Gohr * @var bool skip full table when no results found 586b5e52fdSAndreas Gohr */ 596b5e52fdSAndreas Gohr protected $simplenone = true; 606b5e52fdSAndreas Gohr 616b5e52fdSAndreas Gohr /** 6207993756SAndreas Gohr * @todo we might be able to get rid of this helper and move this to SearchConfig 6307993756SAndreas Gohr * @var \helper_plugin_struct_config 6407993756SAndreas Gohr */ 6507993756SAndreas Gohr protected $helper; 6607993756SAndreas Gohr 6707993756SAndreas Gohr /** 6807993756SAndreas Gohr * Initialize the Aggregation renderer and executes the search 6907993756SAndreas Gohr * 700549dcc5SAndreas Gohr * You need to call @param string $id 7107993756SAndreas Gohr * @param string $mode 7207993756SAndreas Gohr * @param \Doku_Renderer $renderer 7307993756SAndreas Gohr * @param SearchConfig $searchConfig 740549dcc5SAndreas Gohr * @see render() on the resulting object. 750549dcc5SAndreas Gohr * 7607993756SAndreas Gohr */ 778ce43f5aSAnna Dabrowska public function __construct($id, $mode, \Doku_Renderer $renderer, SearchConfig $searchConfig) 78d6d97f60SAnna Dabrowska { 7907993756SAndreas Gohr $this->id = $id; 8007993756SAndreas Gohr $this->mode = $mode; 8107993756SAndreas Gohr $this->renderer = $renderer; 8207993756SAndreas Gohr $this->searchConfig = $searchConfig; 8307993756SAndreas Gohr $this->data = $searchConfig->getConf(); 8407993756SAndreas Gohr $this->columns = $searchConfig->getColumns(); 8507993756SAndreas Gohr 868ce43f5aSAnna Dabrowska $this->result = $this->searchConfig->execute(); 8707993756SAndreas Gohr $this->resultCount = $this->searchConfig->getCount(); 88d4b5a17cSAndreas Gohr $this->resultPIDs = $this->searchConfig->getPids(); 890ceefd5cSAnna Dabrowska $this->resultRids = $this->searchConfig->getRids(); 906fd73b4bSAnna Dabrowska $this->resultRevs = $this->searchConfig->getRevs(); 9107993756SAndreas Gohr $this->helper = plugin_load('helper', 'struct_config'); 9207993756SAndreas Gohr } 9307993756SAndreas Gohr 9407993756SAndreas Gohr /** 95844a4f01SFrieder Schrempf * Returns the page id for the table 96844a4f01SFrieder Schrempf */ 97844a4f01SFrieder Schrempf public function getID() 98844a4f01SFrieder Schrempf { 99844a4f01SFrieder Schrempf return $this->id; 100844a4f01SFrieder Schrempf } 101844a4f01SFrieder Schrempf 102844a4f01SFrieder Schrempf /** 10307993756SAndreas Gohr * Create the table on the renderer 10407993756SAndreas Gohr */ 105d6d97f60SAnna Dabrowska public function render() 106d6d97f60SAnna Dabrowska { 107b7e1d73bSAndreas Gohr 108b7e1d73bSAndreas Gohr // abort early if there are no results at all (not filtered) 1096b5e52fdSAndreas Gohr if (!$this->resultCount && !$this->isDynamicallyFiltered() && $this->simplenone) { 110b7e1d73bSAndreas Gohr $this->startScope(); 111b7e1d73bSAndreas Gohr $this->renderer->cdata($this->helper->getLang('none')); 112b7e1d73bSAndreas Gohr $this->finishScope(); 113b7e1d73bSAndreas Gohr return; 114b7e1d73bSAndreas Gohr } 115b7e1d73bSAndreas Gohr 11607993756SAndreas Gohr $this->startScope(); 117986ab7e6SAndreas Gohr $this->renderActiveFilters(); 118844a4f01SFrieder Schrempf 119844a4f01SFrieder Schrempf $rendercontext = array( 120844a4f01SFrieder Schrempf 'table' => $this, 121844a4f01SFrieder Schrempf 'renderer' => $this->renderer, 1223f640228SFrieder Schrempf 'format' => $this->mode, 123844a4f01SFrieder Schrempf 'search' => $this->searchConfig, 124844a4f01SFrieder Schrempf 'columns' => $this->columns, 125844a4f01SFrieder Schrempf 'data' => $this->result 126844a4f01SFrieder Schrempf ); 127844a4f01SFrieder Schrempf 1282dbe71f8SAnna Dabrowska $event = new \Doku_Event( 129844a4f01SFrieder Schrempf 'PLUGIN_STRUCT_RENDER_AGGREGATION_TABLE', 1302dbe71f8SAnna Dabrowska $rendercontext 131844a4f01SFrieder Schrempf ); 1322dbe71f8SAnna Dabrowska $event->trigger([$this, 'renderTable']); 133844a4f01SFrieder Schrempf 134844a4f01SFrieder Schrempf // export handle 135844a4f01SFrieder Schrempf $this->renderExportControls(); 136844a4f01SFrieder Schrempf $this->finishScope(); 137844a4f01SFrieder Schrempf } 138844a4f01SFrieder Schrempf 139844a4f01SFrieder Schrempf /** 140844a4f01SFrieder Schrempf * Render the default aggregation table 141844a4f01SFrieder Schrempf */ 142844a4f01SFrieder Schrempf public function renderTable($rendercontext) 143844a4f01SFrieder Schrempf { 14407993756SAndreas Gohr $this->renderer->table_open(); 14507993756SAndreas Gohr 14607993756SAndreas Gohr // header 14707993756SAndreas Gohr $this->renderer->tablethead_open(); 148986ab7e6SAndreas Gohr $this->renderColumnHeaders(); 149986ab7e6SAndreas Gohr $this->renderDynamicFilters(); 15007993756SAndreas Gohr $this->renderer->tablethead_close(); 15107993756SAndreas Gohr 15207993756SAndreas Gohr if ($this->resultCount) { 15307993756SAndreas Gohr // actual data 154a9fd81f9SAndreas Gohr $this->renderer->tabletbody_open(); 155986ab7e6SAndreas Gohr $this->renderResult(); 156a9fd81f9SAndreas Gohr $this->renderer->tabletbody_close(); 15707993756SAndreas Gohr 158a9fd81f9SAndreas Gohr // footer (tfoot is develonly currently) 159a9fd81f9SAndreas Gohr if (method_exists($this->renderer, 'tabletfoot_open')) $this->renderer->tabletfoot_open(); 160986ab7e6SAndreas Gohr $this->renderSums(); 161986ab7e6SAndreas Gohr $this->renderPagingControls(); 162a9fd81f9SAndreas Gohr if (method_exists($this->renderer, 'tabletfoot_close')) $this->renderer->tabletfoot_close(); 16307993756SAndreas Gohr } else { 16407993756SAndreas Gohr // nothing found 165986ab7e6SAndreas Gohr $this->renderEmptyResult(); 16607993756SAndreas Gohr } 16707993756SAndreas Gohr 16807993756SAndreas Gohr // table close 16907993756SAndreas Gohr $this->renderer->table_close(); 17007993756SAndreas Gohr } 17107993756SAndreas Gohr 17207993756SAndreas Gohr /** 17307993756SAndreas Gohr * Adds additional info to document and renderer in XHTML mode 17407993756SAndreas Gohr * 17507993756SAndreas Gohr * @see finishScope() 17607993756SAndreas Gohr */ 177d6d97f60SAnna Dabrowska protected function startScope() 178d6d97f60SAnna Dabrowska { 17907993756SAndreas Gohr // unique identifier for this aggregation 18007993756SAndreas Gohr $this->renderer->info['struct_table_hash'] = md5(var_export($this->data, true)); 18109dd691aSAndreas Gohr 18209dd691aSAndreas Gohr // wrapping div 18309dd691aSAndreas Gohr if ($this->mode != 'xhtml') return; 18409dd691aSAndreas Gohr $this->renderer->doc .= "<div class=\"structaggregation\">"; 18507993756SAndreas Gohr } 18607993756SAndreas Gohr 18707993756SAndreas Gohr /** 18807993756SAndreas Gohr * Closes the table and anything opened in startScope() 18907993756SAndreas Gohr * 19007993756SAndreas Gohr * @see startScope() 19107993756SAndreas Gohr */ 192d6d97f60SAnna Dabrowska protected function finishScope() 193d6d97f60SAnna Dabrowska { 19407993756SAndreas Gohr // remove identifier from renderer again 19507993756SAndreas Gohr if (isset($this->renderer->info['struct_table_hash'])) { 19607993756SAndreas Gohr unset($this->renderer->info['struct_table_hash']); 19707993756SAndreas Gohr } 19809dd691aSAndreas Gohr 19909dd691aSAndreas Gohr // wrapping div 20009dd691aSAndreas Gohr if ($this->mode != 'xhtml') return; 20109dd691aSAndreas Gohr $this->renderer->doc .= '</div>'; 20207993756SAndreas Gohr } 20307993756SAndreas Gohr 20407993756SAndreas Gohr /** 20507993756SAndreas Gohr * Displays info about the currently applied filters 20607993756SAndreas Gohr */ 207d6d97f60SAnna Dabrowska protected function renderActiveFilters() 208d6d97f60SAnna Dabrowska { 20907993756SAndreas Gohr if ($this->mode != 'xhtml') return; 21007993756SAndreas Gohr $dynamic = $this->searchConfig->getDynamicParameters(); 21107993756SAndreas Gohr $filters = $dynamic->getFilters(); 21207993756SAndreas Gohr if (!$filters) return; 21307993756SAndreas Gohr 21407993756SAndreas Gohr $fltrs = array(); 21507993756SAndreas Gohr foreach ($filters as $column => $filter) { 21607993756SAndreas Gohr list($comp, $value) = $filter; 21704ec4785SAnna Dabrowska 21804ec4785SAnna Dabrowska // display the filters in a human readable format 21904ec4785SAnna Dabrowska foreach ($this->columns as $col) { 22004ec4785SAnna Dabrowska if ($column === $col->getFullQualifiedLabel()) { 22104ec4785SAnna Dabrowska $column = $col->getTranslatedLabel(); 22204ec4785SAnna Dabrowska } 22304ec4785SAnna Dabrowska } 2241f075418SAnna Dabrowska $fltrs[] = sprintf('"%s" %s "%s"', $column, $this->helper->getLang("comparator $comp"), $value); 22507993756SAndreas Gohr } 22607993756SAndreas Gohr 22707993756SAndreas Gohr $this->renderer->doc .= '<div class="filter">'; 228*17a3a578SAndreas Gohr $this->renderer->doc .= '<h4>' . 229*17a3a578SAndreas Gohr sprintf( 230*17a3a578SAndreas Gohr $this->helper->getLang('tablefilteredby'), 231*17a3a578SAndreas Gohr hsc(implode(' & ', $fltrs)) 232*17a3a578SAndreas Gohr ) . 233*17a3a578SAndreas Gohr '</h4>'; 23407993756SAndreas Gohr $this->renderer->doc .= '<div class="resetfilter">'; 23507993756SAndreas Gohr $this->renderer->internallink($this->id, $this->helper->getLang('tableresetfilter')); 23607993756SAndreas Gohr $this->renderer->doc .= '</div>'; 23707993756SAndreas Gohr $this->renderer->doc .= '</div>'; 23807993756SAndreas Gohr } 23907993756SAndreas Gohr 24007993756SAndreas Gohr /** 24107993756SAndreas Gohr * Shows the column headers with links to sort by column 24207993756SAndreas Gohr */ 243d6d97f60SAnna Dabrowska protected function renderColumnHeaders() 244d6d97f60SAnna Dabrowska { 24507993756SAndreas Gohr $this->renderer->tablerow_open(); 24607993756SAndreas Gohr 24707993756SAndreas Gohr // additional column for row numbers 24834ea6e10SAnna Dabrowska if (!empty($this->data['rownumbers'])) { 24907993756SAndreas Gohr $this->renderer->tableheader_open(); 25007993756SAndreas Gohr $this->renderer->cdata('#'); 25107993756SAndreas Gohr $this->renderer->tableheader_close(); 25207993756SAndreas Gohr } 25307993756SAndreas Gohr 25407993756SAndreas Gohr // show all headers 2558c4ee9beSAndreas Gohr foreach ($this->columns as $num => $column) { 2568c4ee9beSAndreas Gohr $header = ''; 2578c4ee9beSAndreas Gohr if (isset($this->data['headers'][$num])) { 2588c4ee9beSAndreas Gohr $header = $this->data['headers'][$num]; 2598c4ee9beSAndreas Gohr } 26007993756SAndreas Gohr 26107993756SAndreas Gohr // use field label if no header was set 26207993756SAndreas Gohr if (blank($header)) { 26301f8b845SAndreas Gohr if (is_a($column, 'dokuwiki\plugin\struct\meta\Column')) { 26407993756SAndreas Gohr $header = $column->getTranslatedLabel(); 26507993756SAndreas Gohr } else { 26607993756SAndreas Gohr $header = 'column ' . $num; // this should never happen 26707993756SAndreas Gohr } 26807993756SAndreas Gohr } 26907993756SAndreas Gohr 27007993756SAndreas Gohr // simple mode first 27107993756SAndreas Gohr if ($this->mode != 'xhtml') { 27207993756SAndreas Gohr $this->renderer->tableheader_open(); 27307993756SAndreas Gohr $this->renderer->cdata($header); 27407993756SAndreas Gohr $this->renderer->tableheader_close(); 27507993756SAndreas Gohr continue; 27607993756SAndreas Gohr } 27707993756SAndreas Gohr 27807993756SAndreas Gohr // still here? create custom header for more flexibility 27907993756SAndreas Gohr 2809113d04aSAndreas Gohr // width setting, widths are prevalidated, no escape needed 28107993756SAndreas Gohr $width = ''; 2829113d04aSAndreas Gohr if (isset($this->data['widths'][$num]) && $this->data['widths'][$num] != '-') { 2839113d04aSAndreas Gohr $width = ' style="min-width: ' . $this->data['widths'][$num] . ';' . 2849113d04aSAndreas Gohr 'max-width: ' . $this->data['widths'][$num] . ';"'; 28507993756SAndreas Gohr } 28607993756SAndreas Gohr 287d4b5a17cSAndreas Gohr // prepare data attribute for inline edits 288d6d97f60SAnna Dabrowska if ( 289d6d97f60SAnna Dabrowska !is_a($column, '\dokuwiki\plugin\struct\meta\PageColumn') && 290d4b5a17cSAndreas Gohr !is_a($column, '\dokuwiki\plugin\struct\meta\RevisionColumn') 291d4b5a17cSAndreas Gohr ) { 292d4b5a17cSAndreas Gohr $data = 'data-field="' . hsc($column->getFullQualifiedLabel()) . '"'; 293d4b5a17cSAndreas Gohr } else { 294d4b5a17cSAndreas Gohr $data = ''; 295d4b5a17cSAndreas Gohr } 296d4b5a17cSAndreas Gohr 29707993756SAndreas Gohr // sort indicator and link 29807993756SAndreas Gohr $sortclass = ''; 29907993756SAndreas Gohr $sorts = $this->searchConfig->getSorts(); 30007993756SAndreas Gohr $dynamic = $this->searchConfig->getDynamicParameters(); 301aa124708SAndreas Gohr $dynamic->setSort($column, true); 30207993756SAndreas Gohr if (isset($sorts[$column->getFullQualifiedLabel()])) { 303aa124708SAndreas Gohr list(/*colname*/, $currentSort) = $sorts[$column->getFullQualifiedLabel()]; 304aa124708SAndreas Gohr if ($currentSort) { 30507993756SAndreas Gohr $sortclass = 'sort-down'; 30607993756SAndreas Gohr $dynamic->setSort($column, false); 30707993756SAndreas Gohr } else { 30807993756SAndreas Gohr $sortclass = 'sort-up'; 30907993756SAndreas Gohr } 31007993756SAndreas Gohr } 31107993756SAndreas Gohr $link = wl($this->id, $dynamic->getURLParameters()); 31207993756SAndreas Gohr 31307993756SAndreas Gohr // output XHTML header 314d4b5a17cSAndreas Gohr $this->renderer->doc .= "<th $width $data>"; 315*17a3a578SAndreas Gohr $this->renderer->doc .= '<a href="' . $link . '" class="' . $sortclass . '" ' . 316*17a3a578SAndreas Gohr 'title="' . $this->helper->getLang('sort') . '">' . hsc($header) . '</a>'; 31707993756SAndreas Gohr $this->renderer->doc .= '</th>'; 31807993756SAndreas Gohr } 31907993756SAndreas Gohr 32007993756SAndreas Gohr $this->renderer->tablerow_close(); 32107993756SAndreas Gohr } 32207993756SAndreas Gohr 32307993756SAndreas Gohr /** 324b7e1d73bSAndreas Gohr * Is the result set currently dynamically filtered? 325b7e1d73bSAndreas Gohr * @return bool 326b7e1d73bSAndreas Gohr */ 327d6d97f60SAnna Dabrowska protected function isDynamicallyFiltered() 328d6d97f60SAnna Dabrowska { 329b7e1d73bSAndreas Gohr if ($this->mode != 'xhtml') return false; 330b7e1d73bSAndreas Gohr if (!$this->data['dynfilters']) return false; 331b7e1d73bSAndreas Gohr 332b7e1d73bSAndreas Gohr $dynamic = $this->searchConfig->getDynamicParameters(); 333b7e1d73bSAndreas Gohr return (bool)$dynamic->getFilters(); 334b7e1d73bSAndreas Gohr } 335b7e1d73bSAndreas Gohr 336b7e1d73bSAndreas Gohr /** 33707993756SAndreas Gohr * Add input fields for dynamic filtering 33807993756SAndreas Gohr */ 339d6d97f60SAnna Dabrowska protected function renderDynamicFilters() 340d6d97f60SAnna Dabrowska { 34107993756SAndreas Gohr if ($this->mode != 'xhtml') return; 34207993756SAndreas Gohr if (!$this->data['dynfilters']) return; 3431bc467a4SMichael Grosse if (is_a($this->renderer, 'renderer_plugin_dw2pdf')) { 344e6ae02ecSMichael Grosse return; 345e6ae02ecSMichael Grosse } 3461bc467a4SMichael Grosse global $conf; 34707993756SAndreas Gohr 34807993756SAndreas Gohr $this->renderer->doc .= '<tr class="dataflt">'; 34907993756SAndreas Gohr 35007993756SAndreas Gohr // add extra column for row numbers 35107993756SAndreas Gohr if ($this->data['rownumbers']) { 35207993756SAndreas Gohr $this->renderer->doc .= '<th></th>'; 35307993756SAndreas Gohr } 35407993756SAndreas Gohr 35507993756SAndreas Gohr // each column gets a form 35607993756SAndreas Gohr foreach ($this->columns as $column) { 35707993756SAndreas Gohr $this->renderer->doc .= '<th>'; 358*17a3a578SAndreas Gohr 359*17a3a578SAndreas Gohr // BEGIN FORM 36007993756SAndreas Gohr $form = new \Doku_Form(array('method' => 'GET', 'action' => wl($this->id))); 36176195677SAndreas Gohr unset($form->_hidden['sectok']); // we don't need it here 36276195677SAndreas Gohr if (!$conf['userewrite']) $form->addHidden('id', $this->id); 36307993756SAndreas Gohr 36407993756SAndreas Gohr // current value 36507993756SAndreas Gohr $dynamic = $this->searchConfig->getDynamicParameters(); 36607993756SAndreas Gohr $filters = $dynamic->getFilters(); 36707993756SAndreas Gohr if (isset($filters[$column->getFullQualifiedLabel()])) { 36807993756SAndreas Gohr list(, $current) = $filters[$column->getFullQualifiedLabel()]; 36907993756SAndreas Gohr $dynamic->removeFilter($column); 37007993756SAndreas Gohr } else { 37107993756SAndreas Gohr $current = ''; 37207993756SAndreas Gohr } 37307993756SAndreas Gohr 37407993756SAndreas Gohr // Add current request params 37507993756SAndreas Gohr $params = $dynamic->getURLParameters(); 37607993756SAndreas Gohr foreach ($params as $key => $val) { 37707993756SAndreas Gohr $form->addHidden($key, $val); 37807993756SAndreas Gohr } 37907993756SAndreas Gohr 38007993756SAndreas Gohr // add input field 381db9b8745SAndreas Gohr $key = $column->getFullQualifiedLabel() . $column->getType()->getDefaultComparator(); 382*17a3a578SAndreas Gohr $form->addElement( 383*17a3a578SAndreas Gohr form_makeField('text', SearchConfigParameters::$PARAM_FILTER . '[' . $key . ']', $current, '') 384*17a3a578SAndreas Gohr ); 38507993756SAndreas Gohr $this->renderer->doc .= $form->getForm(); 386*17a3a578SAndreas Gohr // END FORM 387*17a3a578SAndreas Gohr 38807993756SAndreas Gohr $this->renderer->doc .= '</th>'; 38907993756SAndreas Gohr } 39007993756SAndreas Gohr $this->renderer->doc .= '</tr>'; 39107993756SAndreas Gohr } 39207993756SAndreas Gohr 39307993756SAndreas Gohr /** 39407993756SAndreas Gohr * Display the actual table data 39507993756SAndreas Gohr */ 396d6d97f60SAnna Dabrowska protected function renderResult() 397d6d97f60SAnna Dabrowska { 39807993756SAndreas Gohr foreach ($this->result as $rownum => $row) { 39947eb8cceSSzymon Olewniczak $data = array( 40047eb8cceSSzymon Olewniczak 'id' => $this->id, 40147eb8cceSSzymon Olewniczak 'mode' => $this->mode, 40247eb8cceSSzymon Olewniczak 'renderer' => $this->renderer, 40347eb8cceSSzymon Olewniczak 'searchConfig' => $this->searchConfig, 40447eb8cceSSzymon Olewniczak 'data' => $this->data, 40547eb8cceSSzymon Olewniczak 'rownum' => &$rownum, 40647eb8cceSSzymon Olewniczak 'row' => &$row, 40747eb8cceSSzymon Olewniczak ); 40847eb8cceSSzymon Olewniczak $evt = new \Doku_Event('PLUGIN_STRUCT_AGGREGATIONTABLE_RENDERRESULTROW', $data); 40947eb8cceSSzymon Olewniczak if ($evt->advise_before()) { 410f107f479SAndreas Gohr $this->renderResultRow($rownum, $row); 411f107f479SAndreas Gohr } 41247eb8cceSSzymon Olewniczak $evt->advise_after(); 41347eb8cceSSzymon Olewniczak } 414f107f479SAndreas Gohr } 415f107f479SAndreas Gohr 416f107f479SAndreas Gohr /** 417f107f479SAndreas Gohr * Render a single result row 418f107f479SAndreas Gohr * 419f107f479SAndreas Gohr * @param int $rownum 420f107f479SAndreas Gohr * @param array $row 421f107f479SAndreas Gohr */ 422d6d97f60SAnna Dabrowska protected function renderResultRow($rownum, $row) 423d6d97f60SAnna Dabrowska { 42407993756SAndreas Gohr $this->renderer->tablerow_open(); 42507993756SAndreas Gohr 426d4b5a17cSAndreas Gohr // add data attribute for inline edit 427d4b5a17cSAndreas Gohr if ($this->mode == 'xhtml') { 428d4b5a17cSAndreas Gohr $pid = $this->resultPIDs[$rownum]; 4290ceefd5cSAnna Dabrowska $rid = $this->resultRids[$rownum]; 4306fd73b4bSAnna Dabrowska $rev = $this->resultRevs[$rownum]; 431d4b5a17cSAndreas Gohr $this->renderer->doc = substr(rtrim($this->renderer->doc), 0, -1); // remove closing '>' 4326fd73b4bSAnna Dabrowska $this->renderer->doc .= ' data-pid="' . hsc($pid) . '" data-rev="' . $rev . '" data-rid="' . $rid . '">'; 433d4b5a17cSAndreas Gohr } 434d4b5a17cSAndreas Gohr 43507993756SAndreas Gohr // row number column 43634ea6e10SAnna Dabrowska if (!empty($this->data['rownumbers'])) { 43707993756SAndreas Gohr $this->renderer->tablecell_open(); 4383215aebfSSzymon Olewniczak $searchConfigConf = $this->searchConfig->getConf(); 4393215aebfSSzymon Olewniczak $this->renderer->cdata($rownum + $searchConfigConf['offset'] + 1); 44007993756SAndreas Gohr $this->renderer->tablecell_close(); 44107993756SAndreas Gohr } 44207993756SAndreas Gohr 44307993756SAndreas Gohr /** @var Value $value */ 44407993756SAndreas Gohr foreach ($row as $colnum => $value) { 44534ea6e10SAnna Dabrowska $align = isset($this->data['align'][$colnum]) ? $this->data['align'][$colnum] : null; 44634ea6e10SAnna Dabrowska $this->renderer->tablecell_open(1, $align); 44707993756SAndreas Gohr $value->render($this->renderer, $this->mode); 44807993756SAndreas Gohr $this->renderer->tablecell_close(); 44907993756SAndreas Gohr 45007993756SAndreas Gohr // summarize 45107993756SAndreas Gohr if ($this->data['summarize'] && is_numeric($value->getValue())) { 45207993756SAndreas Gohr if (!isset($this->sums[$colnum])) { 45307993756SAndreas Gohr $this->sums[$colnum] = 0; 45407993756SAndreas Gohr } 45507993756SAndreas Gohr $this->sums[$colnum] += $value->getValue(); 45607993756SAndreas Gohr } 45707993756SAndreas Gohr } 45807993756SAndreas Gohr $this->renderer->tablerow_close(); 45907993756SAndreas Gohr } 46007993756SAndreas Gohr 46107993756SAndreas Gohr /** 46207993756SAndreas Gohr * Renders an information row for when no results were found 46307993756SAndreas Gohr */ 464d6d97f60SAnna Dabrowska protected function renderEmptyResult() 465d6d97f60SAnna Dabrowska { 46607993756SAndreas Gohr $this->renderer->tablerow_open(); 46770cf6339SAndreas Gohr $this->renderer->tablecell_open(count($this->columns) + $this->data['rownumbers'], 'center'); 46807993756SAndreas Gohr $this->renderer->cdata($this->helper->getLang('none')); 46907993756SAndreas Gohr $this->renderer->tablecell_close(); 47007993756SAndreas Gohr $this->renderer->tablerow_close(); 47107993756SAndreas Gohr } 47207993756SAndreas Gohr 47307993756SAndreas Gohr /** 47407993756SAndreas Gohr * Add sums if wanted 47507993756SAndreas Gohr */ 476d6d97f60SAnna Dabrowska protected function renderSums() 477d6d97f60SAnna Dabrowska { 478d18090e8SAndreas Gohr if (empty($this->data['summarize'])) return; 47907993756SAndreas Gohr 480a0bf8bb2SAndreas Gohr $this->renderer->info['struct_table_meta'] = true; 4818925ba29SAndreas Gohr if ($this->mode == 'xhtml') { 4828925ba29SAndreas Gohr /** @noinspection PhpMethodParametersCountMismatchInspection */ 4838925ba29SAndreas Gohr $this->renderer->tablerow_open('summarize'); 4848925ba29SAndreas Gohr } else { 48507993756SAndreas Gohr $this->renderer->tablerow_open(); 4868925ba29SAndreas Gohr } 48707993756SAndreas Gohr 48807993756SAndreas Gohr if ($this->data['rownumbers']) { 4898925ba29SAndreas Gohr $this->renderer->tableheader_open(); 4908925ba29SAndreas Gohr $this->renderer->tableheader_close(); 49107993756SAndreas Gohr } 49207993756SAndreas Gohr 493aee4116bSAndreas Gohr $len = count($this->columns); 49407993756SAndreas Gohr for ($i = 0; $i < $len; $i++) { 4958925ba29SAndreas Gohr $this->renderer->tableheader_open(1, $this->data['align'][$i]); 496aee4116bSAndreas Gohr if (!empty($this->sums[$i])) { 4979b97e610SAndreas Gohr $this->renderer->cdata('∑ '); 4989b97e610SAndreas Gohr $this->columns[$i]->getType()->renderValue($this->sums[$i], $this->renderer, $this->mode); 49907993756SAndreas Gohr } else { 50007993756SAndreas Gohr if ($this->mode == 'xhtml') { 50107993756SAndreas Gohr $this->renderer->doc .= ' '; 50207993756SAndreas Gohr } 50307993756SAndreas Gohr } 5048925ba29SAndreas Gohr $this->renderer->tableheader_close(); 50507993756SAndreas Gohr } 50607993756SAndreas Gohr $this->renderer->tablerow_close(); 507a0bf8bb2SAndreas Gohr $this->renderer->info['struct_table_meta'] = false; 50807993756SAndreas Gohr } 50907993756SAndreas Gohr 51007993756SAndreas Gohr /** 511986ab7e6SAndreas Gohr * Adds paging controls to the table 51207993756SAndreas Gohr */ 513d6d97f60SAnna Dabrowska protected function renderPagingControls() 514d6d97f60SAnna Dabrowska { 51507993756SAndreas Gohr if (empty($this->data['limit'])) return; 516a0bf8bb2SAndreas Gohr if ($this->mode != 'xhtml') return; 51707993756SAndreas Gohr 518a0bf8bb2SAndreas Gohr $this->renderer->info['struct_table_meta'] = true; 51907993756SAndreas Gohr $this->renderer->tablerow_open(); 5204bc1074dSMichael Grosse $this->renderer->tableheader_open((count($this->columns) + ($this->data['rownumbers'] ? 1 : 0))); 52107993756SAndreas Gohr $offset = $this->data['offset']; 52207993756SAndreas Gohr 52307993756SAndreas Gohr // prev link 52407993756SAndreas Gohr if ($offset) { 52507993756SAndreas Gohr $prev = $offset - $this->data['limit']; 52607993756SAndreas Gohr if ($prev < 0) { 52707993756SAndreas Gohr $prev = 0; 52807993756SAndreas Gohr } 52907993756SAndreas Gohr 53007993756SAndreas Gohr $dynamic = $this->searchConfig->getDynamicParameters(); 53107993756SAndreas Gohr $dynamic->setOffset($prev); 53207993756SAndreas Gohr $link = wl($this->id, $dynamic->getURLParameters()); 53307993756SAndreas Gohr $this->renderer->doc .= '<a href="' . $link . '" class="prev">' . $this->helper->getLang('prev') . '</a>'; 53407993756SAndreas Gohr } 53507993756SAndreas Gohr 53607993756SAndreas Gohr // next link 53707993756SAndreas Gohr if ($this->resultCount > $offset + $this->data['limit']) { 53807993756SAndreas Gohr $next = $offset + $this->data['limit']; 53907993756SAndreas Gohr $dynamic = $this->searchConfig->getDynamicParameters(); 54007993756SAndreas Gohr $dynamic->setOffset($next); 54107993756SAndreas Gohr $link = wl($this->id, $dynamic->getURLParameters()); 54207993756SAndreas Gohr $this->renderer->doc .= '<a href="' . $link . '" class="next">' . $this->helper->getLang('next') . '</a>'; 54307993756SAndreas Gohr } 54407993756SAndreas Gohr 54507993756SAndreas Gohr $this->renderer->tableheader_close(); 54607993756SAndreas Gohr $this->renderer->tablerow_close(); 547a0bf8bb2SAndreas Gohr $this->renderer->info['struct_table_meta'] = true; 54807993756SAndreas Gohr } 54909dd691aSAndreas Gohr 55009dd691aSAndreas Gohr /** 55109dd691aSAndreas Gohr * Adds CSV export controls 55209dd691aSAndreas Gohr */ 553d6d97f60SAnna Dabrowska protected function renderExportControls() 554d6d97f60SAnna Dabrowska { 55509dd691aSAndreas Gohr if ($this->mode != 'xhtml') return; 5567b240ca8SAndreas Gohr if (empty($this->data['csv'])) return; 55709dd691aSAndreas Gohr if (!$this->resultCount) return; 55809dd691aSAndreas Gohr 559c8ccdaf8SAndreas Gohr $dynamic = $this->searchConfig->getDynamicParameters(); 560c8ccdaf8SAndreas Gohr $params = $dynamic->getURLParameters(); 561c8ccdaf8SAndreas Gohr $params['hash'] = $this->renderer->info['struct_table_hash']; 562c8ccdaf8SAndreas Gohr 56309dd691aSAndreas Gohr // FIXME apply dynamic filters 564eafc109fSAndreas Gohr $link = exportlink($this->id, 'struct_csv', $params); 56509dd691aSAndreas Gohr 566*17a3a578SAndreas Gohr $this->renderer->doc .= '<a href="' . $link . '" class="export mediafile mf_csv">' . 567*17a3a578SAndreas Gohr $this->helper->getLang('csvexport') . '</a>'; 56809dd691aSAndreas Gohr } 56907993756SAndreas Gohr} 570