Skip to content

Commit 660d1f2

Browse files
committed
Merge pull request #639 from wmde/addDuplicates
Fix regression when adding the same reference object twice
2 parents 50ca6fc + 5e4c9cd commit 660d1f2

2 files changed

Lines changed: 39 additions & 11 deletions

File tree

src/ReferenceList.php

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
class ReferenceList implements Comparable, Countable, IteratorAggregate, Serializable {
2929

3030
/**
31-
* @var Reference[]
31+
* @var Reference[] Ordered list or references, indexed by SPL object hash.
3232
*/
3333
private $references = array();
3434

@@ -73,7 +73,7 @@ public function addReference( Reference $reference, $index = null ) {
7373

7474
if ( $index === null || $index >= count( $this->references ) ) {
7575
// Append object to the end of the reference list.
76-
$this->references[] = $reference;
76+
$this->references[spl_object_hash( $reference )] = $reference;
7777
} else {
7878
$this->insertReferenceAtIndex( $reference, $index );
7979
}
@@ -100,7 +100,11 @@ public function addNewReference( $snaks = array() /*...*/ ) {
100100
* @param int $index
101101
*/
102102
private function insertReferenceAtIndex( Reference $reference, $index ) {
103-
array_splice( $this->references, $index, 0, array( $reference ) );
103+
$this->references = array_merge(
104+
array_slice( $this->references, 0, $index ),
105+
array( spl_object_hash( $reference ) => $reference ),
106+
array_slice( $this->references, $index )
107+
);
104108
}
105109

106110
/**
@@ -126,10 +130,14 @@ public function hasReference( Reference $reference ) {
126130
* @return int|bool
127131
*/
128132
public function indexOf( Reference $reference ) {
129-
foreach ( $this->references as $index => $ref ) {
133+
$index = 0;
134+
135+
foreach ( $this->references as $ref ) {
130136
if ( $ref === $reference ) {
131137
return $index;
132138
}
139+
140+
$index++;
133141
}
134142

135143
return false;
@@ -174,13 +182,11 @@ public function removeReferenceHash( $referenceHash ) {
174182
return;
175183
}
176184

177-
foreach ( $this->references as $index => $ref ) {
185+
foreach ( $this->references as $splObjectHash => $ref ) {
178186
if ( $ref === $reference ) {
179-
unset( $this->references[$index] );
187+
unset( $this->references[$splObjectHash] );
180188
}
181189
}
182-
183-
$this->references = array_values( $this->references );
184190
}
185191

186192
/**
@@ -211,7 +217,7 @@ public function getReference( $referenceHash ) {
211217
* @return string
212218
*/
213219
public function serialize() {
214-
return serialize( $this->references );
220+
return serialize( array_values( $this->references ) );
215221
}
216222

217223
/**
@@ -222,7 +228,7 @@ public function serialize() {
222228
* @param string $serialized
223229
*/
224230
public function unserialize( $serialized ) {
225-
$this->references = unserialize( $serialized );
231+
$this->__construct( unserialize( $serialized ) );
226232
}
227233

228234
/**
@@ -283,7 +289,7 @@ public function count() {
283289
* @return Traversable
284290
*/
285291
public function getIterator() {
286-
return new ArrayIterator( $this->references );
292+
return new ArrayIterator( array_values( $this->references ) );
287293
}
288294

289295
}

tests/unit/ReferenceListTest.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ public function testCanConstructWithReferenceListObject() {
4444
$this->assertNotNull( $copy->getReference( $reference->getHash() ) );
4545
}
4646

47+
public function testConstructorIgnoresIdenticalObjects() {
48+
$reference = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
49+
$list = new ReferenceList( array( $reference, $reference ) );
50+
$this->assertCount( 1, $list );
51+
}
52+
4753
public function testConstructorDoesNotIgnoreCopies() {
4854
$reference = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
4955
$list = new ReferenceList( array( $reference, clone $reference ) );
@@ -194,6 +200,14 @@ public function testAddReferenceOnNonEmptyList() {
194200
$this->assertSameReferenceOrder( $expectedList, $references );
195201
}
196202

203+
public function testAddReferenceIgnoresIdenticalObjects() {
204+
$list = new ReferenceList();
205+
$reference = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
206+
$list->addReference( $reference );
207+
$list->addReference( $reference );
208+
$this->assertCount( 1, $list );
209+
}
210+
197211
public function testAddReferenceDoesNotIgnoreCopies() {
198212
$list = new ReferenceList();
199213
$reference = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
@@ -202,6 +216,14 @@ public function testAddReferenceDoesNotIgnoreCopies() {
202216
$this->assertCount( 2, $list );
203217
}
204218

219+
public function testAddReferenceAtIndexIgnoresIdenticalObjects() {
220+
$list = new ReferenceList();
221+
$reference = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
222+
$list->addReference( $reference, 0 );
223+
$list->addReference( $reference, 0 );
224+
$this->assertCount( 1, $list );
225+
}
226+
205227
public function testAddReferenceAtIndexZero() {
206228
$reference1 = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
207229
$reference2 = new Reference( array( new PropertyNoValueSnak( 2 ) ) );

0 commit comments

Comments
 (0)