Skip to content

Commit c895742

Browse files
Daniel Kinzlerthiemowmde
authored andcommitted
Allow PHP serialization of custom ID types and foreign IDs. (#728)
1 parent 9938cc0 commit c895742

3 files changed

Lines changed: 144 additions & 47 deletions

File tree

src/Entity/EntityIdValue.php

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
* @license GPL-2.0+
1414
* @author Jeroen De Dauw < jeroendedauw@gmail.com >
1515
* @author Thiemo Mättig
16+
* @author Daniel Kinzler
1617
*/
1718
class EntityIdValue extends DataValueObject {
1819

@@ -27,24 +28,14 @@ public function __construct( EntityId $entityId ) {
2728
*
2829
* @since 7.0 serialization format changed in an incompatible way
2930
*
31+
* @note Do not use PHP serialization for persistence! Use a DataValueSerializer instead.
32+
*
3033
* @return string
3134
*/
3235
public function serialize() {
3336
return serialize( $this->entityId );
3437
}
3538

36-
/**
37-
* This method gets the numeric id from the serialization.
38-
* It makes assumptions we do not want to make about the id format,
39-
* though cannot be removed until we ditch the "numeric id" part
40-
* from the serialization.
41-
*
42-
* @return float Numeric id as a whole number. Can not be int because of 32-bit PHP.
43-
*/
44-
private function getNumericId() {
45-
return floatval( substr( $this->entityId->getSerialization(), 1 ) );
46-
}
47-
4839
/**
4940
* @see Serializable::unserialize
5041
*
@@ -123,11 +114,16 @@ public function getEntityId() {
123114
* @return array
124115
*/
125116
public function getArrayValue() {
126-
return [
117+
$array = [
127118
'entity-type' => $this->entityId->getEntityType(),
128-
'numeric-id' => $this->getNumericId(),
129-
'id' => $this->entityId->getSerialization(),
130119
];
120+
121+
if ( $this->entityId instanceof Int32EntityId ) {
122+
$array['numeric-id'] = $this->entityId->getNumericId();
123+
}
124+
125+
$array['id'] = $this->entityId->getSerialization();
126+
return $array;
131127
}
132128

133129
/**

tests/fixtures/CustomEntityId.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
namespace Wikibase\DataModel\Fixtures;
4+
5+
use Wikibase\DataModel\Entity\EntityId;
6+
7+
/**
8+
* Dummy custom EntityId implementation for use with EntityIdValueTest
9+
*
10+
* @license GPL 2+
11+
* @author Daniel Kinzler
12+
*/
13+
class CustomEntityId extends EntityId {
14+
15+
/**
16+
* @see Serializable::serialize
17+
*
18+
* @return string
19+
*/
20+
public function serialize() {
21+
return $this->serialization;
22+
}
23+
24+
/**
25+
* @see Serializable::unserialize
26+
*
27+
* @param string $serialized
28+
*/
29+
public function unserialize( $serialized ) {
30+
$this->serialization = $serialized;
31+
}
32+
33+
/**
34+
* @return string
35+
*/
36+
public function getEntityType() {
37+
return 'custom';
38+
}
39+
40+
}

tests/unit/Entity/EntityIdValueTest.php

Lines changed: 93 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
namespace Wikibase\DataModel\Tests\Entity;
44

55
use PHPUnit_Framework_TestCase;
6+
use Wikibase\DataModel\Entity\EntityId;
67
use Wikibase\DataModel\Entity\EntityIdValue;
78
use Wikibase\DataModel\Entity\ItemId;
89
use Wikibase\DataModel\Entity\PropertyId;
10+
use Wikibase\DataModel\Fixtures\CustomEntityId;
911

1012
/**
1113
* @covers Wikibase\DataModel\Entity\EntityIdValue
@@ -16,6 +18,7 @@
1618
* @license GPL-2.0+
1719
* @author Jeroen De Dauw < jeroendedauw@gmail.com >
1820
* @author Thiemo Mättig
21+
* @author Daniel Kinzler
1922
*/
2023
class EntityIdValueTest extends PHPUnit_Framework_TestCase {
2124

@@ -29,26 +32,29 @@ public function testCanConstruct() {
2932
* @dataProvider instanceProvider
3033
*/
3134
public function testSerialzationRoundtrip( EntityIdValue $id ) {
32-
$newId = unserialize( serialize( $id ) );
35+
$serialized = serialize( $id );
36+
$newId = unserialize( $serialized );
3337

3438
$this->assertEquals( $id, $newId );
3539
}
3640

3741
public function instanceProvider() {
3842
$ids = [
39-
new ItemId( 'Q1' ),
40-
new ItemId( 'Q42' ),
41-
new ItemId( 'Q31337' ),
42-
new ItemId( 'Q2147483647' ),
43-
new PropertyId( 'P1' ),
44-
new PropertyId( 'P42' ),
45-
new PropertyId( 'P31337' ),
43+
'Q1' => new ItemId( 'Q1' ),
44+
'Q42' => new ItemId( 'Q42' ),
45+
'Q31337' => new ItemId( 'Q31337' ),
46+
'Q2147483647' => new ItemId( 'Q2147483647' ),
47+
'P1' => new PropertyId( 'P1' ),
48+
'P42' => new PropertyId( 'P42' ),
49+
'P31337' => new PropertyId( 'P31337' ),
50+
'X567' => new CustomEntityId( 'X567' ),
51+
'foo:P678' => new PropertyId( 'foo:P678' ),
4652
];
4753

4854
$argLists = [];
4955

50-
foreach ( $ids as $id ) {
51-
$argLists[] = [ new EntityIdValue( $id ) ];
56+
foreach ( $ids as $k => $id ) {
57+
$argLists[$k] = [ new EntityIdValue( $id ) ];
5258
}
5359

5460
return $argLists;
@@ -75,41 +81,96 @@ public function testGetSortKey( EntityIdValue $id ) {
7581
$this->assertInternalType( 'string', $id->getSortKey() );
7682
}
7783

84+
public function provideGetArrayValue() {
85+
return [
86+
'Q2147483647' => [
87+
new ItemId( 'Q2147483647' ),
88+
[
89+
'entity-type' => 'item',
90+
'numeric-id' => 2147483647,
91+
'id' => 'Q2147483647'
92+
],
93+
],
94+
'P31337' => [
95+
new PropertyId( 'P31337' ),
96+
[
97+
'entity-type' => 'property',
98+
'numeric-id' => 31337,
99+
'id' => 'P31337',
100+
],
101+
],
102+
'X567' => [
103+
new CustomEntityId( 'X567' ),
104+
[
105+
'entity-type' => 'custom',
106+
'id' => 'X567',
107+
],
108+
],
109+
'foo:P678' => [
110+
new PropertyId( 'foo:P678' ),
111+
[
112+
'entity-type' => 'property',
113+
'numeric-id' => 678,
114+
'id' => 'foo:P678',
115+
],
116+
],
117+
];
118+
}
119+
78120
/**
79-
* @dataProvider instanceProvider
121+
* @dataProvider provideGetArrayValue
80122
*/
81-
public function testGetArrayValueRoundtrip( EntityIdValue $id ) {
82-
$newId = EntityIdValue::newFromArray( $id->getArrayValue() );
123+
public function testGetArrayValue( EntityId $id, array $expected ) {
124+
$value = new EntityIdValue( $id );
125+
$array = $value->getArrayValue();
83126

84-
$this->assertEquals( $id, $newId );
127+
$this->assertSame( $expected, $array );
85128
}
86129

87-
public function testSerializationCompatibility() {
130+
public function testSerialize() {
88131
$id = new EntityIdValue( new ItemId( 'Q31337' ) );
89132

90-
$this->assertEquals( 'C:32:"Wikibase\DataModel\Entity\ItemId":6:{Q31337}', $id->serialize() );
133+
$this->assertSame( 'C:32:"Wikibase\DataModel\Entity\ItemId":6:{Q31337}', $id->serialize() );
91134
}
92135

93-
public function testDeserializationCompatibility() {
94-
$expected = new EntityIdValue( new ItemId( 'Q31337' ) );
136+
public function provideDeserializationCompatibility() {
137+
$local = new EntityIdValue( new ItemId( 'Q31337' ) );
138+
$foreign = new EntityIdValue( new PropertyId( 'foo:P678' ) );
139+
$custom = new EntityIdValue( new CustomEntityId( 'X567' ) );
95140

96-
// This is the serialization format from f5b8b64823ff215c3796a79d916b6eaa65f4be33, version 0.5 alpha.
97-
$id = unserialize( 'C:39:"Wikibase\DataModel\Entity\EntityIdValue":14:{["item",31337]}' );
98-
$this->assertEquals( $expected, $id );
141+
return [
142+
'local: Version 0.5 alpha (f5b8b64)' => [
143+
'C:39:"Wikibase\DataModel\Entity\EntityIdValue":14:{["item",31337]}',
144+
$local
145+
],
146+
'local: Version 7.0 (7fcddfc)' => [
147+
'C:39:"Wikibase\DataModel\Entity\EntityIdValue":'
148+
. '50:{C:32:"Wikibase\DataModel\Entity\ItemId":6:{Q31337}}',
149+
$local
150+
],
151+
'foreign: Version 7.0 (7fcddfc)' => [
152+
'C:39:"Wikibase\DataModel\Entity\EntityIdValue":'
153+
. '56:{C:36:"Wikibase\DataModel\Entity\PropertyId":8:{foo:P678}}',
154+
$foreign
155+
],
156+
'custom: Version 7.0 (7fcddfc): custom' => [
157+
'C:39:"Wikibase\DataModel\Entity\EntityIdValue":'
158+
. '58:{C:42:"Wikibase\DataModel\Fixtures\CustomEntityId":4:{X567}}',
159+
$custom
160+
],
161+
];
99162
}
100163

101-
public function testGetArrayValueCompatibility() {
102-
$id = new EntityIdValue( new ItemId( 'Q31337' ) );
164+
/**
165+
* @dataProvider provideDeserializationCompatibility
166+
*
167+
* @param string $serialized
168+
* @param EntityIdValue $expected
169+
*/
170+
public function testDeserializationCompatibility( $serialized, EntityIdValue $expected ) {
171+
$id = unserialize( $serialized );
103172

104-
$this->assertSame(
105-
// This is the serialization format from when the EntityIdValue was still together with EntityId.
106-
[
107-
'entity-type' => 'item',
108-
'numeric-id' => (float)31337,
109-
'id' => 'Q31337',
110-
],
111-
$id->getArrayValue()
112-
);
173+
$this->assertEquals( $expected, $id );
113174
}
114175

115176
/**

0 commit comments

Comments
 (0)