Skip to content

Commit 0ca6307

Browse files
authored
Merge pull request #2 from developerstudservis/collections-support
Collections support
2 parents 8a2563c + 64b1127 commit 0ca6307

File tree

7 files changed

+132
-18
lines changed

7 files changed

+132
-18
lines changed

.github/workflows/ci.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
name: CI
22

3-
on: push
3+
on:
4+
- push
5+
- pull_request
46

57
jobs:
68
php-tests:

CHANGELOG.md

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

77
## [Unreleased]
88

9+
## [0.0.2] - 2025-03-14
10+
11+
### Added
12+
- AbstractCollection for handle array of resources in data field
13+
- Exception on pass array as data into AbstractDocument constructor
14+
915
## [0.0.1] - 2025-03-13
1016

1117
### Added
1218
- Extract all DTO types from FreeElephants/json-api-php-toolkit to this project
1319

14-
[Unreleased]: https://github.com/FreeElephants/json-api-dto/compare/0.0.1...HEAD
20+
[Unreleased]: https://github.com/FreeElephants/json-api-dto/compare/0.0.2...HEAD
21+
[0.0.2]: https://github.com/FreeElephants/json-api-dto/releases/tag/0.0.2
1522
[0.0.1]: https://github.com/FreeElephants/json-api-dto/releases/tag/0.0.1
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace FreeElephants\JsonApi\DTO;
5+
6+
abstract class AbstractCollection extends TopLevel
7+
{
8+
public array $data = [];
9+
10+
final public function __construct(array $payload = [])
11+
{
12+
foreach ($payload['data'] as $item) {
13+
$dataItemClassName = $this->getDataItemClassName();
14+
$this->data[] = new $dataItemClassName($item);
15+
}
16+
}
17+
18+
abstract public function getDataItemClassName(): string;
19+
}

src/FreeElephants/JsonApi/DTO/AbstractDocument.php

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,20 @@
77
/**
88
* @property AbstractResourceObject|mixed $data
99
*/
10-
abstract class AbstractDocument
10+
abstract class AbstractDocument extends TopLevel
1111
{
12-
final public function __construct(array $data)
12+
final public function __construct(array $payload)
1313
{
1414
$concreteClass = new \ReflectionClass($this);
1515
$dataProperty = $concreteClass->getProperty('data');
1616
/** @var \ReflectionNamedType $reflectionType */
1717
$reflectionType = $dataProperty->getType();
1818
$dataClassName = $reflectionType->getName();
19-
$this->data = new $dataClassName($data['data']);
20-
}
21-
22-
/**
23-
* @param MessageInterface $httpMessage
24-
* @return static
25-
*/
26-
public static function fromHttpMessage(MessageInterface $httpMessage): self
27-
{
28-
$httpMessage->getBody()->rewind();
29-
$rawJson = $httpMessage->getBody()->getContents();
30-
$decodedJson = json_decode($rawJson, true);
31-
32-
return new static($decodedJson);
19+
if ($dataClassName !== 'array') {
20+
$data = new $dataClassName($payload['data']);
21+
} else {
22+
throw new \UnexpectedValueException('`data` property must be typed, for array of resources use AbstractCollection instead ' . self::class);
23+
}
24+
$this->data = $data;
3325
}
3426
}
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;
5+
6+
use Psr\Http\Message\MessageInterface;
7+
8+
/**
9+
* @property AbstractResourceObject|AbstractResourceObject[] $data
10+
*/
11+
abstract class TopLevel
12+
{
13+
/**
14+
* @param MessageInterface $httpMessage
15+
* @return static
16+
*/
17+
public static function fromHttpMessage(MessageInterface $httpMessage): self
18+
{
19+
$httpMessage->getBody()->rewind();
20+
$rawJson = $httpMessage->getBody()->getContents();
21+
$decodedJson = json_decode($rawJson, true);
22+
23+
return new static($decodedJson);
24+
}
25+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace FreeElephants\JsonApi\DTO;
5+
6+
use FreeElephants\JsonApi\AbstractTestCase;
7+
use FreeElephants\JsonApi\DTO\Example\SomeCollectionDocument;
8+
use Nyholm\Psr7\ServerRequest;
9+
10+
class CollectionTest extends AbstractTestCase
11+
{
12+
public function testCollectionFromHttpMessage(): void
13+
{
14+
$request = new ServerRequest('GET', '/foos');
15+
$request->getBody()->write(<<<JSON
16+
{
17+
"data": [
18+
{
19+
"id": "123",
20+
"type": "foo",
21+
"attributes": {
22+
"foo": "bar",
23+
"date": "2012-04-23T18:25:43.511Z",
24+
"nested": {
25+
"someNestedStructure": {
26+
"someKey": "someValue"
27+
}
28+
}
29+
},
30+
"relationships": {
31+
"baz": {
32+
"data": {
33+
"type": "bazs",
34+
"id": "baz-id"
35+
}
36+
}
37+
}
38+
}
39+
]
40+
}
41+
JSON
42+
);
43+
44+
$collectionDto = SomeCollectionDocument::fromHttpMessage($request);
45+
46+
$this->assertCount(1, $collectionDto->data);
47+
$this->assertSame('123', $collectionDto->data[0]->id);
48+
$this->assertSame('foo', $collectionDto->data[0]->type);
49+
}
50+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace FreeElephants\JsonApi\DTO\Example;
5+
6+
use FreeElephants\JsonApi\DTO\AbstractCollection;
7+
use FreeElephants\JsonApi\DTO\AbstractResourceObject;
8+
9+
class SomeCollectionDocument extends AbstractCollection
10+
{
11+
public function getDataItemClassName(): string
12+
{
13+
return DataItemResourceObject::class;
14+
}
15+
}
16+
17+
class DataItemResourceObject extends AbstractResourceObject
18+
{
19+
}

0 commit comments

Comments
 (0)