Passed
Push — clear ( 11b8fa )
by Bene
03:57
created

StatementList::getMainSnaks()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

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