1<?php 2 3namespace dokuwiki\TreeBuilder\Node; 4 5/** 6 * A node represents one entry in the tree. It can have a parent and children. 7 */ 8abstract class AbstractNode 9{ 10 /** @var AbstractNode|null parent node */ 11 protected ?AbstractNode $parent = null; 12 /** @var string unique ID for this node, usually the page id or external URL */ 13 protected string $id = ''; 14 /** @var string|null title of the node, may be null */ 15 protected ?string $title = null; 16 17 /** @var AbstractNode[] */ 18 protected array $parents = []; 19 /** @var AbstractNode[] */ 20 protected array $children = []; 21 /** @var array */ 22 protected array $properties = []; 23 24 /** 25 * @param string $id The pageID or the external URL 26 * @param string|null $title The title as given in the link 27 */ 28 public function __construct(string $id, ?string $title) 29 { 30 $this->id = $id; 31 $this->title = $title; 32 } 33 34 /** 35 * @return string 36 */ 37 public function getId(): string 38 { 39 return $this->id; 40 } 41 42 /** 43 * Get the namespace of this node 44 * 45 * @return string 46 */ 47 public function getNs(): string 48 { 49 return getNS($this->id); 50 } 51 52 /** 53 * @return string|null 54 */ 55 public function getTitle(): ?string 56 { 57 return $this->title; 58 } 59 60 /** 61 * @param string|null $title 62 */ 63 public function setTitle(?string $title): void 64 { 65 $this->title = $title; 66 } 67 68 /** 69 * Get all nodes on the same level 70 * @return AbstractNode[] 71 */ 72 public function getSiblings(): array 73 { 74 return $this->getParent()->getChildren(); 75 } 76 77 /** 78 * Get all sub nodes, may return an empty array 79 * 80 * @return AbstractNode[] 81 */ 82 public function getChildren(): array 83 { 84 return $this->children; 85 } 86 87 /** 88 * Does this node have children? 89 * 90 * @return bool 91 */ 92 public function hasChildren(): bool 93 { 94 return $this->children !== []; 95 } 96 97 /** 98 * Get all sub nodes and their sub nodes and so on 99 * 100 * @return AbstractNode[] 101 */ 102 public function getDescendants(): array 103 { 104 $descendants = []; 105 foreach ($this->children as $child) { 106 $descendants[] = $child; 107 $descendants = array_merge($descendants, $child->getDescendants()); 108 } 109 return $descendants; 110 } 111 112 /** 113 * Get all parent nodes in reverse order 114 * 115 * This list is cached, so it will only be calculated once. 116 * 117 * @return AbstractNode[] 118 */ 119 public function getParents(): array 120 { 121 if (!$this->parents) { 122 $parent = $this->parent; 123 while ($parent) { 124 $this->parents[] = $parent; 125 $parent = $parent->getParent(); 126 } 127 } 128 129 return $this->parents; 130 } 131 132 /** 133 * Set the direct parent node 134 */ 135 public function setParent(AbstractNode $parent): void 136 { 137 $this->parent = $parent; 138 } 139 140 /** 141 * Get the direct parent node 142 * 143 * @return AbstractNode|null 144 */ 145 public function getParent(): ?AbstractNode 146 { 147 return $this->parent; 148 } 149 150 /** 151 * @param AbstractNode $child 152 * @return void 153 */ 154 public function addChild(AbstractNode $child): void 155 { 156 $child->setParent($this); 157 $this->children[] = $child; 158 } 159 160 /** 161 * Allows to attach an arbitrary property to the page 162 * 163 * @param string $name 164 * @param mixed $value 165 * @return void 166 */ 167 public function setProperty(string $name, $value): void 168 { 169 $this->properties[$name] = $value; 170 } 171 172 /** 173 * Get the named property, default is returned when the property is not set 174 * 175 * @param string $name 176 * @param mixed $default 177 * @return mixed 178 */ 179 public function getProperty(string $name, $default = null) 180 { 181 return $this->properties[$name] ?? $default; 182 } 183 184 /** 185 * Sort the children of this node and all its descendants 186 * 187 * The given comparator function will be called with two nodes as arguments and needs to 188 * return an integer less than, equal to, or greater than zero if the first argument is considered 189 * to be respectively less than, equal to, or greater than the second. 190 * 191 * @param callable $comparator 192 * @return void 193 */ 194 public function sort(callable $comparator): void 195 { 196 usort($this->children, $comparator); 197 foreach ($this->children as $child) { 198 $child->sort($comparator); 199 } 200 } 201 202 /** 203 * Get the string representation of the node 204 * 205 * Uses plus char to show the depth of the node in the tree 206 * 207 * @return string 208 */ 209 public function __toString(): string 210 { 211 return str_pad('', count($this->getParents()), '+') . $this->id; 212 } 213} 214