Completed
Push — master ( 5c3586...68bdab )
by Tomáš
02:53
created

BaseContainer::get()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 6
c 1
b 0
f 0
dl 0
loc 9
ccs 7
cts 7
cp 1
rs 10
cc 3
nc 3
nop 0
crap 3
1
<?php
2
3
4
namespace TournamentGenerator\Containers;
5
6
use Closure;
7
use Countable;
8
use Exception;
9
use Iterator;
10
use TournamentGenerator\Helpers\Sorter\BaseSorter;
11
12
/**
13
 * Class BaseContainer
14
 *
15
 * Container is a helper class for a tree-like structure. It can be used to create a hierarchy and store objects.
16
 *
17
 * @package TournamentGenerator\Containers
18
 * @author  Tomáš Vojík <[email protected]>
19
 * @since   0.4
20
 */
21
class BaseContainer implements Countable, Iterator
22
{
23
24
	/** @var string|int Identifier */
25
	public $id;
26
	/** @var BaseContainer[] Direct child containers */
27
	protected array $children = [];
28
	/** @var BaseContainer|null Parent container reference */
29
	protected ?BaseContainer $parent;
30
	/** @var array Any value that the container holds */
31
	protected array $values = [];
32
33
	/** @var int Current iterator index */
34
	protected int $currentIndex = 0;
35
36
	/**
37
	 * BaseContainer constructor.
38
	 *
39
	 * @param string|int $id
40
	 */
41 190
	public function __construct($id, BaseContainer $parent = null) {
42 190
		$this->id = $id;
43 190
		$this->parent = $parent;
44 190
	}
45
46
	/**
47
	 * Returns the value count
48
	 *
49
	 * @return int
50
	 */
51 38
	public function count() : int {
52 38
		return count($this->get());
53
	}
54
55
	/**
56
	 * Get all values from the container - including child nodes
57
	 *
58
	 * @return array All values
59
	 */
60 120
	public function get() : array {
61 120
		if (count($this->children) > 0) {
62 62
			$values = [$this->values];
63 62
			foreach ($this->children as $child) {
64 62
				$values[] = $child->get();
65
			}
66 62
			return array_merge(...$values);
67
		}
68 120
		return $this->values;
69
	}
70
71
	/**
72
	 * Get all top-level values from the container
73
	 *
74
	 * @return array All values
75
	 */
76 10
	public function getTopLevel() : array {
77 10
		return $this->values;
78
	}
79
80 1
	public function getTopLevelQuery() : ContainerQuery {
81 1
		return new ContainerQuery($this, true);
82
	}
83
84 1
	public function getQuery() : ContainerQuery {
85 1
		return new ContainerQuery($this);
86
	}
87
88
	/**
89
	 * Get the current value
90
	 *
91
	 * @return mixed
92
	 */
93 2
	public function current() {
94 2
		return $this->get()[$this->currentIndex];
95
	}
96
97
	/**
98
	 * Move pointer to next
99
	 */
100 2
	public function next() : void {
101 2
		++$this->currentIndex;
102 2
	}
103
104
	/**
105
	 * Return the current key
106
	 *
107
	 * @return int
108
	 */
109 1
	public function key() : int {
110 1
		return $this->currentIndex;
111
	}
112
113
	/**
114
	 * Check if the current value exists
115
	 *
116
	 * @return bool
117
	 */
118 2
	public function valid() : bool {
119 2
		return isset($this->get()[$this->currentIndex]);
120
	}
121
122
	/**
123
	 * Rewind the iterator
124
	 */
125 2
	public function rewind() : void {
126 2
		$this->currentIndex = 0;
127 2
	}
128
129
	/**
130
	 * Insert a value into container
131
	 *
132
	 * @param array $values Any value to insert into container
133
	 *
134
	 * @post If the value has a container -> add it to the hierarchy
135
	 *
136
	 * @return $this
137
	 * @throws Exception
138
	 */
139 145
	public function insert(...$values) : BaseContainer {
140 145
		foreach ($values as $value) {
141 145
			$this->values[] = $value;
142 145
			if (is_object($value) && method_exists($value, 'getContainer')) {
143 71
				$this->addChild($value->getContainer());
144
			}
145
		}
146 145
		return $this;
147
	}
148
149
	/**
150
	 * Adds a child container
151
	 *
152
	 * @param BaseContainer[] $containers
153
	 *
154
	 * @return $this
155
	 * @post Parent container is set for the added children
156
	 * @throws Exception
157
	 */
158 75
	public function addChild(BaseContainer ...$containers) : BaseContainer {
159 75
		foreach ($containers as $container) {
160 75
			if (!isset($this->children[$container->id])) {
161 75
				$container->setParent($this);
162 75
				$this->children[$container->id] = $container;
163
			}
164
		}
165 75
		return $this;
166
	}
167
168
	/**
169
	 * Gets all ids of the leaf containers
170
	 *
171
	 * @return string[]|int[]
172
	 */
173 50
	public function getLeafIds() : array {
174 50
		if (count($this->children) > 0) {
175 11
			$ids = [];
176 11
			foreach ($this->children as $child) {
177 11
				$ids[] = $child->getLeafIds();
178
			}
179 11
			return array_merge(...$ids);
180
		}
181 50
		return [$this->id];
182
	}
183
184
	/**
185
	 * Add a filter callback
186
	 *
187
	 * @param Closure $callback
188
	 *
189
	 * @return ContainerQuery
190
	 */
191 1
	public function filter(Closure $callback) : ContainerQuery {
192 1
		$query = new ContainerQuery($this);
193 1
		$query->filter($callback);
194 1
		return $query;
195
	}
196
197
	/**
198
	 * Sort a result using a callback - maintaining the index association
199
	 *
200
	 * @param Closure $callback
201
	 *
202
	 * @return ContainerQuery
203
	 */
204 1
	public function sort(Closure $callback) : ContainerQuery {
205 1
		$query = new ContainerQuery($this);
206 1
		$query->sort($callback);
207 1
		return $query;
208
	}
209
210
	/**
211
	 * Sort a result set by a given property
212
	 *
213
	 * @warning Sort callback has a priority.
214
	 *
215
	 * @param string $property
216
	 *
217
	 * @return ContainerQuery
218
	 */
219 1
	public function sortBy(string $property) : ContainerQuery {
220 1
		$query = new ContainerQuery($this);
221 1
		$query->sortBy($property);
222 1
		return $query;
223
	}
224
225
	/**
226
	 * @param BaseSorter $sorter
227
	 *
228
	 * @return ContainerQuery
229
	 */
230 48
	public function addSorter(BaseSorter $sorter) : ContainerQuery {
231 48
		$query = new ContainerQuery($this);
232 48
		$query->addSorter($sorter);
233 48
		return $query;
234
	}
235
236
	/**
237
	 * Get only unique values
238
	 *
239
	 * @return ContainerQuery
240
	 */
241 112
	public function unique() : ContainerQuery {
242 112
		$query = new ContainerQuery($this);
243 112
		$query->unique();
244 112
		return $query;
245
	}
246
247
	/**
248
	 * Get a parent container
249
	 *
250
	 * @return BaseContainer|null
251
	 * @since 0.5
252
	 */
253 2
	public function getParent() : ?BaseContainer {
254 2
		return $this->parent;
255
	}
256
257
	/**
258
	 * Set a container's parent
259
	 *
260
	 * @param BaseContainer|null $parent
261
	 *
262
	 * @return BaseContainer
263
	 * @throws Exception
264
	 * @since 0.5
265
	 */
266 76
	public function setParent(BaseContainer $parent) : BaseContainer {
267 76
		if ($parent !== $this->parent && !is_null($this->parent)) {
268 1
			throw new Exception('Parent container can only be set once!');
269
		}
270 75
		$this->parent = $parent;
271 75
		return $this;
272
	}
273
}