Passed
Push — master ( 9afa79...f29488 )
by smiley
01:58
created

PrototypeTraversalTrait::match()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
c 0
b 0
f 0
rs 10
cc 1
nc 1
nop 1
1
<?php
2
/**
3
 * Trait PrototypeTraversalTrait
4
 *
5
 * @filesource   PrototypeTraversalTrait.php
6
 * @created      06.05.2017
7
 * @package      chillerlan\PrototypeDOM\Traits
8
 * @author       Smiley <[email protected]>
9
 * @copyright    2017 Smiley
10
 * @license      MIT
11
 */
12
13
namespace chillerlan\PrototypeDOM\Node;
14
15
use chillerlan\PrototypeDOM\NodeList;
16
use DOMNode;
17
18
/**
19
 * @property \chillerlan\PrototypeDOM\Document $ownerDocument
20
 */
21
trait PrototypeTraversalTrait{
22
	use PrototypeNodeTrait;
23
24
	/**
25
	 * @param        $selector
26
	 * @param        $index
27
	 * @param string $property
28
	 * @param int    $nodeType https://secure.php.net/manual/dom.constants.php
29
	 *
30
	 * @return \chillerlan\PrototypeDOM\Node\PrototypeTraversal|\DOMNode|null
31
	 */
32
	public function recursivelyFind($selector, int $index = null, string $property = null, int $nodeType = \XML_ELEMENT_NODE):?PrototypeTraversal{
33
34
		if(\is_numeric($selector)){
35
			return $this->ownerDocument->recursivelyFind($this, $property, null, $selector, $nodeType);
36
		}
37
38
		return $this->ownerDocument->recursivelyFind($this, $property, $selector, $index ?? 0, $nodeType);
39
	}
40
41
	/**
42
	 * @link http://api.prototypejs.org/dom/Element/select/
43
	 *
44
	 * @param array $selectors
45
	 *
46
	 * @return \chillerlan\PrototypeDOM\NodeList
47
	 */
48
	public function select(array $selectors = null):NodeList{
49
		return $this->ownerDocument->select($selectors, $this, 'descendant::');
50
	}
51
52
	/**
53
	 * @link http://api.prototypejs.org/dom/Element/match/
54
	 *
55
	 * @param string $selector
56
	 *
57
	 * @return bool
58
	 */
59
	public function match(string $selector):bool{
60
		return $this->ownerDocument->match($this, $selector);
61
	}
62
63
	/**
64
	 * @link http://api.prototypejs.org/dom/Element/down/
65
	 *
66
	 * @param null $expression
67
	 * @param int  $index
68
	 *
69
	 * @return \chillerlan\PrototypeDOM\Node\PrototypeTraversal|null
70
	 */
71
	public function down($expression = null, int $index = null):?PrototypeTraversal{
72
73
		if($expression === null && $index === null){
74
			return $this->firstDescendant();
75
		}
76
77
		$index = $index ?? 0;
78
79
		if(\is_int($expression)){
80
			return $this->select(['*'])->item($expression);
81
		}
82
83
		if(\is_array($expression)){
84
			return $this->select($expression)->item($index);
85
		}
86
87
		return $this->select([$expression])->item($index);
88
	}
89
90
	/**
91
	 * @link http://api.prototypejs.org/dom/Element/up/
92
	 *
93
	 * @param string|null $expression
94
	 * @param int|null    $index
95
	 *
96
	 * @return \chillerlan\PrototypeDOM\Node\PrototypeTraversal|null
97
	 */
98
	public function up($expression = null, int $index = null):?PrototypeTraversal{
99
		return $this->recursivelyFind($expression, $index, 'parentNode');
100
	}
101
102
	/**
103
	 * @link http://api.prototypejs.org/dom/Element/previous/
104
	 *
105
	 * @param string|null $expression
106
	 * @param int|null    $index
107
	 *
108
	 * @return \chillerlan\PrototypeDOM\Node\PrototypeTraversal|null
109
	 */
110
	public function previous($expression = null, int $index = null):?PrototypeTraversal{
111
		return $this->recursivelyFind($expression, $index, 'previousSibling');
112
	}
113
114
	/**
115
	 * @link http://api.prototypejs.org/dom/Element/next/
116
	 *
117
	 * @param string|null $expression
118
	 * @param int|null    $index
119
	 *
120
	 * @return \chillerlan\PrototypeDOM\Node\PrototypeTraversal|null
121
	 */
122
	public function next($expression = null, int $index = null):?PrototypeTraversal{
123
		return $this->recursivelyFind($expression, $index, 'nextSibling');
124
	}
125
126
	/**
127
	 * @link http://api.prototypejs.org/dom/Element/childElements/
128
	 *
129
	 * @param int $nodeType https://secure.php.net/manual/dom.constants.php
130
	 *
131
	 * @return \chillerlan\PrototypeDOM\NodeList
132
	 */
133
	public function childElements(int $nodeType = \XML_ELEMENT_NODE):NodeList{
134
		$children = new NodeList;
135
136
		if(!$this->hasChildNodes()){
0 ignored issues
show
Bug introduced by
It seems like hasChildNodes() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
137
			return $children;
138
		}
139
140
		foreach($this->childNodes as $child){
141
142
			if($child->nodeType === $nodeType){
143
				$children[] = $child;
144
			}
145
146
		}
147
148
		return $children;
149
	}
150
151
	/**
152
	 * @link http://api.prototypejs.org/dom/Element/descendantOf/
153
	 *
154
	 * @param \DOMNode $ancestor
155
	 *
156
	 * @return bool
157
	 */
158
	public function descendantOf(DOMNode $ancestor):bool{
159
		return $this->ancestors()->match($ancestor);
160
	}
161
162
	/**
163
	 * @link http://api.prototypejs.org/dom/Element/ancestors/
164
	 *
165
	 * @return \chillerlan\PrototypeDOM\NodeList
166
	 */
167
	public function ancestors():NodeList{
168
		return $this->recursivelyCollect('parentNode');
169
	}
170
171
	/**
172
	 * @link http://api.prototypejs.org/dom/Element/siblings/
173
	 *
174
	 * @return \chillerlan\PrototypeDOM\NodeList
175
	 */
176
	public function siblings():NodeList{
177
		return $this->previousSiblings()->reverse()->merge($this->nextSiblings());
178
	}
179
180
	/**
181
	 * @link http://api.prototypejs.org/dom/Element/descendants/
182
	 *
183
	 * @return \chillerlan\PrototypeDOM\NodeList
184
	 */
185
	public function descendants():NodeList{
186
		return $this->select();
187
	}
188
189
	/**
190
	 * @link http://api.prototypejs.org/dom/Element/firstDescendant/
191
	 *
192
	 * @return \chillerlan\PrototypeDOM\Node\PrototypeTraversal|null
193
	 */
194
	public function firstDescendant():?PrototypeTraversal{
195
		return $this->descendants()->first();
196
	}
197
198
	/**
199
	 * @link http://api.prototypejs.org/dom/Element/previousSiblings/
200
	 *
201
	 * @return \chillerlan\PrototypeDOM\NodeList
202
	 */
203
	public function previousSiblings():NodeList{
204
		return $this->recursivelyCollect('previousSibling');
205
	}
206
207
	/**
208
	 * @link http://api.prototypejs.org/dom/Element/nextSiblings/
209
	 *
210
	 * @return \chillerlan\PrototypeDOM\NodeList
211
	 */
212
	public function nextSiblings():NodeList{
213
		return $this->recursivelyCollect('nextSibling');
214
	}
215
216
}
217