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