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