Skip to content

Commit d7061f2

Browse files
author
n.gnato
committed
Handle union types
1 parent 30f45b6 commit d7061f2

File tree

8 files changed

+81
-9
lines changed

8 files changed

+81
-9
lines changed

CHANGELOG.md

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

77
## [Unreleased]
88

9+
### Fixed
10+
- Handle Union Types for `data` and `attributes` fields.
11+
912
## [0.0.5] - 2025-03-24
1013

1114
### Fixed

src/FreeElephants/JsonApi/DTO/AbstractDocument.php

Lines changed: 7 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,14 @@ 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+
}
1922
if ($dataClassName !== 'array') {
2023
$data = new $dataClassName($payload['data']);
2124
} 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)