xref: /plugin/struct/meta/AggregationList.php (revision 00f71f1792dd6eaba8ea1c269be2cb4d9d469640)
1<?php
2
3namespace dokuwiki\plugin\struct\meta;
4
5/**
6 * Class AggregationList
7 *
8 * @package dokuwiki\plugin\struct\meta
9 */
10class AggregationList extends Aggregation
11{
12    /** @var int number of all results */
13    protected $resultColumnCount;
14
15    /** @inheritdoc */
16    public function __construct($id, $mode, \Doku_Renderer $renderer, SearchConfig $searchConfig)
17    {
18        parent::__construct($id, $mode, $renderer, $searchConfig);
19        $this->resultColumnCount = count($this->columns);
20    }
21
22    /** @inheritdoc */
23    public function render($showNotFound = false)
24    {
25        $this->startScope();
26        if ($this->result) {
27            $nestedResult = new NestedResult($this->result);
28            $root = $nestedResult->getRoot($this->data['nesting'], $this->data['index']);
29            $this->renderNode($root);
30        } elseif ($showNotFound) {
31            $this->renderer->cdata($this->helper->getLang('none'));
32        }
33        $this->finishScope();
34    }
35
36    /**
37     * Recursively render the result tree
38     *
39     * @param NestedValue $node
40     * @return void
41     */
42    protected function renderNode(NestedValue $node)
43    {
44        $self = $node->getValueObject(); // null for root node
45        $children = $node->getChildren();
46        $results = $node->getResultRows();
47
48        // all our content is in a listitem, unless we are the root node
49        if ($self) {
50            $this->renderer->listitem_open($node->getDepth() + 1); // levels are 1 based
51        }
52
53        // render own value if available
54        if ($self) {
55            $this->renderer->listcontent_open();
56            $this->renderListItem([$self], $node->getDepth()); // zero based depth
57            $this->renderer->listcontent_close();
58        }
59
60        // render children or results as sub-list
61        if ($children || $results) {
62            $this->renderer->listu_open();
63
64            foreach ($children as $child) {
65                $this->renderNode($child);
66            }
67
68            foreach ($results as $result) {
69                $this->renderer->listitem_open($node->getDepth() + 2); // levels are 1 based, this is one deeper
70                $this->renderer->listcontent_open();
71                $this->renderListItem($result, $node->getDepth() + 1); // zero based depth, one deeper
72                $this->renderer->listcontent_close();
73                $this->renderer->listitem_close();
74            }
75
76            $this->renderer->listu_close();
77        }
78
79        // close listitem if opened
80        if ($self) {
81            $this->renderer->listitem_close();
82        }
83    }
84
85    /**
86     * Adds additional info to document and renderer in XHTML mode
87     *
88     * @see finishScope()
89     */
90    protected function startScope()
91    {
92        // wrapping div
93        if ($this->mode != 'xhtml') return;
94        $this->renderer->doc .= "<div class=\"structaggregation listaggregation\">";
95    }
96
97    /**
98     * Closes anything opened in startScope()
99     *
100     * @see startScope()
101     */
102    protected function finishScope()
103    {
104        // wrapping div
105        if ($this->mode != 'xhtml') return;
106        $this->renderer->doc .= '</div>';
107    }
108
109
110    /**
111     * Render the content of a single list item
112     *
113     * @param Value[] $resultrow
114     * @param int $depth The current nesting depth (zero based)
115     */
116    protected function renderListItem($resultrow, $depth)
117    {
118        $sepbyheaders = $this->searchConfig->getConf()['sepbyheaders'];
119        $headers = $this->searchConfig->getConf()['headers'];
120
121        foreach ($resultrow as $index => $value) {
122            if ($value->isEmpty()) continue;
123            $column = $index + $depth; // the resultrow is shifted by the nesting depth
124            if ($sepbyheaders && !empty($headers[$column])) {
125                $header = $headers[$column];
126            } else {
127                $header = '';
128            }
129
130            if ($this->mode === 'xhtml') {
131                $this->renderValueXHTML($value, $header);
132            } else {
133                $this->renderValueGeneric($value, $header);
134            }
135        }
136    }
137
138    /**
139     * Render the given Value in a XHTML renderer
140     * @param Value $value
141     * @param string $header
142     * @return void
143     */
144    protected function renderValueXHTML($value, $header)
145    {
146        $attributes = [
147            'data-struct-column' => strtolower($value->getColumn()->getFullQualifiedLabel()),
148            'data-struct-type' => strtolower($value->getColumn()->getType()->getClass()),
149            'class' => 'li', // default dokuwiki content wrapper
150        ];
151
152        $this->renderer->doc .= sprintf('<div %s>', buildAttributes($attributes)); // wrapper
153        if ($header !== '') {
154            $this->renderer->doc .= sprintf('<span class="struct_header">%s</span> ', hsc($header));
155        }
156        $this->renderer->doc .= '<div class="struct_value">';
157        $value->render($this->renderer, $this->mode);
158        $this->renderer->doc .= '</div>';
159        $this->renderer->doc .= '</div> '; // wrapper
160    }
161
162    /**
163     * Render the given Value in any non-XHTML renderer
164     * @param Value $value
165     * @param string $header
166     * @return void
167     */
168    protected function renderValueGeneric($value, $header)
169    {
170        $this->renderer->listcontent_open();
171        if ($header !== '') $this->renderer->cdata($header . ' ');
172        $value->render($this->renderer, $this->mode);
173        $this->renderer->listcontent_close();
174    }
175}
176