Completed
Pull Request — master (#666)
by no
10:55 queued 07:27
created

StatementList::isEmpty()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1
Metric Value
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
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 = array();
37
38
	/**
39
	 * @param Statement[]|Traversable|Statement $statements
40
	 * @param Statement [$statement2,...]
41
	 *
42
	 * @throws InvalidArgumentException
43 50
	 */
44 50
	public function __construct( $statements = array() /*...*/ ) {
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 = array();
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, array( $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
	 * @deprecated since 6.1, use getMainSnaks instead
134
	 *
135
	 * @return self
136
	 */
137 2
	public function getWithUniqueMainSnaks() {
138 2
		$statements = array();
139
140 2
		foreach ( $this->statements as $statement ) {
141 2
			$statements[$statement->getMainSnak()->getHash()] = $statement;
142 1
		}
143 1
144 2
		return new self( $statements );
145
	}
146 2
147
	/**
148
	 * @since 3.0
149
	 *
150
	 * @param PropertyId $id
151
	 *
152
	 * @return self
153
	 */
154
	public function getByPropertyId( PropertyId $id ) {
155
		$statementList = new self();
156 6
157 6
		foreach ( $this->statements as $statement ) {
158 6
			if ( $statement->getPropertyId()->equals( $id ) ) {
159
				$statementList->statements[] = $statement;
160 6
			}
161 4
		}
162 3
163 3
		return $statementList;
164 6
	}
165
166 6
	/**
167
	 * @since 3.0
168
	 *
169
	 * @param int|int[] $acceptableRanks
170
	 *
171
	 * @return self
172
	 */
173
	public function getByRank( $acceptableRanks ) {
174
		$acceptableRanks = array_flip( (array)$acceptableRanks );
175
		$statementList = new self();
176
177
		foreach ( $this->statements as $statement ) {
178 4
			if ( array_key_exists( $statement->getRank(), $acceptableRanks ) ) {
179 4
				$statementList->statements[] = $statement;
180
			}
181 4
		}
182 1
183
		return $statementList;
184
	}
185 3
186
	/**
187
	 * Returns the so called "best statements".
188
	 * If there are preferred statements, then this is all the preferred statements.
189
	 * If there are no preferred statements, then this is all normal statements.
190
	 *
191
	 * @since 2.4
192
	 *
193
	 * @return self
194
	 */
195
	public function getBestStatements() {
196
		$statements = $this->getByRank( Statement::RANK_PREFERRED );
197
198
		if ( !$statements->isEmpty() ) {
199 1
			return $statements;
200 1
		}
201
202 1
		return $this->getByRank( Statement::RANK_NORMAL );
203 1
	}
204 1
205 1
	/**
206 1
	 * Returns a list of all Snaks on this StatementList. This includes at least the main snaks of
207
	 * all statements, the snaks from qualifiers, and the snaks from references.
208 1
	 *
209
	 * This is a convenience method for use in code that needs to operate on all snaks, e.g.
210
	 * to find all referenced Entities.
211
	 *
212
	 * @since 1.1
213
	 *
214
	 * @return Snak[] Numerically indexed (non-sparse) array.
215
	 */
216 1
	public function getAllSnaks() {
217 1
		$snaks = array();
218
219 1
		foreach ( $this->statements as $statement ) {
220 1
			foreach ( $statement->getAllSnaks() as $snak ) {
221 1
				$snaks[] = $snak;
222
			}
223 1
		}
224
225
		return $snaks;
226
	}
227
228
	/**
229 1
	 * @since 2.3
230 1
	 *
231
	 * @return Snak[] Numerically indexed (non-sparse) array.
232
	 */
233
	public function getMainSnaks() {
234
		$snaks = array();
235
236 4
		foreach ( $this->statements as $statement ) {
237 4
			$snaks[] = $statement->getMainSnak();
238
		}
239
240
		return $snaks;
241
	}
242
243
	/**
244
	 * @return Traversable|Statement[]
245 12
	 */
246 12
	public function getIterator() {
247
		return new ArrayIterator( $this->statements );
248
	}
249
250
	/**
251
	 * @return Statement[] Numerically indexed (non-sparse) array.
252
	 */
253
	public function toArray() {
254
		return $this->statements;
255
	}
256 8
257 8
	/**
258
	 * @see Countable::count
259
	 *
260
	 * @return int
261 8
	 */
262 8
	public function count() {
263 8
		return count( $this->statements );
264 2
	}
265
266
	/**
267 6
	 * @see Comparable::equals
268
	 *
269
	 * @param mixed $target
270 6
	 *
271 6
	 * @return bool
272
	 */
273 6
	public function equals( $target ) {
274 5
		if ( $this === $target ) {
275 3
			return true;
276
		}
277
278 5
		if ( !( $target instanceof self )
279 6
			|| $this->count() !== $target->count()
280
		) {
281 3
			return false;
282
		}
283
284
		return $this->statementsEqual( $target->statements );
285
	}
286
287 6
	private function statementsEqual( array $statements ) {
288 6
		reset( $statements );
289
290
		foreach ( $this->statements as $statement ) {
291
			if ( !$statement->equals( current( $statements ) ) ) {
292
				return false;
293
			}
294
295
			next( $statements );
296
		}
297
298
		return true;
299 5
	}
300 5
301 3
	/**
302 3
	 * @return bool
303
	 */
304 4
	public function isEmpty() {
305
		return empty( $this->statements );
306 2
	}
307
308
	/**
309
	 * @since 3.0
310
	 * @see StatementByGuidMap
311
	 *
312
	 * @param string|null $statementGuid
313
	 *
314
	 * @return Statement|null The first statement with the given GUID or null if not found.
315
	 */
316 1
	public function getFirstStatementWithGuid( $statementGuid ) {
317 1
		foreach ( $this->statements as $statement ) {
318
			if ( $statement->getGuid() === $statementGuid ) {
319 1
				return $statement;
320 1
			}
321 1
		}
322 1
323 1
		return null;
324
	}
325 1
326
	/**
327
	 * @since 4.1
328
	 *
329
	 * @param StatementFilter $filter
330
	 *
331
	 * @return self
332
	 */
333
	public function filter( StatementFilter $filter ) {
334
		$statementList = new self();
335
336
		foreach ( $this->statements as $statement ) {
337
			if ( $filter->statementMatches( $statement ) ) {
338
				$statementList->statements[] = $statement;
339
			}
340
		}
341
342
		return $statementList;
343
	}
344
345
	/**
346
	 * @see http://php.net/manual/en/language.oop5.cloning.php
347
	 *
348
	 * @since 5.1
349
	 */
350
	public function __clone() {
351
		foreach ( $this->statements as &$statement ) {
352
			$statement = clone $statement;
353
		}
354
	}
355
356
}
357