Add EmailLogListPage
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / data / TObjectTreeNode.class.php
CommitLineData
755d49f0 1<?php
a9229942 2
755d49f0 3namespace wcf\data;
a9229942 4
755d49f0
MS
5use wcf\util\ClassUtil;
6
7/**
8 * Default implementation of `IObjectTreeNode`.
a9229942
TD
9 *
10 * @author Matthias Schmidt
11 * @copyright 2001-2019 WoltLab GmbH
12 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
13 * @package WoltLabSuite\Core\Data
14 * @since 5.2
755d49f0 15 */
a9229942
TD
16trait TObjectTreeNode
17{
18 /**
19 * child nodes
20 * @var static[]
21 */
22 protected $children = [];
23
24 /**
25 * current iterator key
26 * @var int
27 */
28 protected $index = 0;
29
30 /**
31 * parent node object
32 * @var static
33 */
34 protected $parentNode;
35
36 /**
37 * Adds the given node as child node and sets the child node's parent node to this node.
38 *
39 * @param IObjectTreeNode $child added child node
40 * @throws \InvalidArgumentException if given object is no (deocrated) instance of this class
41 */
42 public function addChild(IObjectTreeNode $child)
43 {
44 if (!($child instanceof $this) && !ClassUtil::isDecoratedInstanceOf($child, static::class)) {
45 throw new \InvalidArgumentException("Child has to be a (decorated) instance of '" . static::class . "', but instance of '" . \get_class($child) . "' given.");
46 }
47
48 $child->setParentNode($this);
49
50 $this->children[] = $child;
51 }
52
53 /**
54 * Returns the number of child nodes.
55 *
56 * @return int
57 */
58 public function count()
59 {
60 return \count($this->children);
61 }
62
63 /**
64 * Return the currently iterated child node.
65 *
66 * @return static
67 */
68 public function current()
69 {
70 return $this->children[$this->index];
71 }
72
73 /**
74 * Returns an iterator for the currently iterated child node by returning the node itself.
75 *
76 * @return static
77 */
78 public function getChildren()
79 {
80 return $this->children[$this->index];
81 }
82
83 /**
84 * Returns the depth of the node within the tree.
85 *
86 * The minimum depth is `1`.
87 *
88 * @return int
89 */
90 public function getDepth()
91 {
92 $element = $this;
93 $depth = 1;
94
95 while ($element->parentNode->parentNode !== null) {
96 $depth++;
97 $element = $element->parentNode;
98 }
99
100 return $depth;
101 }
102
103 /**
104 * Returns the number of open parent nodes.
105 *
106 * @return int
107 */
108 public function getOpenParentNodes()
109 {
110 $element = $this;
111 $i = 0;
112
113 while ($element->parentNode->parentNode !== null && $element->isLastSibling()) {
114 $i++;
115 $element = $element->parentNode;
116 }
117
118 return $i;
119 }
120
121 /**
122 * Retruns the parent node of this node.
123 *
124 * @return static parent node
125 */
126 public function getParentNode()
127 {
128 return $this->parentNode;
129 }
130
131 /**
132 * Returns `true` if the node as any children and return `false` otherwise.
133 *
134 * @return bool
135 */
136 public function hasChildren()
137 {
138 return !empty($this->children);
139 }
140
141 /**
142 * Return the key of the currently iterated child node.
143 *
144 * @return int
145 */
146 public function key()
147 {
148 return $this->index;
149 }
150
151 /**
152 * Returns `true` if this node is the last sibling and `false` otherwise.
153 *
154 * @return bool
155 */
156 public function isLastSibling()
157 {
158 foreach ($this->parentNode as $key => $child) {
159 if ($child === $this) {
160 return $key === \count($this->parentNode) - 1;
161 }
162 }
163
164 throw new \LogicException("Unreachable");
165 }
166
167 /**
168 * Moves the iteration forward to next child node.
169 */
170 public function next()
171 {
172 $this->index++;
173 }
174
175 /**
176 * Rewind the iteration to the first child node.
177 */
178 public function rewind()
179 {
180 $this->index = 0;
181 }
182
183 /**
184 * Sets the parent node of this node.
185 *
186 * @param IObjectTreeNode $parentNode parent node
187 * @throws \InvalidArgumentException if given object is no (deocrated) instance of this class
188 */
189 public function setParentNode(IObjectTreeNode $parentNode)
190 {
191 if (!($parentNode instanceof $this) && !ClassUtil::isDecoratedInstanceOf($parentNode, static::class)) {
192 throw new \InvalidArgumentException("Parent has to be a (decorated) instance of '" . static::class . "', but instance of '" . \get_class($parentNode) . "' given.");
193 }
194
195 $this->parentNode = $parentNode;
196 }
197
198 /**
199 * Returns `true` if current iteration position is valid and `false` otherwise.
200 *
201 * @return bool
202 */
203 public function valid()
204 {
205 return isset($this->children[$this->index]);
206 }
755d49f0 207}