xref: /plugin/struct/meta/NestedResult.php (revision 5bc00e117f7d6c42d7b1b5918894e63f3f847966)
1<?php
2
3namespace dokuwiki\plugin\struct\meta;
4
5/**
6 * This class builds a nested tree from a search result
7 *
8 * This is used to create the nested output in the AggregationList
9 */
10class NestedResult
11{
12
13    /** @var NestedValue[] */
14    protected $nodes = [];
15
16    /** @var Value[][] */
17    protected $result;
18
19    /**
20     * @param Value[][] $result the original search result
21     * @return void
22     */
23    public function __construct($result)
24    {
25        $this->result = $result;
26    }
27
28    /**
29     * Get the nested result
30     *
31     * @param int $nesting the nesting level to use
32     * @return NestedValue the root node of the nested tree
33     */
34    public function getRoot($nesting) {
35        $this->nodes = [];
36        $root = new NestedValue(null, -1);
37
38        if(!$this->result) return $root;
39        foreach ($this->result as $row) {
40            $this->nestBranch($root, $row, $nesting);
41        }
42
43        return $root;
44    }
45
46    /**
47     * Creates nested nodes for a given result row
48     *
49     * Splits up multi Values into separate nodes, when used in nesting
50     *
51     * @param Value[] $row current result row to work on
52     * @param int $nesting number of wanted nesting levels
53     * @param int $depth current nesting depth (used in recursion)
54     */
55    protected function nestBranch(NestedValue $parent, $row, $nesting, $depth = 0)
56    {
57        // nesting level reached, add row and return
58        if($depth >= $nesting) {
59            $parent->addResultRow($row);
60            return;
61        }
62
63        $valObj = array_shift($row);
64        if (!$valObj) return; // no more values to nest, usually shouldn't happen
65
66        if ($valObj->getColumn()->isMulti()) {
67            // split up multi values into separate nodes
68            $values = $valObj->getValue();
69            foreach ($values as $value) {
70                $newValue = new Value($valObj->getColumn(), $value);
71                $node = $this->getNodeForValue($newValue, $depth);
72                $parent->addChild($node);
73                $this->nestBranch($node, $row, $nesting, $depth + 1);
74            }
75        } else {
76            $node = $this->getNodeForValue($valObj, $depth);
77            $parent->addChild($node);
78            $this->nestBranch($node, $row, $nesting, $depth + 1);
79
80        }
81    }
82
83    /**
84     * Create or get existing Node from the tree
85     *
86     * @param Value $value
87     * @param int $depth
88     * @return NestedValue
89     */
90    protected function getNodeForValue(Value $value, $depth)
91    {
92        $node = new NestedValue($value, $depth);
93        $key = (string) $node;
94        if (!isset($this->nodes[$key])) {
95            $this->nodes[$key] = $node;
96        }
97        return $this->nodes[$key];
98    }
99}
100
101
102