Passed
Push — snakListArray ( c5b802 )
by no
02:24
created

SnakList::append()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 3
ccs 0
cts 0
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 2
1
<?php
2
3
namespace Wikibase\DataModel\Snak;
4
5
use Comparable;
6
use Countable;
7
use Hashable;
8
use InvalidArgumentException;
9
use Iterator;
10
use Serializable;
11
use Traversable;
12
use Wikibase\DataModel\Internal\MapValueHasher;
13
14
/**
15
 * List of Snak objects.
16
 * Indexes the snaks by hash and ensures no more than one snak with the same hash is in the list.
17
 *
18
 * @since 0.1
19
 *
20
 * @license GPL-2.0+
21
 * @author Jeroen De Dauw < [email protected] >
22
 * @author Addshore
23
 */
24
class SnakList implements Comparable, Countable, Hashable, Iterator, Serializable {
25
26
	/**
27
	 * @var Snak[]
28
	 */
29
	private $snaks = [];
30
31
	/**
32
	 * @param Snak[]|Traversable $snaks
33
	 *
34
	 * @throws InvalidArgumentException
35
	 */
36
	public function __construct( $snaks = [] ) {
37
		if ( !is_array( $snaks ) && !( $snaks instanceof Traversable ) ) {
38
			throw new InvalidArgumentException( '$snaks must be an array or an instance of Traversable' );
39
		}
40
41
		foreach ( $snaks as $value ) {
42
			if ( !( $value instanceof Snak ) ) {
43
				throw new InvalidArgumentException( '$value must be a Snak' );
44
			}
45
46
			$this->addSnak( $value );
47
		}
48
	}
49
50
	/**
51
	 * @since 0.1
52
	 *
53
	 * @param string $snakHash
54
	 *
55
	 * @return boolean
56
	 */
57
	public function hasSnakHash( $snakHash ) {
58
		return isset( $this->snaks[$snakHash] );
59
	}
60
61
	/**
62
	 * @since 0.1
63
	 *
64
	 * @param string $snakHash
65
	 */
66
	public function removeSnakHash( $snakHash ) {
67
		unset( $this->snaks[$snakHash] );
68
	}
69
70
	/**
71
	 * @since 0.1
72
	 *
73
	 * @param Snak $snak
74
	 *
75
	 * @return boolean Indicates if the snak was added or not.
76
	 */
77
	public function addSnak( Snak $snak ) {
78
		$hash = $snak->getHash();
79
80
		if ( $this->hasSnakHash( $hash ) ) {
81
			return false;
82
		}
83
84
		$this->snaks[$hash] = $snak;
85
		return true;
86
	}
87
88
	/**
89
	 * @since 0.1
90
	 *
91
	 * @param Snak $snak
92
	 *
93
	 * @return boolean
94
	 */
95
	public function hasSnak( Snak $snak ) {
96
		return $this->hasSnakHash( $snak->getHash() );
97
	}
98
99
	/**
100
	 * @since 0.1
101
	 *
102
	 * @param Snak $snak
103
	 */
104
	public function removeSnak( Snak $snak ) {
105
		$this->removeSnakHash( $snak->getHash() );
106
	}
107
108
	/**
109
	 * @since 0.1
110
	 *
111
	 * @param string $snakHash
112
	 *
113
	 * @return Snak|bool
114
	 */
115
	public function getSnak( $snakHash ) {
116
		return isset( $this->snaks[$snakHash] ) ? $this->snaks[$snakHash] : false;
117
	}
118
119
	/**
120
	 * @see Comparable::equals
121
	 *
122
	 * The comparison is done purely value based, ignoring the order of the elements in the array.
123
	 *
124
	 * @since 0.3
125
	 *
126
	 * @param mixed $target
127
	 *
128
	 * @return bool
129
	 */
130
	public function equals( $target ) {
131
		if ( $this === $target ) {
132
			return true;
133
		}
134
135
		return $target instanceof self
136
			&& $this->getHash() === $target->getHash();
137
	}
138
139
	/**
140
	 * @return int
141
	 */
142
	public function count() {
143
		return count( $this->snaks );
144
	}
145
146
	/**
147
	 * @see Hashable::getHash
148
	 *
149
	 * The hash is purely value based. Order of the elements in the array is not held into account.
150
	 *
151
	 * @since 0.1
152
	 *
153
	 * @return string
154
	 */
155
	public function getHash() {
156
		$hasher = new MapValueHasher();
157
		return $hasher->hash( $this->snaks );
158
	}
159
160
	/**
161
	 * Groups snaks by property, and optionally orders them.
162
	 *
163
	 * @param string[] $order List of property ID strings to order by. Snaks with other properties
164
	 *  will also be grouped, but put at the end, in the order each property appeared first in the
165
	 *  original list.
166
	 *
167
	 * @since 0.5
168
	 */
169
	public function orderByProperty( array $order = [] ) {
170
		$byProperty = array_fill_keys( $order, [] );
171
172
		foreach ( $this->snaks as $snak ) {
173
			$byProperty[$snak->getPropertyId()->getSerialization()][$snak->getHash()] = $snak;
174
		}
175
176
		$this->snaks = [];
177
		foreach ( $byProperty as $snaks ) {
178
			$this->snaks = array_merge( $this->snaks, $snaks );
0 ignored issues
show
Documentation Bug introduced by
It seems like array_merge($this->snaks, $snaks) of type array is incompatible with the declared type array<integer,object<Wik...e\DataModel\Snak\Snak>> of property $snaks.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
179
		}
180
	}
181
182
	/**
183
	 * @see Serializable::serialize
184
	 *
185
	 * @return string
186
	 */
187
	public function serialize() {
188
		return serialize( [
189
			'data' => array_values( $this->snaks ),
190
			'index' => count( $this->snaks ) - 1,
191
		] );
192
	}
193
194
	/**
195
	 * @see Serializable::unserialize
196
	 *
197
	 * @param string $serialized
198
	 */
199
	public function unserialize( $serialized ) {
200
		$serializationData = unserialize( $serialized );
201
		$this->snaks = [];
202
		foreach ( $serializationData['data'] as $snak ) {
203
			$this->addSnak( $snak );
204
		}
205
	}
206
207
	/**
208
	 * Returns if the ArrayObject has no elements.
209
	 *
210
	 * @return bool
211
	 */
212
	public function isEmpty() {
213
		return $this->snaks === [];
214
	}
215
216
	public function current() {
217
		return current( $this->snaks );
218
	}
219
220
	public function next() {
221
		return next( $this->snaks );
222
	}
223
224
	public function key() {
225
		return key( $this->snaks );
226
	}
227
228
	public function valid() {
229
		return current( $this->snaks ) !== false;
230
	}
231
232
	public function rewind() {
233
		return reset( $this->snaks );
234
	}
235
236
}
237