Skip to content

Commit 07c1f61

Browse files
committed
Allow unknown properties for forward compatability with JsonAPI 1.1
1 parent e616e2a commit 07c1f61

File tree

6 files changed

+47
-57
lines changed

6 files changed

+47
-57
lines changed

src/V1/Document.php

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -40,32 +40,26 @@ protected function parse(mixed $object): void
4040
throw new ValidationException('The properties `data` and `errors` MUST NOT coexist in Document.');
4141
}
4242

43-
if (property_exists($object, 'data')) {
44-
$this->set('data', $this->parseData($object->data));
45-
}
46-
47-
if (property_exists($object, 'meta')) {
48-
$this->set('meta', $this->create('Meta', $object->meta));
49-
}
50-
51-
if (property_exists($object, 'errors')) {
52-
$this->set('errors', $this->create('ErrorCollection', $object->errors));
53-
}
54-
55-
if (property_exists($object, 'included')) {
56-
if (!property_exists($object, 'data')) {
57-
throw new ValidationException('If Document does not contain a `data` property, the `included` property MUST NOT be present either.');
43+
foreach ($object as $key => $value) {
44+
if ($key === 'data') {
45+
$this->set('data', $this->parseData($value));
46+
} else if ($key === 'meta') {
47+
$this->set('meta', $this->create('Meta', $value));
48+
} else if ($key === 'errors') {
49+
$this->set('errors', $this->create('ErrorCollection', $value));
50+
} else if ($key === 'included') {
51+
if (!property_exists($object, 'data')) {
52+
throw new ValidationException('If Document does not contain a `data` property, the `included` property MUST NOT be present either.');
53+
}
54+
55+
$this->set('included', $this->create('ResourceCollection', $object->included));
56+
} else if ($key === 'jsonapi') {
57+
$this->set('jsonapi', $this->create('Jsonapi', $value));
58+
} else if ($key === 'links') {
59+
$this->set('links', $this->create('DocumentLink', $value));
60+
} else {
61+
$this->set($key, $value);
5862
}
59-
60-
$this->set('included', $this->create('ResourceCollection', $object->included));
61-
}
62-
63-
if (property_exists($object, 'jsonapi')) {
64-
$this->set('jsonapi', $this->create('Jsonapi', $object->jsonapi));
65-
}
66-
67-
if (property_exists($object, 'links')) {
68-
$this->set('links', $this->create('DocumentLink', $object->links));
6963
}
7064
}
7165

src/V1/Jsonapi.php

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,18 @@ protected function parse(mixed $object): void
3131
throw new ValidationException('Jsonapi has to be an object, "' . gettype($object) . '" given.');
3232
}
3333

34-
if (property_exists($object, 'version')) {
35-
if (is_object($object->version) or is_array($object->version)) {
36-
throw new ValidationException('property "version" cannot be an object or array, "' . gettype($object->version) . '" given.');
34+
foreach ($object as $key => $value) {
35+
if ($key === 'version') {
36+
if (is_object($value) or is_array($value)) {
37+
throw new ValidationException('property "version" cannot be an object or array, "' . gettype($value) . '" given.');
38+
}
39+
40+
$this->set('version', strval($value));
41+
} else if ($key === 'meta') {
42+
$this->set('meta', $this->create('Meta', $value));
43+
} else {
44+
$this->set($key, $value);
3745
}
38-
39-
$this->set('version', strval($object->version));
40-
}
41-
42-
if (property_exists($object, 'meta')) {
43-
$this->set('meta', $this->create('Meta', $object->meta));
4446
}
4547
}
4648

tests/Functional/ParsingTest.php

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -629,7 +629,7 @@ public function testParseNormativeStatementsForVersion10Correctly(): void
629629
$document = Parser::parseResponseString($string);
630630

631631
$this->assertInstanceOf(Document::class, $document);
632-
$this->assertSame(['data', 'included', 'jsonapi'], $document->getKeys());
632+
$this->assertSame(['jsonapi', 'data', 'included'], $document->getKeys());
633633
$this->assertSame('1.0', $document->get('jsonapi.version'));
634634
$this->assertInstanceOf(Accessable::class, $document->get('data'));
635635
$this->assertCount(6, $document->get('data')->getKeys());
@@ -643,7 +643,7 @@ public function testParseNormativeStatementsForVersion11Correctly(): void
643643
$document = Parser::parseResponseString($string);
644644

645645
$this->assertInstanceOf(Document::class, $document);
646-
$this->assertSame(['data', 'included', 'jsonapi'], $document->getKeys());
646+
$this->assertSame(['jsonapi', 'data', 'included'], $document->getKeys());
647647
$this->assertSame('1.1', $document->get('jsonapi.version'));
648648
$this->assertInstanceOf(Accessable::class, $document->get('data'));
649649
$this->assertCount(6, $document->get('data')->getKeys());
@@ -659,9 +659,7 @@ public function testParseJsonApiObjectWithVersion11Correctly(): void
659659
$this->assertInstanceOf(Document::class, $document);
660660
$this->assertSame(['meta', 'jsonapi'], $document->getKeys());
661661
$this->assertInstanceOf(Accessable::class, $document->get('jsonapi'));
662-
$this->assertSame(['version'], $document->get('jsonapi')->getKeys());
663-
// TODO #90: Add support for unknown properties
664-
// $this->assertSame(['version', 'ext', 'profile'], $document->get('jsonapi')->getKeys());
662+
$this->assertSame(['version', 'ext', 'profile'], $document->get('jsonapi')->getKeys());
665663
$this->assertSame('1.1', $document->get('jsonapi.version'));
666664
}
667665
}

