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