Passed
Push — master ( c7b7b3...d0017a )
by Daniel
07:28
created

StatementList::clear()   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
c 0
b 0
f 0
dl 0
loc 3
ccs 0
cts 0
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 2
1
<?php
2
3
namespace Wikibase\DataModel\Statement;
4
5
use ArrayIterator;
6
use Comparable;
7
use Countable;
8
use InvalidArgumentException;
9
use IteratorAggregate;
10
use Traversable;
11
use Wikibase\DataModel\Entity\PropertyId;
12
use Wikibase\DataModel\Reference;
13
use Wikibase\DataModel\ReferenceList;
14
use Wikibase\DataModel\Snak\Snak;
15
use Wikibase\DataModel\Snak\SnakList;
16
17
/**
18
 * Ordered and non-unique collection of Statement objects.
19
 * Provides various filter operations.
20
 *
21
 * Does not do any indexing by default.
22
 * Does not provide complex modification functionality.
23
 *
24
 * @since 1.0
25
 *
26
 * @license GPL-2.0+
27
 * @author Jeroen De Dauw < [email protected] >
28
 * @author Bene* < [email protected] >
29
 * @author Thiemo Mättig
30
 */
31
class StatementList implements IteratorAggregate, Comparable, Countable {
32
33
	/**
34
	 * @var Statement[]
35
	 */
36
	private $statements = [];
37
38
	/**
39
	 * @param Statement[]|Traversable|Statement $statements
40
	 * @param Statement [$statement2,...]
41
	 *
42
	 * @throws InvalidArgumentException
43 50
	 */
44 50
	public function __construct( $statements = [] /*...*/ ) {
45 32
		if ( $statements instanceof Statement ) {
46 32
			$statements = func_get_args();
47
		}
48 50
49 1
		if ( !is_array( $statements ) && !( $statements instanceof Traversable ) ) {
50
			throw new InvalidArgumentException( '$statements must be an array or an instance of Traversable' );
51
		}
52 49
53 38
		foreach ( $statements as $statement ) {
54 2
			if ( !( $statement instanceof Statement ) ) {
55
				throw new InvalidArgumentException( 'Every element in $statements must be an instance of Statement' );
56
			}
57 38
58 49
			$this->statements[] = $statement;
59 47
		}
60
	}
61
62
	/**
63
	 * Returns the property ids used by the statements.
64
	 * The keys of the returned array hold the serializations of the property ids.
65
	 *
66
	 * @return PropertyId[] Array indexed by property id serialization.
67 2
	 */
68 2
	public function getPropertyIds() {
69
		$propertyIds = [];
70 2
71 1
		foreach ( $this->statements as $statement ) {
72 2
			$propertyIds[$statement->getPropertyId()->getSerialization()] = $statement->getPropertyId();
73
		}
74 2
75
		return $propertyIds;
76
	}
77 11
78 11
	/**
79 11
	 * @since 1.0, setting an index is supported since 6.1
80
	 * @see ReferenceList::addReference
81
	 *
82
	 * @param Statement $statement
83
	 * @param int|null $index New position of the added statement, or null to append.
84
	 *
85
	 * @throws InvalidArgumentException
86
	 */
87 7
	public function addStatement( Statement $statement, $index = null ) {
88 7
		if ( $index === null ) {
89 7
			$this->statements[] = $statement;
90
		} elseif ( is_int( $index ) && $index >= 0 ) {
91 7
			array_splice( $this->statements, $index, 0, [ $statement ] );
92 7
		} else {
93
			throw new InvalidArgumentException( '$index must be a non-negative integer or null' );
94 7
		}
95 7
	}
96
97
	/**
98
	 * @param Snak $mainSnak
99
	 * @param Snak[]|SnakList|null $qualifiers
100
	 * @param Reference[]|ReferenceList|null $references
101
	 * @param string|null $guid
102 4
	 */
103 4
	public function addNewStatement( Snak $mainSnak, $qualifiers = null, $references = null, $guid = null ) {
104 4
		$qualifiers = is_array( $qualifiers ) ? new SnakList( $qualifiers ) : $qualifiers;
105 3
		$references = is_array( $references ) ? new ReferenceList( $references ) : $references;
106 3
107 4
		$statement = new Statement( $mainSnak, $qualifiers, $references );
108
		$statement->setGuid( $guid );
109 4
110 4
		$this->statements[] = $statement;
111
	}
112
113
	/**
114
	 * @since 3.0
115
	 *
116
	 * @param string|null $guid
117
	 */
118
	public function removeStatementsWithGuid( $guid ) {
119
		foreach ( $this->statements as $index => $statement ) {
120 1
			if ( $statement->getGuid() === $guid ) {
121 1
				unset( $this->statements[$index] );
122
			}
123 1
		}
124 1
125 1
		$this->statements = array_values( $this->statements );
126
	}
127 1
128
	/**
129
	 * Statements that have a main snak already in the list are filtered out.
130
	 * The last occurrences are retained.
131
	 *
132
	 * @since 1.0
133
	 *
134
	 * @return self
135
	 */
136
	public function getWithUniqueMainSnaks() {
137 2
		$statements = [];
138 2
139
		foreach ( $this->statements as $statement ) {
140 2
			$statements[$statement->getMainSnak()->getHash()] = $statement;
141 2
		}
142 1
143 1
		return new self( $statements );
144 2
	}
145
146 2
	/**
147
	 * @since 3.0
148
	 *
149
	 * @param PropertyId $id
150
	 *
151
	 * @return self
152
	 */
153
	public function getByPropertyId( PropertyId $id ) {
154
		$statementList = new self();
155
156 6
		foreach ( $this->statements as $statement ) {
157 6
			if ( $statement->getPropertyId()->equals( $id ) ) {
158 6
				$statementList->statements[] = $statement;
159
			}
160 6
		}
161 4
162 3
		return $statementList;
163 3
	}
164 6
165
	/**
166 6
	 * @since 3.0
167
	 *
168
	 * @param int|int[] $acceptableRanks
169
	 *
170
	 * @return self
171
	 */
172
	public function getByRank( $acceptableRanks ) {
173
		$acceptableRanks = array_flip( (array)$acceptableRanks );
174
		$statementList = new self();
175
176
		foreach ( $this->statements as $statement ) {
177
			if ( array_key_exists( $statement->getRank(), $acceptableRanks ) ) {
178 4
				$statementList->statements[] = $statement;
179 4
			}
180
		}
181 4
182 1
		return $statementList;
183
	}
184
185 3
	/**
186
	 * Returns the so called "best statements".
187
	 * If there are preferred statements, then this is all the preferred statements.
188
	 * If there are no preferred statements, then this is all normal statements.
189
	 *
190
	 * @since 2.4
191
	 *
192
	 * @return self
193
	 */
194
	public function getBestStatements() {
195
		$statements = $this->getByRank( Statement::RANK_PREFERRED );
196
197
		if ( !$statements->isEmpty() ) {
198
			return $statements;
199 1
		}
200 1
201
		return $this->getByRank( Statement::RANK_NORMAL );
202 1
	}
203 1
204 1
	/**
205 1
	 * Returns a list of all Snaks on this StatementList. This includes at least the main snaks of
206 1
	 * all statements, the snaks from qualifiers, and the snaks from references.
207
	 *
208 1
	 * This is a convenience method for use in code that needs to operate on all snaks, e.g.
209
	 * to find all referenced Entities.
210
	 *
211
	 * @since 1.1
212
	 *
213
	 * @return Snak[] Numerically indexed (non-sparse) array.
214
	 */
215
	public function getAllSnaks() {
216 1
		$snaks = [];
217 1
218
		foreach ( $this->statements as $statement ) {
219 1
			foreach ( $statement->getAllSnaks() as $snak ) {
220 1
				$snaks[] = $snak;
221 1
			}
222
		}
223 1
224
		return $snaks;
225
	}
226
227
	/**
228
	 * @since 2.3
229 1
	 *
230 1
	 * @return Snak[] Numerically indexed (non-sparse) array.
231
	 */
232
	public function getMainSnaks() {
233
		$snaks = [];
234
235
		foreach ( $this->statements as $statement ) {
236 4
			$snaks[] = $statement->getMainSnak();
237 4
		}
238
239
		return $snaks;
240
	}
241
242
	/**
243
	 * @return Traversable|Statement[]
244
	 */
245 12
	public function getIterator() {
246 12
		return new ArrayIterator( $this->statements );
247
	}
248
249
	/**
250
	 * @return Statement[] Numerically indexed (non-sparse) array.
251
	 */
252
	public function toArray() {
253
		return $this->statements;
254
	}
255
256 8
	/**
257 8
	 * @see Countable::count
258
	 *
259
	 * @return int
260
	 */
261 8
	public function count() {
262 8
		return count( $this->statements );
263 8
	}
264 2
265
	/**
266
	 * @see Comparable::equals
267 6
	 *
268
	 * @param mixed $target
269
	 *
270 6
	 * @return bool
271 6
	 */
272
	public function equals( $target ) {
273 6
		if ( $this === $target ) {
274 5
			return true;
275 3
		}
276
277
		if ( !( $target instanceof self )
278 5
			|| $this->count() !== $target->count()
279 6
		) {
280
			return false;
281 3
		}
282
283
		return $this->statementsEqual( $target->statements );
284
	}
285
286
	private function statementsEqual( array $statements ) {
287 6
		reset( $statements );
288 6
289
		foreach ( $this->statements as $statement ) {
290
			if ( !$statement->equals( current( $statements ) ) ) {
291
				return false;
292
			}
293
294
			next( $statements );
295
		}
296
297
		return true;
298
	}
299 5
300 5
	/**
301 3
	 * @return bool
302 3
	 */
303
	public function isEmpty() {
304 4
		return empty( $this->statements );
305
	}
306 2
307
	/**
308
	 * @since 3.0
309
	 * @see StatementByGuidMap
310
	 *
311
	 * @param string|null $statementGuid
312
	 *
313
	 * @return Statement|null The first statement with the given GUID or null if not found.
314
	 */
315
	public function getFirstStatementWithGuid( $statementGuid ) {
316 1
		foreach ( $this->statements as $statement ) {
317 1
			if ( $statement->getGuid() === $statementGuid ) {
318
				return $statement;
319 1
			}
320 1
		}
321 1
322 1
		return null;
323 1
	}
324
325 1
	/**
326
	 * @since 4.1
327
	 *
328
	 * @param StatementFilter $filter
329
	 *
330
	 * @return self
331
	 */
332
	public function filter( StatementFilter $filter ) {
333
		$statementList = new self();
334
335
		foreach ( $this->statements as $statement ) {
336
			if ( $filter->statementMatches( $statement ) ) {
337
				$statementList->statements[] = $statement;
338
			}
339
		}
340
341
		return $statementList;
342
	}
343
344
	/**
345
	 * Removes all statements from this list.
346
	 *
347
	 * @since 6.0
348
	 */
349
	public function clear() {
350
		$this->statements = [];
351
	}
352
353
	/**
354
	 * @see http://php.net/manual/en/language.oop5.cloning.php
355
	 *
356
	 * @since 5.1
357
	 */
358
	public function __clone() {
359
		foreach ( $this->statements as &$statement ) {
360
			$statement = clone $statement;
361
		}
362
	}
363
364
}
365