Skip to content

Commit 2b02699

Browse files
authored
Merge pull request #7 from developerstudservis/handle-union-types
Handle union types
2 parents 30f45b6 + 8b487ad commit 2b02699

File tree

8 files changed

+96
-10
lines changed

8 files changed

+96
-10
lines changed

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased]
88

9+
## [0.0.6] - 2025-04-05
10+
11+
### Fixed
12+
- Handle Union Types for `data` and `attributes` fields.
13+
914
## [0.0.5] - 2025-03-24
1015

1116
### Fixed
@@ -32,7 +37,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3237
### Added
3338
- Extract all DTO types from FreeElephants/json-api-php-toolkit to this project
3439

35-
[Unreleased]: https://github.com/FreeElephants/json-api-dto/compare/0.0.5...HEAD
40+
[Unreleased]: https://github.com/FreeElephants/json-api-dto/compare/0.0.6...HEAD
41+
[0.0.6]: https://github.com/FreeElephants/json-api-dto/releases/tag/0.0.6
3642
[0.0.5]: https://github.com/FreeElephants/json-api-dto/releases/tag/0.0.5
3743
[0.0.4]: https://github.com/FreeElephants/json-api-dto/releases/tag/0.0.4
3844
[0.0.3]: https://github.com/FreeElephants/json-api-dto/releases/tag/0.0.3

src/FreeElephants/JsonApi/DTO/AbstractDocument.php

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
namespace FreeElephants\JsonApi\DTO;
44

5-
use Psr\Http\Message\MessageInterface;
6-
75
/**
86
* @property AbstractResourceObject|mixed $data
97
*/
@@ -13,9 +11,25 @@ final public function __construct(array $payload)
1311
{
1412
$concreteClass = new \ReflectionClass($this);
1513
$dataProperty = $concreteClass->getProperty('data');
16-
/** @var \ReflectionNamedType $reflectionType */
14+
1715
$reflectionType = $dataProperty->getType();
18-
$dataClassName = $reflectionType->getName();
16+
if ($reflectionType instanceof \ReflectionNamedType) {
17+
$dataClassName = $reflectionType->getName();
18+
} else {
19+
/** @var \ReflectionUnionType $reflectionType */
20+
$dataClassName = $reflectionType->getTypes()[0]->getName();
21+
}
22+
23+
/**
24+
* In cases like:
25+
* `public array|Example\ResourceObjectExt|Example\ResourceObject $data;`
26+
* ReflectionUnionType::getTypes() return types in next orders:
27+
* - Example\ResourceObjectExt
28+
* - Example\ResourceObject
29+
* - array
30+
*
31+
* This exception is [can] not covered with test. But this behavior not documented at https://www.php.net/manual/en/reflectionuniontype.gettypes.php
32+
*/
1933
if ($dataClassName !== 'array') {
2034
$data = new $dataClassName($payload['data']);
2135
} else {

src/FreeElephants/JsonApi/DTO/AbstractResourceObject.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,19 @@ class AbstractResourceObject
1515

1616
public function __construct(array $data)
1717
{
18-
$this->id = $data['id'] ?? null;
18+
$this->id = $data['id'];
1919
$this->type = $data['type'];
2020

2121
$concreteClass = new \ReflectionClass($this);
2222

2323
if (property_exists($this, 'attributes')) {
24-
$attributesProperty = $concreteClass->getProperty('attributes');
25-
$attributesClass = $attributesProperty->getType()->getName();
24+
$attributesPropertyType = $concreteClass->getProperty('attributes')->getType();
25+
26+
if($attributesPropertyType instanceof \ReflectionUnionType) {
27+
$attributesClass = $attributesPropertyType->getTypes()[0]->getName();
28+
} else {
29+
$attributesClass = $attributesPropertyType->getName();
30+
}
2631
$this->attributes = new $attributesClass($data['attributes']);
2732
}
2833

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace FreeElephants\JsonApi\DTO\Example;
5+
6+
class AttributesExt extends Attributes
7+
{
8+
public int $baz;
9+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace FreeElephants\JsonApi\DTO\Example;
5+
6+
use FreeElephants\JsonApi\DTO\AbstractResourceObject;
7+
8+
class ResourceObject extends AbstractResourceObject
9+
{
10+
11+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace FreeElephants\JsonApi\DTO\Example;
5+
6+
class ResourceObjectExt extends ResourceObject
7+
{
8+
9+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace FreeElephants\JsonApi\DTO\Reflection;
5+
6+
use FreeElephants\JsonApi\AbstractTestCase;
7+
use FreeElephants\JsonApi\DTO\AbstractDocument;
8+
use FreeElephants\JsonApi\DTO\Example;
9+
10+
class DocumentTestPHP8 extends AbstractTestCase
11+
{
12+
public function testUnionTypes(): void
13+
{
14+
$document = new class([
15+
'data' => [
16+
'id' => '1',
17+
'type' => 'foos',
18+
],
19+
]) extends AbstractDocument {
20+
public Example\ResourceObjectExt|Example\ResourceObject $data;
21+
};
22+
23+
$this->assertInstanceOf(Example\ResourceObjectExt::class, $document->data);
24+
}
25+
}

tests/FreeElephants/JsonApi/DTO/ResourceObjectTestPHP8.php renamed to tests/FreeElephants/JsonApi/DTO/Reflection/ResourceObjectTestPHP8.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
<?php
22

3-
namespace FreeElephants\JsonApi\DTO;
3+
namespace FreeElephants\JsonApi\DTO\Reflection;
44

55
use FreeElephants\JsonApi\AbstractTestCase;
6+
use FreeElephants\JsonApi\DTO\AbstractResourceObject;
7+
use FreeElephants\JsonApi\DTO\Example;
8+
use FreeElephants\JsonApi\DTO\Example\AttributesExt;
69

710
class ResourceObjectTestPHP8 extends AbstractTestCase
811
{
@@ -13,6 +16,7 @@ public function testUnionTypes()
1316
'type' => 'type',
1417
'attributes' => [
1518
'foo' => 'bar',
19+
'baz' => 1,
1620
],
1721
'relationships' => [
1822
'one' => [
@@ -23,11 +27,14 @@ public function testUnionTypes()
2327
],
2428
],
2529
]) extends AbstractResourceObject{
26-
public Example\Attributes $attributes;
30+
public Example\AttributesExt|Example\Attributes $attributes;
2731
public Example\OneRelationships|Example\TwoRelationships $relationships;
2832
};
2933

3034
$this->assertSame('one', $resourceObject->relationships->one->data->type);
35+
$this->assertSame('bar', $resourceObject->attributes->foo);
36+
$this->assertSame(1, $resourceObject->attributes->baz);
37+
$this->assertInstanceOf(AttributesExt::class, $resourceObject->attributes);
3138
}
3239
}
3340

0 commit comments

Comments
 (0)