Completed
Pull Request — master (#634)
by Bene
04:24 queued 01:18
created

ReferenceList   B

Complexity

Total Complexity 36

Size/Duplication

Total Lines 255
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 98.73%

Importance

Changes 12
Bugs 2 Features 2
Metric Value
wmc 36
c 12
b 2
f 2
lcom 1
cbo 2
dl 0
loc 255
ccs 78
cts 79
cp 0.9873
rs 8.8

17 Methods

Rating   Name   Duplication   Size   Complexity  
A addNewReference() 0 7 2
B __construct() 0 13 5
B addReference() 0 16 7
A insertReferenceAtIndex() 0 3 1
A hasReference() 0 3 1
A indexOf() 0 9 3
A removeReference() 0 3 1
A hasReferenceHash() 0 3 1
A removeReferenceHash() 0 9 3
A getReference() 0 9 3
A serialize() 0 3 1
A unserialize() 0 3 1
A isEmpty() 0 3 1
A getValueHash() 0 4 1
A equals() 0 8 3
A count() 0 3 1
A getIterator() 0 3 1
1
<?php
2
3
namespace Wikibase\DataModel;
4
5
use ArrayIterator;
6
use Comparable;
7
use Countable;
8
use InvalidArgumentException;
9
use IteratorAggregate;
10
use Serializable;
11
use Traversable;
12
use Wikibase\DataModel\Internal\MapValueHasher;
13
use Wikibase\DataModel\Snak\Snak;
14
15
/**
16
 * List of Reference objects.
17
 *
18
 * @since 0.1
19
 * Does not implement References anymore since 2.0
20
 * Does not extend SplObjectStorage since 5.0
21
 *
22
 * @licence GNU GPL v2+
23
 * @author Jeroen De Dauw < [email protected] >
24
 * @author H. Snater < [email protected] >
25
 * @author Thiemo Mättig
26
 * @author Bene* < [email protected] >
27
 */
28
class ReferenceList implements Comparable, Countable, IteratorAggregate, Serializable {
29
30
	/**
31
	 * @var Reference[]
32
	 */
33
	private $references = array();
34 29
35 29
	/**
36 8
	 * @param Reference[]|Traversable $references
37
	 *
38
	 * @throws InvalidArgumentException
39 21
	 */
40 12
	public function __construct( $references = array() ) {
41 4
		if ( !is_array( $references ) && !( $references instanceof Traversable ) ) {
42
			throw new InvalidArgumentException( '$references must be an array or an instance of Traversable' );
43
		}
44 8
45 17
		foreach ( $references as $reference ) {
46 17
			if ( !( $reference instanceof Reference ) ) {
47
				throw new InvalidArgumentException( 'Every element in $references must be an instance of Reference' );
48
			}
49
50
			$this->addReference( $reference );
51
		}
52
	}
53
54
	/**
55
	 * Adds the provided reference to the list.
56
	 * Empty references are ignored.
57
	 *
58 14
	 * @since 0.1
59 14
	 *
60
	 * @param Reference $reference
61
	 * @param int|null $index
62
	 *
63 14
	 * @throws InvalidArgumentException
64
	 */
65 14
	public function addReference( Reference $reference, $index = null ) {
66 14
		if ( $index !== null && ( !is_int( $index ) || $index < 0 ) ) {
67 2
			throw new InvalidArgumentException( '$index must be a non-negative integer or null' );
68
		}
69 14
70
		if ( $reference->isEmpty() ) {
71
			return;
72
		}
73
74
		if ( $index === null || $index >= count( $this->references ) ) {
75
			// Append object to the end of the reference list.
76
			$this->references[] = $reference;
77 14
		} else {
78 14
			$this->insertReferenceAtIndex( $reference, $index );
79 14
		}
80 14
	}
81 14
82
	/**
83
	 * @since 1.1
84
	 *
85
	 * @param Snak[]|Snak $snaks
86
	 * @param Snak [$snak2,...]
87
	 *
88
	 * @throws InvalidArgumentException
89
	 */
90
	public function addNewReference( $snaks = array() /*...*/ ) {
91 6
		if ( $snaks instanceof Snak ) {
92 6
			$snaks = func_get_args();
93 5
		}
94 5
95
		$this->addReference( new Reference( $snaks ) );
96 6
	}
97 5
98
	/**
99
	 * @param Reference $reference
100
	 * @param int $index
101
	 */
102
	private function insertReferenceAtIndex( Reference $reference, $index ) {
103 2
		array_splice( $this->references, $index, 0, array( $reference ) );
104 2
	}
105 2
106
	/**
107
	 * Returns if the list contains a reference with the same hash as the provided reference.
108 2
	 *
109 2
	 * @since 0.1
110 2
	 *
111 2
	 * @param Reference $reference
112 2
	 *
113
	 * @return bool
114 2
	 */
115 2
	public function hasReference( Reference $reference ) {
116 2
		return $this->hasReferenceHash( $reference->getHash() );
117
	}
118
119 2
	/**
120
	 * Returns the index of a reference or false if the reference could not be found.
121 2
	 *
122 2
	 * @since 0.5
123 2
	 *
124 2
	 * @param Reference $reference
125
	 *
126
	 * @return int|bool
127
	 */
128
	public function indexOf( Reference $reference ) {
129
		foreach ( $this->references as $index => $ref ) {
130
			if ( $ref === $reference ) {
131
				return $index;
132
			}
133
		}
134
135 6
		return false;
136 6
	}
137 6
138
	/**
139
	 * Removes the reference with the same hash as the provided reference if such a reference exists in the list.
140
	 *
141
	 * @since 0.1
142
	 *
143
	 * @param Reference $reference
144
	 */
145
	public function removeReference( Reference $reference ) {
146
		$this->removeReferenceHash( $reference->getHash() );
147
	}
148
149 2
	/**
150 2
	 * Returns if the list contains a reference with the provided hash.
151
	 *
152 2
	 * @since 0.3
153 1
	 *
154 1
	 * @param string $referenceHash
155
	 *
156 1
	 * @return bool
157 2
	 */
158
	public function hasReferenceHash( $referenceHash ) {
159 2
		return $this->getReference( $referenceHash ) !== null;
160
	}
161
162
	/**
163
	 * Removes the reference with the provided hash if it exists in the list.
164
	 *
165
	 * @since 0.3
166
	 *
167
	 * @param string $referenceHash	`
168
	 */
169 3
	public function removeReferenceHash( $referenceHash ) {
170 3
		foreach ( $this->references as $index => $reference ) {
171 3
			if ( $reference->getHash() === $referenceHash ) {
172
				unset( $this->references[$index] );
173
			}
174
		}
175
176
		$this->references = array_values( $this->references );
177
	}
178
179
	/**
180
	 * Returns the reference with the provided hash, or
181
	 * null if there is no such reference in the list.
182 8
	 *
183 8
	 * @since 0.3
184
	 *
185
	 * @param string $referenceHash
186
	 *
187
	 * @return Reference|null
188
	 */
189
	public function getReference( $referenceHash ) {
190
		foreach ( $this->references as $reference ) {
191
			if ( $reference->getHash() === $referenceHash ) {
192
				return $reference;
193 5
			}
194 5
		}
195
196 5
		return null;
197 3
	}
198 3
199 5
	/**
200
	 * @see Serializable::serialize
201
	 *
202
	 * @since 2.1
203
	 *
204
	 * @return string
205
	 */
206
	public function serialize() {
207
		return serialize( $this->references );
208
	}
209
210 14
	/**
211
	 * @see Serializable::unserialize
212
	 *
213
	 * @since 2.1
214 14
	 *
215 10
	 * @param string $serialized
216 10
	 */
217
	public function unserialize( $serialized ) {
218 9
		$this->references = unserialize( $serialized );
219
	}
220 9
221
	/**
222
	 * @since 4.4
223
	 *
224
	 * @return bool
225
	 */
226
	public function isEmpty() {
227
		return empty( $this->references );
228
	}
229
230 3
	/**
231 3
	 * The hash is purely valuer based. Order of the elements in the array is not held into account.
232
	 *
233
	 * @since 0.3
234
	 *
235
	 * @return string
236
	 */
237
	public function getValueHash() {
238
		$hasher = new MapValueHasher();
239
		return $hasher->hash( $this->references );
240
	}
241 3
242 3
	/**
243 3
	 * @see Comparable::equals
244
	 *
245
	 * The comparison is done purely value based, ignoring the order of the elements in the array.
246
	 *
247
	 * @since 0.3
248
	 *
249
	 * @param mixed $target
250 3
	 *
251 3
	 * @return bool
252
	 */
253
	public function equals( $target ) {
254
		if ( $this === $target ) {
255
			return true;
256
		}
257
258
		return $target instanceof self
259
		       && $this->getValueHash() === $target->getValueHash();
260
	}
261
262
	/**
263
	 * @see Countable::count
264
	 *
265
	 * @return int
266
	 */
267
	public function count() {
268
		return count( $this->references );
269
	}
270
271
	/**
272
	 * @see IteratorAggregate::getIterator
273
	 *
274
	 * @since 5.0
275
	 *
276
	 * @return Traversable
277
	 */
278
	public function getIterator() {
279
		return new ArrayIterator( $this->references );
280
	}
281
282
}
283