Completed
Pull Request — master (#617)
by Bene
05:59 queued 03:04
created

ReferenceList::toArray()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 3
ccs 0
cts 0
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 2
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 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
 * @licence GNU GPL v2+
22
 * @author Jeroen De Dauw < [email protected] >
23
 * @author H. Snater < [email protected] >
24
 * @author Thiemo Mättig
25
 * @author Bene* < [email protected] >
26
 */
27
class ReferenceList implements Comparable, Countable, IteratorAggregate {
28
29
	/**
30
	 * @var Reference[]
31
	 */
32
	private $references = array();
33
34 29
	/**
35 29
	 * @param Reference[]|Traversable $references
36 8
	 *
37
	 * @throws InvalidArgumentException
38
	 */
39 21
	public function __construct( $references = array() ) {
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
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
		if ( $index === null || $index >= count( $this->references ) ) {
74
			// Append object to the end of the reference list.
75
			$this->references[] = $reference;
76
		} else {
77 14
			$this->insertReferenceAtIndex( $reference, $index );
78 14
		}
79 14
	}
80 14
81 14
	/**
82
	 * @since 1.1
83
	 *
84
	 * @param Snak[]|Snak $snaks
85
	 * @param Snak [$snak2,...]
86
	 *
87
	 * @throws InvalidArgumentException
88
	 */
89
	public function addNewReference( $snaks = array() /*...*/ ) {
90
		if ( $snaks instanceof Snak ) {
91 6
			$snaks = func_get_args();
92 6
		}
93 5
94 5
		$this->addReference( new Reference( $snaks ) );
95
	}
96 6
97 5
	/**
98
	 * @param Reference $reference
99
	 * @param int $index
100
	 */
101
	private function insertReferenceAtIndex( Reference $reference, $index ) {
102
		array_splice( $this->references, $index, 0, array( $reference ) );
103 2
	}
104 2
105 2
	/**
106
	 * Returns if the list contains a reference with the same hash as the provided reference.
107
	 *
108 2
	 * @since 0.1
109 2
	 *
110 2
	 * @param Reference $reference
111 2
	 *
112 2
	 * @return boolean
113
	 */
114 2
	public function hasReference( Reference $reference ) {
115 2
		return $this->hasReferenceHash( $reference->getHash() );
116 2
	}
117
118
	/**
119 2
	 * Returns the index of a reference or false if the reference could not be found.
120
	 *
121 2
	 * @since 0.5
122 2
	 *
123 2
	 * @param Reference $reference
124 2
	 *
125
	 * @return int|boolean
126
	 */
127
	public function indexOf( Reference $reference ) {
128
		foreach ( $this->references as $index => $ref ) {
129
			if ( $ref === $reference ) {
130
				return $index;
131
			}
132
		}
133
134
		return false;
135 6
	}
136 6
137 6
	/**
138
	 * Removes the reference with the same hash as the provided reference if such a reference exists in the list.
139
	 *
140
	 * @since 0.1
141
	 *
142
	 * @param Reference $reference
143
	 */
144
	public function removeReference( Reference $reference ) {
145
		$this->removeReferenceHash( $reference->getHash() );
146
	}
147
148
	/**
149 2
	 * Returns if the list contains a reference with the provided hash.
150 2
	 *
151
	 * @since 0.3
152 2
	 *
153 1
	 * @param string $referenceHash
154 1
	 *
155
	 * @return boolean
156 1
	 */
157 2
	public function hasReferenceHash( $referenceHash ) {
158
		return $this->getReference( $referenceHash ) !== null;
159 2
	}
160
161
	/**
162
	 * Removes the reference with the provided hash if it exists in the list.
163
	 *
164
	 * @since 0.3
165
	 *
166
	 * @param string $referenceHash	`
167
	 */
168
	public function removeReferenceHash( $referenceHash ) {
169 3
		foreach ( $this->references as $index => $reference ) {
170 3
			if ( $reference->getHash() === $referenceHash ) {
171 3
				$this->removeReferenceAtIndex( $index );
172
			}
173
		}
174
	}
175
176
	/**
177
	 * @param int $index
178
	 */
179
	private function removeReferenceAtIndex( $index ) {
180
		array_splice( $this->references, $index, 1 );
181
	}
182 8
183 8
	/**
184
	 * Returns the reference with the provided hash, or
185
	 * null if there is no such reference in the list.
186
	 *
187
	 * @since 0.3
188
	 *
189
	 * @param string $referenceHash
190
	 *
191
	 * @return Reference|null
192
	 */
193 5
	public function getReference( $referenceHash ) {
194 5
		foreach ( $this->references as $reference ) {
195
			if ( $reference->getHash() === $referenceHash ) {
196 5
				return $reference;
197 3
			}
198 3
		}
199 5
200
		return null;
201
	}
202
203
	/**
204
	 * @see Serializable::serialize
205
	 *
206
	 * @since 2.1
207
	 *
208
	 * @return string
209
	 */
210 14
	public function serialize() {
211
		return serialize( $this->references );
212
	}
213
214 14
	/**
215 10
	 * @see Serializable::unserialize
216 10
	 *
217
	 * @since 2.1
218 9
	 *
219
	 * @param string $data
220 9
	 */
221
	public function unserialize( $data ) {
222
		$this->__construct( unserialize( $data ) );
223
	}
224
225
	/**
226
	 * @since 4.4
227
	 *
228
	 * @return bool
229
	 */
230 3
	public function isEmpty() {
231 3
		return empty( $this->references );
232
	}
233
234
	/**
235
	 * The hash is purely valuer based. Order of the elements in the array is not held into account.
236
	 *
237
	 * @since 0.3
238
	 *
239
	 * @return string
240
	 */
241 3
	public function getValueHash() {
242 3
		$hasher = new MapValueHasher();
243 3
		return $hasher->hash( $this->references );
244
	}
245
246
	/**
247
	 * @see Comparable::equals
248
	 *
249
	 * The comparison is done purely value based, ignoring the order of the elements in the array.
250 3
	 *
251 3
	 * @since 0.3
252
	 *
253
	 * @param mixed $target
254
	 *
255
	 * @return bool
256
	 */
257
	public function equals( $target ) {
258
		if ( $this === $target ) {
259
			return true;
260
		}
261
262
		return $target instanceof self
263
		       && $this->getValueHash() === $target->getValueHash();
264
	}
265
266
	/**
267
	 * @see Countable::count
268
	 *
269
	 * @return int
270
	 */
271
	public function count() {
272
		return count( $this->references );
273
	}
274
275
	/**
276
	 * @see IteratorAggregate::getIterator
277
	 *
278
	 * @since 5.0
279
	 *
280
	 * @return Traversable
281
	 */
282
	public function getIterator() {
283
		return new ArrayIterator( $this->references );
284
	}
285
286
}
287