xref: /plugin/struct/meta/NestedValue.php (revision 5bc00e117f7d6c42d7b1b5918894e63f3f847966)
1<?php
2
3namespace dokuwiki\plugin\struct\meta;
4
5use dokuwiki\Utf8\Sort;
6
7/**
8 * Object to create a tree of values
9 *
10 * You should not create these yourself, but use the NestedResult class instead
11 */
12class NestedValue
13{
14
15    /** @var Value */
16    protected $value;
17
18    /** @var NestedValue[] */
19    protected $children = [];
20
21    /** @var Value[][] */
22    protected $resultRows = [];
23
24    /** @var int the nesting depth */
25    protected $depth;
26
27    /**
28     * Create a nested version of the given value
29     *
30     * @param Value|null $value The value to store, null for root node
31     * @param int $depth The depth of this node (avoids collision where the same values are selected on multiple levels)
32     */
33    public function __construct(?Value $value, $depth = 0)
34    {
35        $this->value = $value;
36        $this->depth = $depth;
37    }
38
39    /**
40     * @return int
41     */
42    public function getDepth()
43    {
44        return $this->depth;
45    }
46
47    /**
48     * Access the stored value
49     *
50     * @return Value|null the value stored in this node, null for root node
51     */
52    public function getValueObject()
53    {
54        return $this->value;
55    }
56
57    /**
58     * Add a child node
59     *
60     * Nodes with the same key (__toString()) will be overwritten
61     *
62     * @param NestedValue $child
63     * @return void
64     */
65    public function addChild(NestedValue $child)
66    {
67        $this->children[(string)$child] = $child; // ensures uniqueness
68    }
69
70    /**
71     * Get all child nodes
72     *
73     * @return NestedValue[]
74     */
75    public function getChildren()
76    {
77        $children = $this->children;
78        usort($children, [$this, 'sortChildren']);
79        return $children;
80    }
81
82    /**
83     * Add a result row to this node
84     *
85     * @param Value[] $row
86     * @return void
87     */
88    public function addResultRow($row)
89    {
90        $this->resultRows[] = $row;
91    }
92
93    /**
94     * Get all result rows stored in this node
95     *
96     * @return Value[][]
97     */
98    public function getResultRows()
99    {
100        return $this->resultRows;
101    }
102
103    /**
104     * Get a unique key for this node
105     *
106     * @return string
107     */
108    public function __toString()
109    {
110        if ($this->value === null) return ''; // root node
111        return $this->value->__toString() . '-' . $this->depth;
112    }
113
114    /**
115     * Custom comparator to sort the children of this node
116     *
117     * @param NestedValue $a
118     * @param NestedValue $b
119     * @return int
120     */
121    public function sortChildren(NestedValue $a, NestedValue $b)
122    {
123        // note: the way NestedResults build the NestedValues, the value object should
124        // always contain a single value only. But since the associated column is still
125        // a multi-value column, getCompareValue() will still return an array.
126        // So here we treat all returns as array and join them with a dash (even though
127        // there should never be more than one value in there)
128        return Sort::strcmp(
129            join('-', (array)$a->getValueObject()->getCompareValue()),
130            join('-', (array)$b->getValueObject()->getCompareValue())
131        );
132    }
133
134}
135