tests/Functional/SerializerTest.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,6 @@ public function testParseJsonapiDataWithErrorAbortManager(string $filename, bool
7878
$document = $manager->parse($input);
7979

8080
$expected = json_decode($string, true);
81-
// TODO #90: Add support for unknown properties
82-
//** @phpstan-ignore-next-line */
83-
unset($expected['jsonapi']['ext']);
84-
//** @phpstan-ignore-next-line */
85-
unset($expected['jsonapi']['profile']);
8681

8782
// Test full array
8883
$this->assertEquals(

tests/Unit/V1/DocumentTest.php

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,15 @@ public function testCreateWithObjectReturnsSelf(): void
3838
{
3939
$object = new \stdClass();
4040
$object->meta = new \stdClass();
41-
$object->ignore = 'this property must be ignored';
41+
$object->fc = 'test property for forward compatability';
4242

4343
$document = new Document($object, $this->manager, $this->parent);
4444

4545
$this->assertInstanceOf(Document::class, $document);
4646
$this->assertInstanceOf(Accessable::class, $document);
47-
$this->assertSame($document->getKeys(), ['meta']);
47+
$this->assertSame($document->getKeys(), ['meta', 'fc']);
4848
$this->assertTrue($document->has('meta'));
49+
$this->assertTrue($document->has('fc'));
4950
$this->assertInstanceOf(Accessable::class, $document->get('meta'));
5051
$this->assertFalse($document->has('data'));
5152
$this->assertFalse($document->has('errors'));
@@ -63,26 +64,26 @@ public function testCreateWithAllPossibleValues(): void
6364
$object->data = new \stdClass();
6465
$object->data->type = 'types';
6566
$object->data->id = 'id';
67+
$object->meta = new \stdClass();
6668
$object->included = [];
6769
$object->included[0] = new \stdClass();
6870
$object->included[0]->type = 'types';
6971
$object->included[0]->id = 'id';
70-
$object->links = new \stdClass();
7172
$object->jsonapi = new \stdClass();
72-
$object->meta = new \stdClass();
73-
$object->ignore = 'this property must be ignored';
73+
$object->links = new \stdClass();
74+
$object->fc = 'test property for forward compatability';
7475

7576
$document = new Document($object, $this->manager, $this->parent);
7677

7778
$this->assertInstanceOf(Document::class, $document);
78-
$this->assertSame($document->getKeys(), ['data', 'meta', 'included', 'jsonapi', 'links']);
79+
$this->assertSame($document->getKeys(), ['data', 'meta', 'included', 'jsonapi', 'links', 'fc']);
7980
$this->assertTrue($document->has('data'));
8081
$this->assertTrue($document->has('meta'));
8182
$this->assertFalse($document->has('errors'));
8283
$this->assertTrue($document->has('jsonapi'));
8384
$this->assertTrue($document->has('links'));
8485
$this->assertTrue($document->has('included'));
85-
$this->assertFalse($document->has('ignore'));
86+
$this->assertTrue($document->has('fc'));
8687
}
8788

8889
/**

tests/Unit/V1/JsonapiTest.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,18 +42,18 @@ public function testCreateWithObject(): void
4242
// This object MAY also contain a meta member, whose value is a meta object
4343
$object->meta = new \stdClass();
4444

45-
// these properties must be ignored
46-
$object->testobj = new \stdClass();
47-
$object->teststring = 'http://example.org/link';
45+
// test properties for forward compatability
46+
$object->fcobj = new \stdClass();
47+
$object->fcstring = 'http://example.org/link';
4848

4949
$jsonapi = new Jsonapi($object, $this->manager, $this->parent);
5050

5151
$this->assertInstanceOf(Jsonapi::class, $jsonapi);
5252
$this->assertInstanceOf(Accessable::class, $jsonapi);
53-
$this->assertSame($jsonapi->getKeys(), ['version', 'meta']);
53+
$this->assertSame($jsonapi->getKeys(), ['version', 'meta', 'fcobj', 'fcstring']);
5454

55-
$this->assertFalse($jsonapi->has('testobj'));
56-
$this->assertFalse($jsonapi->has('teststring'));
55+
$this->assertTrue($jsonapi->has('fcobj'));
56+
$this->assertTrue($jsonapi->has('fcstring'));
5757
$this->assertTrue($jsonapi->has('version'));
5858
$this->assertSame($jsonapi->get('version'), '1.0');
5959
$this->assertTrue($jsonapi->has('meta'));

0 commit comments

Comments
 (0)