Passed
Push — master ( 8e4c14...93bf08 )
by smiley
06:58
created

NodeList::key()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 2
ccs 0
cts 0
cp 0
rs 10
cc 1
nc 1
nop 0
crap 2
1
<?php
2
/**
3
 * Class NodeList
4
 *
5
 * @filesource   NodeList.php
6
 * @created      09.05.2017
7
 * @package      chillerlan\PrototypeDOM
8
 * @author       Smiley <[email protected]>
9
 * @copyright    2017 Smiley
10
 * @license      MIT
11
 */
12
13
namespace chillerlan\PrototypeDOM;
14
15
use chillerlan\PrototypeDOM\Node\PrototypeNode;
16
use ArrayAccess, Countable, DOMNode, DOMNodeList, Exception, OutOfBoundsException, SeekableIterator;
17
18
use function array_column, array_key_exists, array_merge, array_reverse, call_user_func_array, count,
19
	is_callable, is_int, is_iterable, iterator_to_array;
20
21
22
class NodeList implements PrototypeEnumerable, SeekableIterator, ArrayAccess, Countable{
23
24
	protected array $array = [];
25
26
	protected int $offset = 0;
27
28
	/**
29
	 * NodeList constructor.
30
	 */
31
	public function __construct(iterable $nodes = null){
32
33
		if($nodes instanceof DOMNodeList){
34
			$this->array = iterator_to_array($nodes);
35
		}
36
		elseif($nodes instanceof NodeList){
37
			$this->array = $nodes->toArray();
38
		}
39
		elseif(is_iterable($nodes)){
40
			foreach($nodes as $node){
41
				if($node instanceof DOMNode || $node instanceof PrototypeNode){
42
					$this->array[] = $node;
43
				}
44
			}
45
		}
46
47
	}
48
49
50
	/***********
51
	 * generic *
52
	 ***********/
53
54
	/**
55
	 *
56
	 */
57 43
	public function match(DOMNode $node):bool{
58
		/** @var \chillerlan\PrototypeDOM\Node\Element $element */
59 43
		foreach($this->array as $element){
60 42
61
			if($element->isSameNode($node)){
62
				return true;
63 43
			}
64
65
		}
66
67
		return false;
68
	}
69
70
	/**
71
	 *
72
	 */
73 2
	public function merge(NodeList $nodelist):NodeList{
74 2
		$this->array = array_merge($this->array, $nodelist->toArray());
75
76
		return $this;
77
	}
78
79
	/**
80
	 *
81
	 */
82
	public function inspect(bool $xml = false):string{
83
		return (new Document($this, $xml))->inspect(null, $xml);
84
	}
85
86
	/*************
87 1
	 * Countable *
88
	 *************/
89 1
90
	/**
91 1
	 * @link https://www.php.net/manual/countable.count.php
92 1
	 * @inheritdoc
93
	 */
94
	public function count():int{
95
		return count($this->array);
96
	}
97 1
98
	/************
99
	 * Iterator *
100
	 ************/
101
102
	/**
103
	 * @link https://www.php.net/manual/iterator.current.php
104
	 * @inheritdoc
105 7
	 * @return \DOMNode|\chillerlan\PrototypeDOM\Node\PrototypeHTMLElement|null
106 7
	 */
107
	public function current():?DOMNode{
108
		return $this->array[$this->offset] ?? null;
109
	}
110
111
	/**
112
	 * @link https://www.php.net/manual/iterator.next.php
113
	 * @inheritdoc
114 1
	 */
115 1
	public function next():void{
116
		$this->offset++;
117 1
	}
118
119
	/**
120
	 * @link https://www.php.net/manual/iterator.key.php
121
	 * @inheritdoc
122
	 */
123
	public function key():int{
124
		return $this->offset;
125 2
	}
126 2
127
	/**
128
	 * @link https://www.php.net/manual/iterator.valid.php
129
	 * @inheritdoc
130
	 */
131
	public function valid():bool{
132
		return array_key_exists($this->offset, $this->array);
133
	}
134
135
	/**
136
	 * @link https://www.php.net/manual/iterator.rewind.php
137
	 * @inheritdoc
138
	 */
139 42
	public function rewind():void{
140
		$this->offset = 0;
141 42
	}
142
143 42
	/********************
144 1
	 * SeekableIterator *
145
	 ********************/
146
147 41
	/**
148
	 * @link https://www.php.net/manual/seekableiterator.seek.php
149
	 * @inheritdoc
150
	 */
151
	public function seek($pos):void{
152 42
		$this->rewind();
153
154
		for( ; $this->offset < $pos; ){
155
156
			if(!\next($this->array)) {
157
				throw new OutOfBoundsException('invalid seek position: '.$pos);
158
			}
159
160
			$this->offset++;
161
		}
162
163
	}
164
165
	/***************
166
	 * ArrayAccess *
167
	 ***************/
168
169
	/**
170
	 * @link https://www.php.net/manual/arrayaccess.offsetexists.php
171
	 * @inheritdoc
172
	 */
173
	public function offsetExists($offset):bool{
174
		return array_key_exists($offset, $this->array);
175
	}
176
177
	/**
178
	 * @link https://www.php.net/manual/arrayaccess.offsetget.php
179
	 * @inheritdoc
180
	 * @return \DOMNode|\chillerlan\PrototypeDOM\Node\PrototypeHTMLElement|null
181
	 */
182
	public function offsetGet($offset):?DOMNode{
183
		return $this->array[$offset] ?? null;
184
	}
185
186
	/**
187
	 * @link https://www.php.net/manual/arrayaccess.offsetset.php
188
	 * @inheritdoc
189
	 */
190
	public function offsetSet($offset, $value):void{
191
192
		if($value instanceof DOMNode){
193
194
			is_int($offset)
195
				? $this->array[$offset] = $value
196
				: $this->array[] = $value;
197
198
		}
199
200
	}
201
202
	/**
203
	 * @link https://www.php.net/manual/arrayaccess.offsetunset.php
204
	 * @inheritdoc
205
	 */
206
	public function offsetUnset($offset):void{
207
		unset($this->array[$offset]);
208
	}
209
210
	/*************
211
	 * Prototype *
212
	 *************/
213
214
	/**
215
	 * @inheritDoc
216
	 * @return \DOMNode|\chillerlan\PrototypeDOM\Node\PrototypeHTMLElement|null
217
	 */
218
	public function first():?DOMNode{
219
		return $this->array[0] ?? null;
220
	}
221
222
	/**
223
	 * @inheritDoc
224
	 * @return \DOMNode|\chillerlan\PrototypeDOM\Node\PrototypeHTMLElement|null
225
	 */
226
	public function last():?DOMNode{
227
		return $this->array[count($this->array) - 1] ?? null;
228
	}
229
230
	/**
231
	 * @inheritDoc
232
	 */
233
	public function pluck(string $property):array{
234
		return array_column($this->array, $property);
235
	}
236
237
	/**
238
	 * @inheritDoc
239
	 */
240
	public function reverse():NodeList{
241
		$this->array  = array_reverse($this->array);
242
		$this->offset = 0;
243
244
		return $this;
245
	}
246
247
	/**
248
	 * @inheritDoc
249
	 */
250
	public function toArray():array{
251
		return $this->array;
252
	}
253
254
	/**
255
	 * @inheritDoc
256
	 */
257
	public function each($callback){
258
		$this->map($callback);
259
260
		return $this;
261
	}
262
263
	/**
264
	 * @inheritDoc
265
	 */
266
	public function map($callback):array {
267
268
		if(!is_callable($callback)){
269
			throw new Exception('invalid callback');
270
		}
271
272
		$return = [];
273
274
		foreach($this->array as $index => $element){
275
			$return[$index] = call_user_func_array($callback, [$element, $index]);
276
		}
277
278
		return $return;
279
	}
280
281
	/**
282
	 * @inheritDoc
283
	 */
284
	public function clear():NodeList{
285
		$this->array  = [];
286
		$this->offset = 0;
287
288
		return $this;
289
	}
290
291
	/**
292
	 * @inheritDoc
293
	 * @throws \Exception
294
	 */
295
	public function findAll($callback):array{
296
297
		if(!is_callable($callback)){
298
			throw new Exception('invalid callback');
299
		}
300
301
		$return = [];
302
303
		foreach($this->array as $index => $element){
304
305
			if(call_user_func_array($callback, [$element, $index]) === true){
306
				$return[] = $element;
307
			}
308
309
		}
310
311
		return $return;
312
	}
313
314
	/**
315
	 * @inheritDoc
316
	 * @throws \Exception
317
	 */
318
	public function reject($callback):array{
319
320
		if(!is_callable($callback)){
321
			throw new Exception('invalid callback');
322
		}
323
324
		$return = [];
325
326
		foreach($this->array as $index => $element){
327
328
			if(call_user_func_array($callback, [$element, $index]) !== true){
329
				$return[] = $element;
330
			}
331
332
		}
333
334
		return $return;
335
	}
336
337
}
338