ReferenceList::__unserialize()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 3
ccs 1
cts 1
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
namespace Wikibase\DataModel;
4
5
use ArrayIterator;
6
use Countable;
7
use InvalidArgumentException;
8
use IteratorAggregate;
9
use Serializable;
10
use Traversable;
11
use Wikibase\DataModel\Internal\MapValueHasher;
12
use Wikibase\DataModel\Snak\Snak;
13
14
/**
15
 * List of Reference objects.
16
 *
17
 * @since 0.1
18
 * Does not implement References anymore since 2.0
19
 * Does not extend SplObjectStorage since 5.0
20
 *
21
 * @license GPL-2.0-or-later
22
 * @author Jeroen De Dauw < [email protected] >
23
 * @author H. Snater < [email protected] >
24
 * @author Thiemo Kreuz
25
 * @author Bene* < [email protected] >
26
 */
27
class ReferenceList implements Countable, IteratorAggregate, Serializable {
28
29
	/**
30
	 * @var Reference[] Ordered list or references, indexed by SPL object hash.
31
	 */
32
	private $references = [];
33
34 29
	/**
35 29
	 * @param Reference[]|Traversable $references
36 8
	 *
37
	 * @throws InvalidArgumentException
38
	 */
39 21
	public function __construct( $references = [] ) {
40 12
		if ( !is_array( $references ) && !( $references instanceof Traversable ) ) {
41 4
			throw new InvalidArgumentException( '$references must be an array or an instance of Traversable' );
42
		}
43
44 8
		foreach ( $references as $reference ) {
45 17
			if ( !( $reference instanceof Reference ) ) {
46 17
				throw new InvalidArgumentException( 'Every element in $references must be an instance of Reference' );
47
			}
48
49
			$this->addReference( $reference );
50
		}
51
	}
52
53
	/**
54
	 * Adds the provided reference to the list.
55
	 * Empty references are ignored.
56
	 *
57
	 * @since 0.1
58 14
	 *
59 14
	 * @param Reference $reference
60
	 * @param int|null $index New position of the added reference, or null to append.
61
	 *
62
	 * @throws InvalidArgumentException
63 14
	 */
64
	public function addReference( Reference $reference, $index = null ) {
65 14
		if ( $index !== null && ( !is_int( $index ) || $index < 0 ) ) {
66 14
			throw new InvalidArgumentException( '$index must be a non-negative integer or null' );
67 2
		}
68
69 14
		if ( $reference->isEmpty() ) {
70
			return;
71
		}
72
73
		$splHash = spl_object_hash( $reference );
74
75
		if ( array_key_exists( $splHash, $this->references ) ) {
76
			return;
77 14
		}
78 14
79 14
		if ( $index === null || $index >= count( $this->references ) ) {
80 14
			// Append object to the end of the reference list.
81 14
			$this->references[$splHash] = $reference;
82
		} else {
83
			$this->insertReferenceAtIndex( $reference, $index );
84
		}
85
	}
86
87
	/**
88
	 * @since 1.1
89
	 *
90
	 * @param Snak ...$snaks
91 6
	 * (passing a single Snak[] is still supported but deprecated)
92 6
	 *
93 5
	 * @throws InvalidArgumentException
94 5
	 */
95
	public function addNewReference( ...$snaks ) {
96 6
		if ( count( $snaks ) === 1 && is_array( $snaks[0] ) ) {
97 5
			// TODO stop supporting this
98
			$snaks = $snaks[0];
99
		}
100
101
		$this->addReference( new Reference( $snaks ) );
102
	}
103 2
104 2
	/**
105 2
	 * @param Reference $reference
106
	 * @param int $index
107
	 */
108 2
	private function insertReferenceAtIndex( Reference $reference, $index ) {
109 2
		if ( !is_int( $index ) ) {
110 2
			throw new InvalidArgumentException( '$index must be an integer' );
111 2
		}
112 2
113
		$splHash = spl_object_hash( $reference );
114 2
115 2
		$this->references = array_merge(
0 ignored issues
show
Documentation Bug introduced by
It seems like array_merge(array_slice(...s->references, $index)) of type array<integer|string,obj...e\DataModel\Reference>> is incompatible with the declared type array<integer,object<Wik...e\DataModel\Reference>> of property $references.

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...
116 2
			array_slice( $this->references, 0, $index ),
117
			[ $splHash => $reference ],
118
			array_slice( $this->references, $index )
119 2
		);
120
	}
121 2
122 2
	/**
123 2
	 * Returns if the list contains a reference with the same hash as the provided reference.
124 2
	 *
125
	 * @since 0.1
126
	 *
127
	 * @param Reference $reference
128
	 *
129
	 * @return bool
130
	 */
131
	public function hasReference( Reference $reference ) {
132
		return $this->hasReferenceHash( $reference->getHash() );
133
	}
134
135 6
	/**
136 6
	 * Returns the index of the Reference object or false if the Reference could not be found.
137 6
	 *
138
	 * @since 0.5
139
	 *
140
	 * @param Reference $reference
141
	 *
142
	 * @return int|bool
143
	 */
144
	public function indexOf( Reference $reference ) {
145
		$index = 0;
146
147
		foreach ( $this->references as $ref ) {
148
			if ( $ref === $reference ) {
149 2
				return $index;
150 2
			}
151
152 2
			$index++;
153 1
		}
154 1
155
		return false;
156 1
	}
157 2
158
	/**
159 2
	 * Removes the reference with the same hash as the provided reference if such a reference exists in the list.
160
	 *
161
	 * @since 0.1
162
	 *
163
	 * @param Reference $reference
164
	 */
165
	public function removeReference( Reference $reference ) {
166
		$this->removeReferenceHash( $reference->getHash() );
167
	}
168
169 3
	/**
170 3
	 * Returns if the list contains a reference with the provided hash.
171 3
	 *
172
	 * @since 0.3
173
	 *
174
	 * @param string $referenceHash
175
	 *
176
	 * @return bool
177
	 */
178
	public function hasReferenceHash( $referenceHash ) {
179
		return $this->getReference( $referenceHash ) !== null;
180
	}
181
182 8
	/**
183 8
	 * Looks for the first Reference object in this list with the provided hash.
184
	 * Removes all occurences of that object.
185
	 *
186
	 * @since 0.3
187
	 *
188
	 * @param string $referenceHash	`
189
	 */
190
	public function removeReferenceHash( $referenceHash ) {
191
		$reference = $this->getReference( $referenceHash );
192
193 5
		if ( $reference === null ) {
194 5
			return;
195
		}
196 5
197 3
		foreach ( $this->references as $splObjectHash => $ref ) {
198 3
			if ( $ref === $reference ) {
199 5
				unset( $this->references[$splObjectHash] );
200
			}
201
		}
202
	}
203
204
	/**
205
	 * Returns the first Reference object with the provided hash, or
206
	 * null if there is no such reference in the list.
207
	 *
208
	 * @since 0.3
209
	 *
210 14
	 * @param string $referenceHash
211
	 *
212
	 * @return Reference|null
213
	 */
214 14
	public function getReference( $referenceHash ) {
215 10
		foreach ( $this->references as $reference ) {
216 10
			if ( $reference->getHash() === $referenceHash ) {
217
				return $reference;
218 9
			}
219
		}
220 9
221
		return null;
222
	}
223
224
	/**
225
	 * @see Serializable::serialize
226
	 *
227
	 * @since 2.1
228
	 *
229
	 * @return string
230 3
	 */
231 3
	public function serialize() {
232
		return serialize( array_values( $this->references ) );
233
	}
234
235
	/**
236
	 * @see https://wiki.php.net/rfc/custom_object_serialization
237
	 *
238
	 * @return array
239
	 */
240
	public function __serialize() {
241 3
		return [
242 3
			'references' => array_values( $this->references )
243 3
		];
244
	}
245
246
	/**
247
	 * @see https://wiki.php.net/rfc/custom_object_serialization
248
	 *
249
	 * @param array $data
250 3
	 */
251 3
	public function __unserialize( array $data ) : void {
252
		$this->references = $data['references'];
253
	}
254
255
	/**
256
	 * @see Serializable::unserialize
257
	 *
258
	 * @since 2.1
259
	 *
260
	 * @param string $serialized
261
	 */
262
	public function unserialize( $serialized ) {
263
		$this->__construct( unserialize( $serialized ) );
264
	}
265
266
	/**
267
	 * @since 4.4
268
	 *
269
	 * @return bool
270
	 */
271
	public function isEmpty() {
272
		return empty( $this->references );
273
	}
274
275
	/**
276
	 * The hash is purely valuer based. Order of the elements in the array is not held into account.
277
	 *
278
	 * @since 0.3
279
	 *
280
	 * @return string
281
	 */
282
	public function getValueHash() {
283
		$hasher = new MapValueHasher();
284
		return $hasher->hash( $this->references );
0 ignored issues
show
Documentation introduced by
$this->references is of type array<integer,object<Wik...e\DataModel\Reference>>, but the function expects a object<Traversable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
285
	}
286
287
	/**
288
	 * The comparison is done purely value based, ignoring the order of the elements in the array.
289
	 *
290
	 * @since 0.3
291
	 *
292
	 * @param mixed $target
293
	 *
294
	 * @return bool
295
	 */
296
	public function equals( $target ) {
297
		if ( $this === $target ) {
298
			return true;
299
		}
300
301
		return $target instanceof self
302
			&& $this->getValueHash() === $target->getValueHash();
303
	}
304
305
	/**
306
	 * @see Countable::count
307
	 *
308
	 * @return int
309
	 */
310
	public function count() {
311
		return count( $this->references );
312
	}
313
314
	/**
315
	 * @see IteratorAggregate::getIterator
316
	 *
317
	 * @since 5.0
318
	 *
319
	 * @return Iterator|Reference[]
320
	 */
321
	public function getIterator() {
322
		return new ArrayIterator( array_values( $this->references ) );
323
	}
324
325
}
326