xref: /plugin/struct/meta/AggregationTable.php (revision d6d97f6064c3b0f90310be8341edc9585520ee54)
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 */
10*d6d97f60SAnna Dabrowskaclass AggregationTable
11*d6d97f60SAnna Dabrowska{
1207993756SAndreas Gohr
1307993756SAndreas Gohr    /**
1407993756SAndreas Gohr     * @var string the page id of the page this is rendered to
1507993756SAndreas Gohr     */
1607993756SAndreas Gohr    protected $id;
1707993756SAndreas Gohr    /**
1807993756SAndreas Gohr     * @var string the Type of renderer used
1907993756SAndreas Gohr     */
2007993756SAndreas Gohr    protected $mode;
2107993756SAndreas Gohr    /**
2207993756SAndreas Gohr     * @var \Doku_Renderer the DokuWiki renderer used to create the output
2307993756SAndreas Gohr     */
2407993756SAndreas Gohr    protected $renderer;
2507993756SAndreas Gohr    /**
2607993756SAndreas Gohr     * @var SearchConfig the configured search - gives access to columns etc.
2707993756SAndreas Gohr     */
2807993756SAndreas Gohr    protected $searchConfig;
2907993756SAndreas Gohr
3007993756SAndreas Gohr    /**
3107993756SAndreas Gohr     * @var Column[] the list of columns to be displayed
3207993756SAndreas Gohr     */
3307993756SAndreas Gohr    protected $columns;
3407993756SAndreas Gohr
3507993756SAndreas Gohr    /**
3607993756SAndreas Gohr     * @var  Value[][] the search result
3707993756SAndreas Gohr     */
3807993756SAndreas Gohr    protected $result;
3907993756SAndreas Gohr
4007993756SAndreas Gohr    /**
4107993756SAndreas Gohr     * @var int number of all results
4207993756SAndreas Gohr     */
4307993756SAndreas Gohr    protected $resultCount;
4407993756SAndreas Gohr
4507993756SAndreas Gohr    /**
46d4b5a17cSAndreas Gohr     * @var string[] the result PIDs for each row
47d4b5a17cSAndreas Gohr     */
48d4b5a17cSAndreas Gohr    protected $resultPIDs;
490ceefd5cSAnna Dabrowska    protected $resultRids;
506fd73b4bSAnna Dabrowska    protected $resultRevs;
51d4b5a17cSAndreas Gohr
52d4b5a17cSAndreas Gohr    /**
5307993756SAndreas Gohr     * @var array for summing up columns
5407993756SAndreas Gohr     */
5507993756SAndreas Gohr    protected $sums;
5607993756SAndreas Gohr
5707993756SAndreas Gohr    /**
586b5e52fdSAndreas Gohr     * @var bool skip full table when no results found
596b5e52fdSAndreas Gohr     */
606b5e52fdSAndreas Gohr    protected $simplenone = true;
616b5e52fdSAndreas Gohr
626b5e52fdSAndreas Gohr    /**
6307993756SAndreas Gohr     * @todo we might be able to get rid of this helper and move this to SearchConfig
6407993756SAndreas Gohr     * @var \helper_plugin_struct_config
6507993756SAndreas Gohr     */
6607993756SAndreas Gohr    protected $helper;
6707993756SAndreas Gohr
6807993756SAndreas Gohr    /**
6907993756SAndreas Gohr     * Initialize the Aggregation renderer and executes the search
7007993756SAndreas Gohr     *
7107993756SAndreas Gohr     * You need to call @see render() on the resulting object.
7207993756SAndreas Gohr     *
7307993756SAndreas Gohr     * @param string $id
7407993756SAndreas Gohr     * @param string $mode
7507993756SAndreas Gohr     * @param \Doku_Renderer $renderer
7607993756SAndreas Gohr     * @param SearchConfig $searchConfig
7707993756SAndreas Gohr     */
78*d6d97f60SAnna Dabrowska    public function __construct($id, $mode, \Doku_Renderer $renderer, SearchConfig $searchConfig, $idColumn)
79*d6d97f60SAnna Dabrowska    {
8007993756SAndreas Gohr        $this->id = $id;
8107993756SAndreas Gohr        $this->mode = $mode;
8207993756SAndreas Gohr        $this->renderer = $renderer;
8307993756SAndreas Gohr        $this->searchConfig = $searchConfig;
8407993756SAndreas Gohr        $this->data = $searchConfig->getConf();
8507993756SAndreas Gohr        $this->columns = $searchConfig->getColumns();
8607993756SAndreas Gohr
87efe74305SAnna Dabrowska        // FIXME detect or get real columnId
88efe74305SAnna Dabrowska        // for now rid is OK for page data because tables are also joined on rev
89d400a5f0SAnna Dabrowska        $this->result = $this->searchConfig->execute($idColumn);
9007993756SAndreas Gohr        $this->resultCount = $this->searchConfig->getCount();
91d4b5a17cSAndreas Gohr        $this->resultPIDs = $this->searchConfig->getPids();
920ceefd5cSAnna Dabrowska        $this->resultRids = $this->searchConfig->getRids();
936fd73b4bSAnna Dabrowska        $this->resultRevs = $this->searchConfig->getRevs();
9407993756SAndreas Gohr        $this->helper = plugin_load('helper', 'struct_config');
9507993756SAndreas Gohr    }
9607993756SAndreas Gohr
9707993756SAndreas Gohr    /**
9807993756SAndreas Gohr     * Create the table on the renderer
9907993756SAndreas Gohr     */
100*d6d97f60SAnna Dabrowska    public function render()
101*d6d97f60SAnna Dabrowska    {
102b7e1d73bSAndreas Gohr
103b7e1d73bSAndreas Gohr        // abort early if there are no results at all (not filtered)
1046b5e52fdSAndreas Gohr        if (!$this->resultCount && !$this->isDynamicallyFiltered() && $this->simplenone) {
105b7e1d73bSAndreas Gohr            $this->startScope();
106b7e1d73bSAndreas Gohr            $this->renderer->cdata($this->helper->getLang('none'));
107b7e1d73bSAndreas Gohr            $this->finishScope();
108b7e1d73bSAndreas Gohr            return;
109b7e1d73bSAndreas Gohr        }
110b7e1d73bSAndreas Gohr
11107993756SAndreas Gohr        // table open
11207993756SAndreas Gohr        $this->startScope();
113986ab7e6SAndreas Gohr        $this->renderActiveFilters();
11407993756SAndreas Gohr        $this->renderer->table_open();
11507993756SAndreas Gohr
11607993756SAndreas Gohr        // header
11707993756SAndreas Gohr        $this->renderer->tablethead_open();
118986ab7e6SAndreas Gohr        $this->renderColumnHeaders();
119986ab7e6SAndreas Gohr        $this->renderDynamicFilters();
12007993756SAndreas Gohr        $this->renderer->tablethead_close();
12107993756SAndreas Gohr
12207993756SAndreas Gohr        if ($this->resultCount) {
12307993756SAndreas Gohr            // actual data
124a9fd81f9SAndreas Gohr            $this->renderer->tabletbody_open();
125986ab7e6SAndreas Gohr            $this->renderResult();
126a9fd81f9SAndreas Gohr            $this->renderer->tabletbody_close();
12707993756SAndreas Gohr
128a9fd81f9SAndreas Gohr            // footer (tfoot is develonly currently)
129a9fd81f9SAndreas Gohr            if (method_exists($this->renderer, 'tabletfoot_open')) $this->renderer->tabletfoot_open();
130986ab7e6SAndreas Gohr            $this->renderSums();
131986ab7e6SAndreas Gohr            $this->renderPagingControls();
132a9fd81f9SAndreas Gohr            if (method_exists($this->renderer, 'tabletfoot_close')) $this->renderer->tabletfoot_close();
13307993756SAndreas Gohr        } else {
13407993756SAndreas Gohr            // nothing found
135986ab7e6SAndreas Gohr            $this->renderEmptyResult();
13607993756SAndreas Gohr        }
13707993756SAndreas Gohr
13807993756SAndreas Gohr        // table close
13907993756SAndreas Gohr        $this->renderer->table_close();
14009dd691aSAndreas Gohr
14109dd691aSAndreas Gohr        // export handle
14209dd691aSAndreas Gohr        $this->renderExportControls();
14307993756SAndreas Gohr        $this->finishScope();
14407993756SAndreas Gohr    }
14507993756SAndreas Gohr
14607993756SAndreas Gohr    /**
14707993756SAndreas Gohr     * Adds additional info to document and renderer in XHTML mode
14807993756SAndreas Gohr     *
14907993756SAndreas Gohr     * @see finishScope()
15007993756SAndreas Gohr     */
151*d6d97f60SAnna Dabrowska    protected function startScope()
152*d6d97f60SAnna Dabrowska    {
15307993756SAndreas Gohr        // unique identifier for this aggregation
15407993756SAndreas Gohr        $this->renderer->info['struct_table_hash'] = md5(var_export($this->data, true));
15509dd691aSAndreas Gohr
15609dd691aSAndreas Gohr        // wrapping div
15709dd691aSAndreas Gohr        if ($this->mode != 'xhtml') return;
15809dd691aSAndreas Gohr        $this->renderer->doc .= "<div class=\"structaggregation\">";
15907993756SAndreas Gohr    }
16007993756SAndreas Gohr
16107993756SAndreas Gohr    /**
16207993756SAndreas Gohr     * Closes the table and anything opened in startScope()
16307993756SAndreas Gohr     *
16407993756SAndreas Gohr     * @see startScope()
16507993756SAndreas Gohr     */
166*d6d97f60SAnna Dabrowska    protected function finishScope()
167*d6d97f60SAnna Dabrowska    {
16807993756SAndreas Gohr        // remove identifier from renderer again
16907993756SAndreas Gohr        if (isset($this->renderer->info['struct_table_hash'])) {
17007993756SAndreas Gohr            unset($this->renderer->info['struct_table_hash']);
17107993756SAndreas Gohr        }
17209dd691aSAndreas Gohr
17309dd691aSAndreas Gohr        // wrapping div
17409dd691aSAndreas Gohr        if ($this->mode != 'xhtml') return;
17509dd691aSAndreas Gohr        $this->renderer->doc .= '</div>';
17607993756SAndreas Gohr    }
17707993756SAndreas Gohr
17807993756SAndreas Gohr    /**
17907993756SAndreas Gohr     * Displays info about the currently applied filters
18007993756SAndreas Gohr     */
181*d6d97f60SAnna Dabrowska    protected function renderActiveFilters()
182*d6d97f60SAnna Dabrowska    {
18307993756SAndreas Gohr        if ($this->mode != 'xhtml') return;
18407993756SAndreas Gohr        $dynamic = $this->searchConfig->getDynamicParameters();
18507993756SAndreas Gohr        $filters = $dynamic->getFilters();
18607993756SAndreas Gohr        if (!$filters) return;
18707993756SAndreas Gohr
18807993756SAndreas Gohr        $fltrs = array();
18907993756SAndreas Gohr        foreach ($filters as $column => $filter) {
19007993756SAndreas Gohr            list($comp, $value) = $filter;
19104ec4785SAnna Dabrowska
19204ec4785SAnna Dabrowska            // display the filters in a human readable format
19304ec4785SAnna Dabrowska            foreach ($this->columns as $col) {
19404ec4785SAnna Dabrowska                if ($column === $col->getFullQualifiedLabel()) {
19504ec4785SAnna Dabrowska                    $column = $col->getTranslatedLabel();
19604ec4785SAnna Dabrowska                }
19704ec4785SAnna Dabrowska            }
1981f075418SAnna Dabrowska            $fltrs[] = sprintf('"%s" %s "%s"', $column, $this->helper->getLang("comparator $comp"), $value);
19907993756SAndreas Gohr        }
20007993756SAndreas Gohr
20107993756SAndreas Gohr        $this->renderer->doc .= '<div class="filter">';
20207993756SAndreas Gohr        $this->renderer->doc .= '<h4>' . sprintf($this->helper->getLang('tablefilteredby'), hsc(implode(' & ', $fltrs))) . '</h4>';
20307993756SAndreas Gohr        $this->renderer->doc .= '<div class="resetfilter">';
20407993756SAndreas Gohr        $this->renderer->internallink($this->id, $this->helper->getLang('tableresetfilter'));
20507993756SAndreas Gohr        $this->renderer->doc .= '</div>';
20607993756SAndreas Gohr        $this->renderer->doc .= '</div>';
20707993756SAndreas Gohr    }
20807993756SAndreas Gohr
20907993756SAndreas Gohr    /**
21007993756SAndreas Gohr     * Shows the column headers with links to sort by column
21107993756SAndreas Gohr     */
212*d6d97f60SAnna Dabrowska    protected function renderColumnHeaders()
213*d6d97f60SAnna Dabrowska    {
21407993756SAndreas Gohr        $this->renderer->tablerow_open();
21507993756SAndreas Gohr
21607993756SAndreas Gohr        // additional column for row numbers
21707993756SAndreas Gohr        if ($this->data['rownumbers']) {
21807993756SAndreas Gohr            $this->renderer->tableheader_open();
21907993756SAndreas Gohr            $this->renderer->cdata('#');
22007993756SAndreas Gohr            $this->renderer->tableheader_close();
22107993756SAndreas Gohr        }
22207993756SAndreas Gohr
22307993756SAndreas Gohr        // show all headers
2248c4ee9beSAndreas Gohr        foreach ($this->columns as $num => $column) {
2258c4ee9beSAndreas Gohr            $header = '';
2268c4ee9beSAndreas Gohr            if (isset($this->data['headers'][$num])) {
2278c4ee9beSAndreas Gohr                $header = $this->data['headers'][$num];
2288c4ee9beSAndreas Gohr            }
22907993756SAndreas Gohr
23007993756SAndreas Gohr            // use field label if no header was set
23107993756SAndreas Gohr            if (blank($header)) {
23201f8b845SAndreas Gohr                if (is_a($column, 'dokuwiki\plugin\struct\meta\Column')) {
23307993756SAndreas Gohr                    $header = $column->getTranslatedLabel();
23407993756SAndreas Gohr                } else {
23507993756SAndreas Gohr                    $header = 'column ' . $num; // this should never happen
23607993756SAndreas Gohr                }
23707993756SAndreas Gohr            }
23807993756SAndreas Gohr
23907993756SAndreas Gohr            // simple mode first
24007993756SAndreas Gohr            if ($this->mode != 'xhtml') {
24107993756SAndreas Gohr                $this->renderer->tableheader_open();
24207993756SAndreas Gohr                $this->renderer->cdata($header);
24307993756SAndreas Gohr                $this->renderer->tableheader_close();
24407993756SAndreas Gohr                continue;
24507993756SAndreas Gohr            }
24607993756SAndreas Gohr
24707993756SAndreas Gohr            // still here? create custom header for more flexibility
24807993756SAndreas Gohr
2499113d04aSAndreas Gohr            // width setting, widths are prevalidated, no escape needed
25007993756SAndreas Gohr            $width = '';
2519113d04aSAndreas Gohr            if (isset($this->data['widths'][$num]) && $this->data['widths'][$num] != '-') {
2529113d04aSAndreas Gohr                $width = ' style="min-width: ' . $this->data['widths'][$num] . ';' .
2539113d04aSAndreas Gohr                         'max-width: ' . $this->data['widths'][$num] . ';"';
25407993756SAndreas Gohr            }
25507993756SAndreas Gohr
256d4b5a17cSAndreas Gohr            // prepare data attribute for inline edits
257*d6d97f60SAnna Dabrowska            if (
258*d6d97f60SAnna Dabrowska                !is_a($column, '\dokuwiki\plugin\struct\meta\PageColumn') &&
259d4b5a17cSAndreas Gohr                !is_a($column, '\dokuwiki\plugin\struct\meta\RevisionColumn')
260d4b5a17cSAndreas Gohr            ) {
261d4b5a17cSAndreas Gohr                $data = 'data-field="' . hsc($column->getFullQualifiedLabel()) . '"';
262d4b5a17cSAndreas Gohr            } else {
263d4b5a17cSAndreas Gohr                $data = '';
264d4b5a17cSAndreas Gohr            }
265d4b5a17cSAndreas Gohr
26607993756SAndreas Gohr            // sort indicator and link
26707993756SAndreas Gohr            $sortclass = '';
26807993756SAndreas Gohr            $sorts = $this->searchConfig->getSorts();
26907993756SAndreas Gohr            $dynamic = $this->searchConfig->getDynamicParameters();
270aa124708SAndreas Gohr            $dynamic->setSort($column, true);
27107993756SAndreas Gohr            if (isset($sorts[$column->getFullQualifiedLabel()])) {
272aa124708SAndreas Gohr                list(/*colname*/, $currentSort) = $sorts[$column->getFullQualifiedLabel()];
273aa124708SAndreas Gohr                if ($currentSort) {
27407993756SAndreas Gohr                    $sortclass = 'sort-down';
27507993756SAndreas Gohr                    $dynamic->setSort($column, false);
27607993756SAndreas Gohr                } else {
27707993756SAndreas Gohr                    $sortclass = 'sort-up';
27807993756SAndreas Gohr                }
27907993756SAndreas Gohr            }
28007993756SAndreas Gohr            $link = wl($this->id, $dynamic->getURLParameters());
28107993756SAndreas Gohr
28207993756SAndreas Gohr            // output XHTML header
283d4b5a17cSAndreas Gohr            $this->renderer->doc .= "<th $width $data>";
28407993756SAndreas Gohr            $this->renderer->doc .= '<a href="' . $link . '" class="' . $sortclass . '" title="' . $this->helper->getLang('sort') . '">' . hsc($header) . '</a>';
28507993756SAndreas Gohr            $this->renderer->doc .= '</th>';
28607993756SAndreas Gohr        }
28707993756SAndreas Gohr
28807993756SAndreas Gohr        $this->renderer->tablerow_close();
28907993756SAndreas Gohr    }
29007993756SAndreas Gohr
29107993756SAndreas Gohr    /**
292b7e1d73bSAndreas Gohr     * Is the result set currently dynamically filtered?
293b7e1d73bSAndreas Gohr     * @return bool
294b7e1d73bSAndreas Gohr     */
295*d6d97f60SAnna Dabrowska    protected function isDynamicallyFiltered()
296*d6d97f60SAnna Dabrowska    {
297b7e1d73bSAndreas Gohr        if ($this->mode != 'xhtml') return false;
298b7e1d73bSAndreas Gohr        if (!$this->data['dynfilters']) return false;
299b7e1d73bSAndreas Gohr
300b7e1d73bSAndreas Gohr        $dynamic = $this->searchConfig->getDynamicParameters();
301b7e1d73bSAndreas Gohr        return (bool) $dynamic->getFilters();
302b7e1d73bSAndreas Gohr    }
303b7e1d73bSAndreas Gohr
304b7e1d73bSAndreas Gohr    /**
30507993756SAndreas Gohr     * Add input fields for dynamic filtering
30607993756SAndreas Gohr     */
307*d6d97f60SAnna Dabrowska    protected function renderDynamicFilters()
308*d6d97f60SAnna Dabrowska    {
30907993756SAndreas Gohr        if ($this->mode != 'xhtml') return;
31007993756SAndreas Gohr        if (!$this->data['dynfilters']) return;
3111bc467a4SMichael Grosse        if (is_a($this->renderer, 'renderer_plugin_dw2pdf')) {
312e6ae02ecSMichael Grosse            return;
313e6ae02ecSMichael Grosse        }
3141bc467a4SMichael Grosse        global $conf;
31507993756SAndreas Gohr
31607993756SAndreas Gohr        $this->renderer->doc .= '<tr class="dataflt">';
31707993756SAndreas Gohr
31807993756SAndreas Gohr        // add extra column for row numbers
31907993756SAndreas Gohr        if ($this->data['rownumbers']) {
32007993756SAndreas Gohr            $this->renderer->doc .= '<th></th>';
32107993756SAndreas Gohr        }
32207993756SAndreas Gohr
32307993756SAndreas Gohr        // each column gets a form
32407993756SAndreas Gohr        foreach ($this->columns as $column) {
32507993756SAndreas Gohr            $this->renderer->doc .= '<th>';
32607993756SAndreas Gohr            {
32707993756SAndreas Gohr                $form = new \Doku_Form(array('method' => 'GET', 'action' => wl($this->id)));
32876195677SAndreas Gohr                unset($form->_hidden['sectok']); // we don't need it here
32976195677SAndreas Gohr                if (!$conf['userewrite']) $form->addHidden('id', $this->id);
33007993756SAndreas Gohr
33107993756SAndreas Gohr                // current value
33207993756SAndreas Gohr                $dynamic = $this->searchConfig->getDynamicParameters();
33307993756SAndreas Gohr                $filters = $dynamic->getFilters();
33407993756SAndreas Gohr            if (isset($filters[$column->getFullQualifiedLabel()])) {
33507993756SAndreas Gohr                list(, $current) = $filters[$column->getFullQualifiedLabel()];
33607993756SAndreas Gohr                $dynamic->removeFilter($column);
33707993756SAndreas Gohr            } else {
33807993756SAndreas Gohr                $current = '';
33907993756SAndreas Gohr            }
34007993756SAndreas Gohr
34107993756SAndreas Gohr                // Add current request params
34207993756SAndreas Gohr                $params = $dynamic->getURLParameters();
34307993756SAndreas Gohr            foreach ($params as $key => $val) {
34407993756SAndreas Gohr                $form->addHidden($key, $val);
34507993756SAndreas Gohr            }
34607993756SAndreas Gohr
34707993756SAndreas Gohr                // add input field
348db9b8745SAndreas Gohr                $key = $column->getFullQualifiedLabel() . $column->getType()->getDefaultComparator();
349d60f71efSAndreas Gohr                $form->addElement(form_makeField('text', SearchConfigParameters::$PARAM_FILTER . '[' . $key . ']', $current, ''));
35007993756SAndreas Gohr                $this->renderer->doc .= $form->getForm();
35107993756SAndreas Gohr            }
35207993756SAndreas Gohr            $this->renderer->doc .= '</th>';
35307993756SAndreas Gohr        }
35407993756SAndreas Gohr        $this->renderer->doc .= '</tr>';
35507993756SAndreas Gohr    }
35607993756SAndreas Gohr
35707993756SAndreas Gohr    /**
35807993756SAndreas Gohr     * Display the actual table data
35907993756SAndreas Gohr     */
360*d6d97f60SAnna Dabrowska    protected function renderResult()
361*d6d97f60SAnna Dabrowska    {
36207993756SAndreas Gohr        foreach ($this->result as $rownum => $row) {
36347eb8cceSSzymon Olewniczak            $data = array(
36447eb8cceSSzymon Olewniczak                'id' => $this->id,
36547eb8cceSSzymon Olewniczak                'mode' => $this->mode,
36647eb8cceSSzymon Olewniczak                'renderer' => $this->renderer,
36747eb8cceSSzymon Olewniczak                'searchConfig' => $this->searchConfig,
36847eb8cceSSzymon Olewniczak                'data' => $this->data,
36947eb8cceSSzymon Olewniczak                'rownum' => &$rownum,
37047eb8cceSSzymon Olewniczak                'row' => &$row,
37147eb8cceSSzymon Olewniczak            );
37247eb8cceSSzymon Olewniczak            $evt = new \Doku_Event('PLUGIN_STRUCT_AGGREGATIONTABLE_RENDERRESULTROW', $data);
37347eb8cceSSzymon Olewniczak            if ($evt->advise_before()) {
374f107f479SAndreas Gohr                $this->renderResultRow($rownum, $row);
375f107f479SAndreas Gohr            }
37647eb8cceSSzymon Olewniczak            $evt->advise_after();
37747eb8cceSSzymon Olewniczak        }
378f107f479SAndreas Gohr    }
379f107f479SAndreas Gohr
380f107f479SAndreas Gohr    /**
381f107f479SAndreas Gohr     * Render a single result row
382f107f479SAndreas Gohr     *
383f107f479SAndreas Gohr     * @param int $rownum
384f107f479SAndreas Gohr     * @param array $row
385f107f479SAndreas Gohr     */
386*d6d97f60SAnna Dabrowska    protected function renderResultRow($rownum, $row)
387*d6d97f60SAnna Dabrowska    {
38807993756SAndreas Gohr        $this->renderer->tablerow_open();
38907993756SAndreas Gohr
390d4b5a17cSAndreas Gohr        // add data attribute for inline edit
391d4b5a17cSAndreas Gohr        if ($this->mode == 'xhtml') {
392d4b5a17cSAndreas Gohr            $pid = $this->resultPIDs[$rownum];
3930ceefd5cSAnna Dabrowska            $rid = $this->resultRids[$rownum];
3946fd73b4bSAnna Dabrowska            $rev = $this->resultRevs[$rownum];
395d4b5a17cSAndreas Gohr            $this->renderer->doc = substr(rtrim($this->renderer->doc), 0, -1); // remove closing '>'
3966fd73b4bSAnna Dabrowska            $this->renderer->doc .= ' data-pid="' . hsc($pid) . '" data-rev="' . $rev . '" data-rid="' . $rid . '">';
397d4b5a17cSAndreas Gohr        }
398d4b5a17cSAndreas Gohr
39907993756SAndreas Gohr        // row number column
40007993756SAndreas Gohr        if ($this->data['rownumbers']) {
40107993756SAndreas Gohr            $this->renderer->tablecell_open();
4023215aebfSSzymon Olewniczak            $searchConfigConf = $this->searchConfig->getConf();
4033215aebfSSzymon Olewniczak            $this->renderer->cdata($rownum + $searchConfigConf['offset'] + 1);
40407993756SAndreas Gohr            $this->renderer->tablecell_close();
40507993756SAndreas Gohr        }
40607993756SAndreas Gohr
40707993756SAndreas Gohr        /** @var Value $value */
40807993756SAndreas Gohr        foreach ($row as $colnum => $value) {
40995eef580SAndreas Gohr            $this->renderer->tablecell_open(1, $this->data['align'][$colnum]);
41007993756SAndreas Gohr            $value->render($this->renderer, $this->mode);
41107993756SAndreas Gohr            $this->renderer->tablecell_close();
41207993756SAndreas Gohr
41307993756SAndreas Gohr            // summarize
41407993756SAndreas Gohr            if ($this->data['summarize'] && is_numeric($value->getValue())) {
41507993756SAndreas Gohr                if (!isset($this->sums[$colnum])) {
41607993756SAndreas Gohr                    $this->sums[$colnum] = 0;
41707993756SAndreas Gohr                }
41807993756SAndreas Gohr                $this->sums[$colnum] += $value->getValue();
41907993756SAndreas Gohr            }
42007993756SAndreas Gohr        }
42107993756SAndreas Gohr        $this->renderer->tablerow_close();
42207993756SAndreas Gohr    }
42307993756SAndreas Gohr
42407993756SAndreas Gohr    /**
42507993756SAndreas Gohr     * Renders an information row for when no results were found
42607993756SAndreas Gohr     */
427*d6d97f60SAnna Dabrowska    protected function renderEmptyResult()
428*d6d97f60SAnna Dabrowska    {
42907993756SAndreas Gohr        $this->renderer->tablerow_open();
43070cf6339SAndreas Gohr        $this->renderer->tablecell_open(count($this->columns) + $this->data['rownumbers'], 'center');
43107993756SAndreas Gohr        $this->renderer->cdata($this->helper->getLang('none'));
43207993756SAndreas Gohr        $this->renderer->tablecell_close();
43307993756SAndreas Gohr        $this->renderer->tablerow_close();
43407993756SAndreas Gohr    }
43507993756SAndreas Gohr
43607993756SAndreas Gohr    /**
43707993756SAndreas Gohr     * Add sums if wanted
43807993756SAndreas Gohr     */
439*d6d97f60SAnna Dabrowska    protected function renderSums()
440*d6d97f60SAnna Dabrowska    {
441d18090e8SAndreas Gohr        if (empty($this->data['summarize'])) return;
44207993756SAndreas Gohr
443a0bf8bb2SAndreas Gohr        $this->renderer->info['struct_table_meta'] = true;
4448925ba29SAndreas Gohr        if ($this->mode == 'xhtml') {
4458925ba29SAndreas Gohr            /** @noinspection PhpMethodParametersCountMismatchInspection */
4468925ba29SAndreas Gohr            $this->renderer->tablerow_open('summarize');
4478925ba29SAndreas Gohr        } else {
44807993756SAndreas Gohr            $this->renderer->tablerow_open();
4498925ba29SAndreas Gohr        }
45007993756SAndreas Gohr
45107993756SAndreas Gohr        if ($this->data['rownumbers']) {
4528925ba29SAndreas Gohr            $this->renderer->tableheader_open();
4538925ba29SAndreas Gohr            $this->renderer->tableheader_close();
45407993756SAndreas Gohr        }
45507993756SAndreas Gohr
456aee4116bSAndreas Gohr        $len = count($this->columns);
45707993756SAndreas Gohr        for ($i = 0; $i < $len; $i++) {
4588925ba29SAndreas Gohr            $this->renderer->tableheader_open(1, $this->data['align'][$i]);
459aee4116bSAndreas Gohr            if (!empty($this->sums[$i])) {
4609b97e610SAndreas Gohr                $this->renderer->cdata('∑ ');
4619b97e610SAndreas Gohr                $this->columns[$i]->getType()->renderValue($this->sums[$i], $this->renderer, $this->mode);
46207993756SAndreas Gohr            } else {
46307993756SAndreas Gohr                if ($this->mode == 'xhtml') {
46407993756SAndreas Gohr                    $this->renderer->doc .= '&nbsp;';
46507993756SAndreas Gohr                }
46607993756SAndreas Gohr            }
4678925ba29SAndreas Gohr            $this->renderer->tableheader_close();
46807993756SAndreas Gohr        }
46907993756SAndreas Gohr        $this->renderer->tablerow_close();
470a0bf8bb2SAndreas Gohr        $this->renderer->info['struct_table_meta'] = false;
47107993756SAndreas Gohr    }
47207993756SAndreas Gohr
47307993756SAndreas Gohr    /**
474986ab7e6SAndreas Gohr     * Adds paging controls to the table
47507993756SAndreas Gohr     */
476*d6d97f60SAnna Dabrowska    protected function renderPagingControls()
477*d6d97f60SAnna Dabrowska    {
47807993756SAndreas Gohr        if (empty($this->data['limit'])) return;
479a0bf8bb2SAndreas Gohr        if ($this->mode != 'xhtml') return;
48007993756SAndreas Gohr
481a0bf8bb2SAndreas Gohr        $this->renderer->info['struct_table_meta'] = true;
48207993756SAndreas Gohr        $this->renderer->tablerow_open();
4834bc1074dSMichael Grosse        $this->renderer->tableheader_open((count($this->columns) + ($this->data['rownumbers'] ? 1 : 0)));
48407993756SAndreas Gohr        $offset = $this->data['offset'];
48507993756SAndreas Gohr
48607993756SAndreas Gohr        // prev link
48707993756SAndreas Gohr        if ($offset) {
48807993756SAndreas Gohr            $prev = $offset - $this->data['limit'];
48907993756SAndreas Gohr            if ($prev < 0) {
49007993756SAndreas Gohr                $prev = 0;
49107993756SAndreas Gohr            }
49207993756SAndreas Gohr
49307993756SAndreas Gohr            $dynamic = $this->searchConfig->getDynamicParameters();
49407993756SAndreas Gohr            $dynamic->setOffset($prev);
49507993756SAndreas Gohr            $link = wl($this->id, $dynamic->getURLParameters());
49607993756SAndreas Gohr            $this->renderer->doc .= '<a href="' . $link . '" class="prev">' . $this->helper->getLang('prev') . '</a>';
49707993756SAndreas Gohr        }
49807993756SAndreas Gohr
49907993756SAndreas Gohr        // next link
50007993756SAndreas Gohr        if ($this->resultCount > $offset + $this->data['limit']) {
50107993756SAndreas Gohr            $next = $offset + $this->data['limit'];
50207993756SAndreas Gohr            $dynamic = $this->searchConfig->getDynamicParameters();
50307993756SAndreas Gohr            $dynamic->setOffset($next);
50407993756SAndreas Gohr            $link = wl($this->id, $dynamic->getURLParameters());
50507993756SAndreas Gohr            $this->renderer->doc .= '<a href="' . $link . '" class="next">' . $this->helper->getLang('next') . '</a>';
50607993756SAndreas Gohr        }
50707993756SAndreas Gohr
50807993756SAndreas Gohr        $this->renderer->tableheader_close();
50907993756SAndreas Gohr        $this->renderer->tablerow_close();
510a0bf8bb2SAndreas Gohr        $this->renderer->info['struct_table_meta'] = true;
51107993756SAndreas Gohr    }
51209dd691aSAndreas Gohr
51309dd691aSAndreas Gohr    /**
51409dd691aSAndreas Gohr     * Adds CSV export controls
51509dd691aSAndreas Gohr     */
516*d6d97f60SAnna Dabrowska    protected function renderExportControls()
517*d6d97f60SAnna Dabrowska    {
51809dd691aSAndreas Gohr        if ($this->mode != 'xhtml') return;
5197b240ca8SAndreas Gohr        if (empty($this->data['csv'])) return;
52009dd691aSAndreas Gohr        if (!$this->resultCount) return;
52109dd691aSAndreas Gohr
522c8ccdaf8SAndreas Gohr        $dynamic = $this->searchConfig->getDynamicParameters();
523c8ccdaf8SAndreas Gohr        $params = $dynamic->getURLParameters();
524c8ccdaf8SAndreas Gohr        $params['hash'] = $this->renderer->info['struct_table_hash'];
525c8ccdaf8SAndreas Gohr
52609dd691aSAndreas Gohr        // FIXME apply dynamic filters
527eafc109fSAndreas Gohr        $link = exportlink($this->id, 'struct_csv', $params);
52809dd691aSAndreas Gohr
52909dd691aSAndreas Gohr        $this->renderer->doc .= '<a href="' . $link . '" class="export mediafile mf_csv">' . $this->helper->getLang('csvexport') . '</a>';
53009dd691aSAndreas Gohr    }
53107993756SAndreas Gohr}
532