Skip to content

Commit a743d5c

Browse files
committed
Do not use ByPropertyIdArray
1 parent 6f85c91 commit a743d5c

File tree

4 files changed

+268
-68
lines changed

4 files changed

+268
-68
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
"vendor/bin/phpcs src/* tests/* --standard=phpcs.xml --extensions=php -sp"
5858
],
5959
"phpmd": [
60-
"vendor/bin/phpmd src/,tests/unit/ text phpmd.xml"
60+
"vendor/bin/phpmd src/ text phpmd.xml"
6161
]
6262
}
6363
}

src/Statement/StatementListChanger.php

Lines changed: 107 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace Wikibase\DataModel\Services\Statement;
44

5-
use Wikibase\DataModel\ByPropertyIdArray;
5+
use Wikibase\DataModel\Entity\PropertyId;
66
use Wikibase\DataModel\Statement\Statement;
77
use Wikibase\DataModel\Statement\StatementList;
88

@@ -20,18 +20,6 @@ public function clear( StatementList $statementList ) {
2020
}
2121
}
2222

23-
/**
24-
* @param StatementList $statementList
25-
* @param Statement[] $statements
26-
*/
27-
private function replaceStatements( StatementList $statementList, array $statements ) {
28-
$this->clear( $statementList );
29-
30-
foreach ( $statements as $statement ) {
31-
$statementList->addStatement( $statement );
32-
}
33-
}
34-
3523
public function groupByProperty( StatementList $statementList ) {
3624
$byId = [];
3725

@@ -51,19 +39,116 @@ public function groupByProperty( StatementList $statementList ) {
5139

5240
/**
5341
* @param StatementList $statementList
54-
* @param Statement $statement
42+
* @param Statement $newStatement
43+
* @param int|null $index An absolute index in the list. If the index is not next to a statement
44+
* with the same property ID, the closest possibly position is used instead. Default is null,
45+
* which adds the new statement after the last statement with the same property ID.
46+
*/
47+
public function addToGroup(
48+
StatementList $statementList,
49+
Statement $newStatement,
50+
$index = null
51+
) {
52+
$statements = $statementList->toArray();
53+
$id = $newStatement->getPropertyId();
54+
55+
if ( $index === null ) {
56+
$index = $this->getLastIndexWithinGroup( $statements, $id );
57+
} else {
58+
// Limit search range to avoid looping non-existing positions
59+
$indexInRange = min( max( 0, $index ), count( $statements ) );
60+
$index = $this->getClosestIndexWithinGroup( $statements, $id, $indexInRange );
61+
if ( $index === null ) {
62+
$index = $this->getClosestIndexAtGroupBorder( $statements, $indexInRange );
63+
}
64+
}
65+
66+
$statementList->addStatement( $newStatement, $index );
67+
}
68+
69+
/**
70+
* @param Statement[] $statements
71+
* @param PropertyId $id
72+
*
73+
* @return int|null
74+
*/
75+
private function getLastIndexWithinGroup( array $statements, PropertyId $id ) {
76+
for ( $i = count( $statements ); $i > 0; $i-- ) {
77+
if ( $statements[$i - 1]->getPropertyId()->equals( $id ) ) {
78+
return $i;
79+
}
80+
}
81+
82+
return null;
83+
}
84+
85+
/**
86+
* @param Statement[] $statements
87+
* @param PropertyId $id
5588
* @param int $index
89+
*
90+
* @return int|null
5691
*/
57-
public function addToGroup( StatementList $statementList, Statement $statement, $index ) {
58-
if ( $statementList->isEmpty() ) {
59-
$statementList->addStatement( $statement );
60-
return;
92+
private function getClosestIndexWithinGroup( array $statements, PropertyId $id, $index ) {
93+
$longestDistance = max( $index, count( $statements ) - $index );
94+
95+
for ( $i = 0; $i <= $longestDistance; $i++ ) {
96+
if ( $this->isWithinGroup( $statements, $id, $index - $i ) ) {
97+
return $index - $i;
98+
} elseif ( $i && $this->isWithinGroup( $statements, $id, $index + $i ) ) {
99+
return $index + $i;
100+
}
61101
}
62102

63-
$byPropertyIdArray = new ByPropertyIdArray( $statementList->toArray() );
64-
$byPropertyIdArray->buildIndex();
65-
$byPropertyIdArray->addObjectAtIndex( $statement, $index );
66-
$this->replaceStatements( $statementList, $byPropertyIdArray->toFlatArray() );
103+
return null;
104+
}
105+
106+
/**
107+
* @param Statement[] $statements
108+
* @param int $index
109+
*
110+
* @return int|null
111+
*/
112+
private function getClosestIndexAtGroupBorder( array $statements, $index ) {
113+
$longestDistance = max( $index, count( $statements ) - $index );
114+
115+
for ( $i = 0; $i <= $longestDistance; $i++ ) {
116+
if ( $this->isGroupBorder( $statements, $index - $i ) ) {
117+
return $index - $i;
118+
} elseif ( $i && $this->isGroupBorder( $statements, $index + $i ) ) {
119+
return $index + $i;
120+
}
121+
}
122+
123+
return null;
124+
}
125+
126+
/**
127+
* @param Statement[] $statements
128+
* @param PropertyId $id
129+
* @param int $index
130+
*
131+
* @return bool
132+
*/
133+
private function isWithinGroup( array $statements, PropertyId $id, $index ) {
134+
$count = count( $statements );
135+
136+
// Valid if the index either prepends ot appends a statement with the same property ID
137+
return $index > 0 && $index <= $count && $statements[$index - 1]->getPropertyId()->equals( $id )
138+
|| $index >= 0 && $index < $count && $statements[$index]->getPropertyId()->equals( $id );
139+
}
140+
141+
/**
142+
* @param Statement[] $statements
143+
* @param int $index
144+
*
145+
* @return bool
146+
*/
147+
private function isGroupBorder( array $statements, $index ) {
148+
// First and last possible position is always a border
149+
return $index <= 0
150+
|| $index >= count( $statements )
151+
|| !$statements[$index - 1]->getPropertyId()->equals( $statements[$index]->getPropertyId() );
67152
}
68153

69154
}

tests/unit/Lookup/DispatchingEntityLookupTest.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,14 @@ public function testGivenNotExistingEntityIdFromKnownRepository_getEntityReturns
7272

7373
/**
7474
* @param Exception $exception
75-
* @return \PHPUnit_Framework_MockObject_MockObject|EntityLookup
75+
*
76+
* @return EntityLookup
7677
*/
7778
private function getExceptionThrowingLookup( Exception $exception ) {
7879
$lookup = $this->getMock( EntityLookup::class );
7980
$lookup->expects( $this->any() )
8081
->method( $this->anything() )
81-
->willThrowException( $exception );
82+
->will( $this->throwException( $exception ) );
8283
return $lookup;
8384
}
8485

0 commit comments

Comments
 (0)