xref: /plugin/struct/meta/AggregationCloud.php (revision 0549dcc5bc88d4f9d923acdd09931d8d51be7097)
1<?php
2
3namespace dokuwiki\plugin\struct\meta;
4
5class AggregationCloud
6{
7    /**
8     * @var string the page id of the page this is rendered to
9     */
10    protected $id;
11
12    /**
13     * @var string the Type of renderer used
14     */
15    protected $mode;
16
17    /**
18     * @var \Doku_Renderer the DokuWiki renderer used to create the output
19     */
20    protected $renderer;
21
22    /**
23     * @var SearchConfig the configured search - gives access to columns etc.
24     */
25    protected $searchConfig;
26
27    /**
28     * @var Column[] the list of columns to be displayed
29     */
30    protected $columns;
31
32    /**
33     * @var  Value[][] the search result
34     */
35    protected $result;
36
37    /**
38     * @var int number of all results
39     */
40    protected $resultCount;
41
42    /**
43     * Initialize the Aggregation renderer and executes the search
44     *
45     * You need to call @param string $id
46     * @param string $mode
47     * @param \Doku_Renderer $renderer
48     * @param SearchConfig $searchConfig
49     * @see render() on the resulting object.
50     *
51     */
52    public function __construct($id, $mode, \Doku_Renderer $renderer, SearchCloud $searchConfig)
53    {
54        $this->id = $id;
55        $this->mode = $mode;
56        $this->renderer = $renderer;
57        $this->searchConfig = $searchConfig;
58        $this->data = $searchConfig->getConf();
59        $this->columns = $searchConfig->getColumns();
60        $this->result = $this->searchConfig->execute();
61        $this->resultCount = $this->searchConfig->getCount();
62
63        $this->max = $this->result[0]['count'];
64        $this->min = end($this->result)['count'];
65    }
66
67    /**
68     * Create the cloud on the renderer
69     */
70    public function render()
71    {
72
73        $this->sortResults();
74
75        $this->startScope();
76        $this->startList();
77        foreach ($this->result as $result) {
78            $this->renderTag($result);
79        }
80        $this->finishList();
81        $this->finishScope();
82        return;
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=\"structcloud\">";
95    }
96
97    /**
98     * Closes the table and 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     * Render a tag of the cloud
111     *
112     * @param ['tag' => Value, 'count' => int] $result
113     */
114    protected function renderTag($result)
115    {
116        /**
117         * @var Value $value
118         */
119        $value = $result['tag'];
120        $count = $result['count'];
121        if ($value->isEmpty()) {
122            return;
123        }
124
125        $type = strtolower($value->getColumn()->getType()->getClass());
126        $weight = $this->getWeight($count, $this->min, $this->max);
127
128        if (!empty($this->data['target'])) {
129            $target = $this->data['target'];
130        } else {
131            global $INFO;
132            $target = $INFO['id'];
133        }
134
135        $tagValue = $value->getDisplayValue();
136        if (is_array($tagValue)) {
137            $tagValue = $tagValue[0];
138        }
139        $key = $value->getColumn()->getFullQualifiedLabel() . '=';
140        $filter = SearchConfigParameters::$PARAM_FILTER . '[' . urlencode($key) . ']=' . urlencode($tagValue);
141
142        $this->renderer->listitem_open(1);
143        $this->renderer->listcontent_open();
144
145        if ($this->mode == 'xhtml') {
146            $this->renderer->doc .= "<div style='font-size:$weight%' data-count='$count' class='cloudtag struct_$type'>";
147        }
148
149        $value->renderAsTagCloudLink($this->renderer, $this->mode, $target, $filter, $weight);
150
151        if ($this->mode == 'xhtml') {
152            $this->renderer->doc .= '</div>';
153        }
154
155        $this->renderer->listcontent_close();
156        $this->renderer->listitem_close();
157    }
158
159    /**
160     * This interpolates the weight between 70 and 150 based on $min, $max and $current
161     *
162     * @param int $current
163     * @param int $min
164     * @param int $max
165     * @return int
166     */
167    protected function getWeight($current, $min, $max)
168    {
169        if ($min == $max) {
170            return 100;
171        }
172        return round(($current - $min) / ($max - $min) * 80 + 70);
173    }
174
175    /**
176     * Sort the list of results
177     */
178    protected function sortResults()
179    {
180        usort($this->result, function ($a, $b) {
181            $asort = $a['tag']->getColumn()->getType()->getSortString($a['tag']);
182            $bsort = $b['tag']->getColumn()->getType()->getSortString($b['tag']);
183            if ($asort < $bsort) {
184                return -1;
185            }
186            if ($asort > $bsort) {
187                return 1;
188            }
189            return 0;
190        });
191    }
192
193    protected function startList()
194    {
195        $this->renderer->listu_open();
196    }
197
198    protected function finishList()
199    {
200        $this->renderer->listu_close();
201    }
202}
203