Test Failed
Push — master ( 9cf31c...ad793d )
by smiley
03:41
created

TraversalTrait::down()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 18
c 0
b 0
f 0
rs 9.3554
cc 5
nc 4
nop 2
1
<?php
2
/**
3
 * Trait TraversalTrait
4
 *
5
 * @filesource   TraversalTrait.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 TraversalTrait{
22
23
	/**
24
	 * @param        $selector
25
	 * @param        $index
26
	 * @param string $property
27
	 * @param int    $nodeType https://secure.php.net/manual/dom.constants.php
28
	 *
29
	 * @return \chillerlan\PrototypeDOM\Node\PrototypeNode|null
30
	 */
31
	public function recursivelyFind($selector, int $index = null, string $property = null, int $nodeType = \XML_ELEMENT_NODE):?PrototypeNode{
32
33
		if(\is_numeric($selector)){
34
			return $this->ownerDocument->recursivelyFind($this, $property, null, $selector, $nodeType);
35
		}
36
37
		return $this->ownerDocument->recursivelyFind($this, $property, $selector, $index ?? 0, $nodeType);
38
	}
39
40
	/**
41
	 * @link http://api.prototypejs.org/dom/Element/select/
42
	 *
43
	 * @param array $selectors
44
	 *
45
	 * @return \chillerlan\PrototypeDOM\NodeList
46
	 */
47
	public function select(array $selectors = null):NodeList{
48
		return $this->ownerDocument->select($selectors, $this, 'descendant::');
49
	}
50
51
	/**
52
	 * @link http://api.prototypejs.org/dom/Element/match/
53
	 *
54
	 * @param string $selector
55
	 *
56
	 * @return bool
57
	 */
58
	public function match(string $selector):bool{
59
		return $this->ownerDocument->match($this, $selector);
60
	}
61
62
	/**
63
	 * @link http://api.prototypejs.org/dom/Element/down/
64
	 *
65
	 * @param null $expression
66
	 * @param int  $index
67
	 *
68
	 * @return \chillerlan\PrototypeDOM\Node\PrototypeNode|null
69
	 */
70
	public function down($expression = null, int $index = null):?PrototypeNode{
71
72
		if($expression === null && $index === null){
73
			return $this->firstDescendant();
74
		}
75
76
		$index = $index ?? 0;
77
78
		if(\is_int($expression)){
79
			return $this->select(['*'])->item($expression);
80
		}
81
82
		if(\is_array($expression)){
83
			return $this->select($expression)->item($index);
84
		}
85
86
		return $this->select([$expression])->item($index);
87
	}
88
89
	/**
90
	 * @link http://api.prototypejs.org/dom/Element/up/
91
	 *
92
	 * @param string|null $expression
93
	 * @param int|null    $index
94
	 *
95
	 * @return \chillerlan\PrototypeDOM\Node\PrototypeNode|null
96
	 */
97
	public function up($expression = null, int $index = null):?PrototypeNode{
98
		return $this->recursivelyFind($expression, $index, 'parentNode');
99
	}
100
101
	/**
102
	 * @link http://api.prototypejs.org/dom/Element/previous/
103
	 *
104
	 * @param string|null $expression
105
	 * @param int|null    $index
106
	 *
107
	 * @return \chillerlan\PrototypeDOM\Node\PrototypeNode|null
108
	 */
109
	public function previous($expression = null, int $index = null):?PrototypeNode{
110
		return $this->recursivelyFind($expression, $index, 'previousSibling');
111
	}
112
113
	/**
114
	 * @link http://api.prototypejs.org/dom/Element/next/
115
	 *
116
	 * @param string|null $expression
117
	 * @param int|null    $index
118
	 *
119
	 * @return \chillerlan\PrototypeDOM\Node\PrototypeNode|null
120
	 */
121
	public function next($expression = null, int $index = null):?PrototypeNode{
122
		return $this->recursivelyFind($expression, $index, 'nextSibling');
123
	}
124
125
	/**
126
	 * @link http://api.prototypejs.org/dom/Element/childElements/
127
	 *
128
	 * @param int $nodeType https://secure.php.net/manual/dom.constants.php
129
	 *
130
	 * @return \chillerlan\PrototypeDOM\NodeList
131
	 */
132
	public function childElements(int $nodeType = \XML_ELEMENT_NODE):NodeList{
133
		$children = new NodeList;
134
135
		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...
136
			return $children;
137
		}
138
139
		foreach($this->childNodes as $child){
0 ignored issues
show
Bug introduced by
The property childNodes does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

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