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 Kreuz |
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
|
|
|
*/ |
44
|
|
|
public function __construct( $statements = [] /*...*/ ) { |
45
|
|
|
if ( $statements instanceof Statement ) { |
46
|
|
|
$statements = func_get_args(); |
47
|
|
|
} |
48
|
|
|
|
49
|
|
|
if ( !is_array( $statements ) && !( $statements instanceof Traversable ) ) { |
50
|
|
|
throw new InvalidArgumentException( '$statements must be an array or an instance of Traversable' ); |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
foreach ( $statements as $statement ) { |
54
|
|
|
if ( !( $statement instanceof Statement ) ) { |
55
|
|
|
throw new InvalidArgumentException( 'Every element in $statements must be an instance of Statement' ); |
56
|
|
|
} |
57
|
|
|
|
58
|
|
|
$this->statements[] = $statement; |
59
|
|
|
} |
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
|
|
|
*/ |
68
|
|
|
public function getPropertyIds() { |
69
|
|
|
$propertyIds = []; |
70
|
|
|
|
71
|
|
|
foreach ( $this->statements as $statement ) { |
72
|
|
|
$propertyIds[$statement->getPropertyId()->getSerialization()] = $statement->getPropertyId(); |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
return $propertyIds; |
76
|
|
|
} |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* @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
|
|
|
public function addStatement( Statement $statement, $index = null ) { |
88
|
|
|
if ( $index === null ) { |
89
|
|
|
$this->statements[] = $statement; |
90
|
|
|
} elseif ( is_int( $index ) && $index >= 0 ) { |
91
|
|
|
array_splice( $this->statements, $index, 0, [ $statement ] ); |
92
|
|
|
} else { |
93
|
|
|
throw new InvalidArgumentException( '$index must be a non-negative integer or null' ); |
94
|
|
|
} |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* @param Snak $mainSnak |
99
|
|
|
* @param Snak[]|SnakList|null $qualifiers |
100
|
|
|
* @param Reference[]|ReferenceList|null $references |
101
|
|
|
* @param string|null $guid |
102
|
|
|
*/ |
103
|
|
|
public function addNewStatement( Snak $mainSnak, $qualifiers = null, $references = null, $guid = null ) { |
104
|
|
|
$qualifiers = is_array( $qualifiers ) ? new SnakList( $qualifiers ) : $qualifiers; |
105
|
|
|
$references = is_array( $references ) ? new ReferenceList( $references ) : $references; |
106
|
|
|
|
107
|
|
|
$statement = new Statement( $mainSnak, $qualifiers, $references ); |
108
|
|
|
$statement->setGuid( $guid ); |
109
|
|
|
|
110
|
|
|
$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
|
|
|
if ( $statement->getGuid() === $guid ) { |
121
|
|
|
unset( $this->statements[$index] ); |
122
|
|
|
} |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
$this->statements = array_values( $this->statements ); |
126
|
|
|
} |
127
|
|
|
|
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
|
|
|
$statements = []; |
138
|
|
|
|
139
|
|
|
foreach ( $this->statements as $statement ) { |
140
|
|
|
$statements[$statement->getMainSnak()->getHash()] = $statement; |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
return new self( $statements ); |
144
|
|
|
} |
145
|
|
|
|
146
|
|
|
/** |
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
|
|
|
foreach ( $this->statements as $statement ) { |
157
|
|
|
if ( $statement->getPropertyId()->equals( $id ) ) { |
158
|
|
|
$statementList->statements[] = $statement; |
159
|
|
|
} |
160
|
|
|
} |
161
|
|
|
|
162
|
|
|
return $statementList; |
163
|
|
|
} |
164
|
|
|
|
165
|
|
|
/** |
166
|
|
|
* @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
|
|
|
$statementList->statements[] = $statement; |
179
|
|
|
} |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
return $statementList; |
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
/** |
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
|
|
|
} |
200
|
|
|
|
201
|
|
|
return $this->getByRank( Statement::RANK_NORMAL ); |
|
|
|
|
202
|
|
|
} |
203
|
|
|
|
204
|
|
|
/** |
205
|
|
|
* Returns a list of all Snaks on this StatementList. This includes at least the main snaks of |
206
|
|
|
* all statements, the snaks from qualifiers, and the snaks from references. |
207
|
|
|
* |
208
|
|
|
* 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
|
|
|
$snaks = []; |
217
|
|
|
|
218
|
|
|
foreach ( $this->statements as $statement ) { |
219
|
|
|
foreach ( $statement->getAllSnaks() as $snak ) { |
220
|
|
|
$snaks[] = $snak; |
221
|
|
|
} |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
return $snaks; |
225
|
|
|
} |
226
|
|
|
|
227
|
|
|
/** |
228
|
|
|
* @since 2.3 |
229
|
|
|
* |
230
|
|
|
* @return Snak[] Numerically indexed (non-sparse) array. |
231
|
|
|
*/ |
232
|
|
|
public function getMainSnaks() { |
233
|
|
|
$snaks = []; |
234
|
|
|
|
235
|
|
|
foreach ( $this->statements as $statement ) { |
236
|
|
|
$snaks[] = $statement->getMainSnak(); |
237
|
|
|
} |
238
|
|
|
|
239
|
|
|
return $snaks; |
240
|
|
|
} |
241
|
|
|
|
242
|
|
|
/** |
243
|
|
|
* @return Traversable|Statement[] |
244
|
|
|
*/ |
245
|
|
|
public function getIterator() { |
246
|
|
|
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
|
|
|
/** |
257
|
|
|
* @see Countable::count |
258
|
|
|
* |
259
|
|
|
* @return int |
260
|
|
|
*/ |
261
|
|
|
public function count() { |
262
|
|
|
return count( $this->statements ); |
263
|
|
|
} |
264
|
|
|
|
265
|
|
|
/** |
266
|
|
|
* @see Comparable::equals |
267
|
|
|
* |
268
|
|
|
* @param mixed $target |
269
|
|
|
* |
270
|
|
|
* @return bool |
271
|
|
|
*/ |
272
|
|
|
public function equals( $target ) { |
273
|
|
|
if ( $this === $target ) { |
274
|
|
|
return true; |
275
|
|
|
} |
276
|
|
|
|
277
|
|
|
if ( !( $target instanceof self ) |
278
|
|
|
|| $this->count() !== $target->count() |
279
|
|
|
) { |
280
|
|
|
return false; |
281
|
|
|
} |
282
|
|
|
|
283
|
|
|
return $this->statementsEqual( $target->statements ); |
284
|
|
|
} |
285
|
|
|
|
286
|
|
|
private function statementsEqual( array $statements ) { |
287
|
|
|
reset( $statements ); |
288
|
|
|
|
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
|
|
|
|
300
|
|
|
/** |
301
|
|
|
* @return bool |
302
|
|
|
*/ |
303
|
|
|
public function isEmpty() { |
304
|
|
|
return empty( $this->statements ); |
305
|
|
|
} |
306
|
|
|
|
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
|
|
|
foreach ( $this->statements as $statement ) { |
317
|
|
|
if ( $statement->getGuid() === $statementGuid ) { |
318
|
|
|
return $statement; |
319
|
|
|
} |
320
|
|
|
} |
321
|
|
|
|
322
|
|
|
return null; |
323
|
|
|
} |
324
|
|
|
|
325
|
|
|
/** |
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 7.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
|
|
|
|
This class constant has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.