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