Skip to content

Commit b62e69c

Browse files
authored
Merge pull request #3594 from alanpoulain/graphql-fix-subresource-dto
2 parents 28bfdf9 + b9a2e13 commit b62e69c

22 files changed

+193
-76
lines changed

features/graphql/input_output.feature

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@ Feature: GraphQL DTO input and output
55

66
@createSchema
77
Scenario: Retrieve an Output with GraphQL
8+
Given there is a RelatedDummy with 0 friends
89
When I add "Content-Type" header equal to "application/ld+json"
910
And I send a "POST" request to "/dummy_dto_input_outputs" with body:
1011
"""
1112
{
1213
"foo": "test",
13-
"bar": 1
14+
"bar": 1,
15+
"relatedDummies": ["/related_dummies/1"]
1416
}
1517
"""
1618
Then the response status code should be 201
@@ -22,20 +24,51 @@ Feature: GraphQL DTO input and output
2224
"hydra": "http://www.w3.org/ns/hydra/core#",
2325
"id": "OutputDto/id",
2426
"baz": "OutputDto/baz",
25-
"bat": "OutputDto/bat"
27+
"bat": "OutputDto/bat",
28+
"relatedDummies": "OutputDto/relatedDummies"
2629
},
2730
"@type": "DummyDtoInputOutput",
2831
"@id": "/dummy_dto_input_outputs/1",
2932
"id": 1,
3033
"baz": 1,
31-
"bat": "test"
34+
"bat": "test",
35+
"relatedDummies": [
36+
{
37+
"@context": "/contexts/RelatedDummy",
38+
"@id": "/related_dummies/1",
39+
"@type": "https://schema.org/Product",
40+
"name": "RelatedDummy with friends",
41+
"dummyDate": null,
42+
"thirdLevel": null,
43+
"relatedToDummyFriend": [],
44+
"dummyBoolean": null,
45+
"embeddedDummy": {
46+
"dummyName": null,
47+
"dummyBoolean": null,
48+
"dummyDate": null,
49+
"dummyFloat": null,
50+
"dummyPrice": null,
51+
"symfony": null
52+
},
53+
"id": 1,
54+
"symfony": "symfony",
55+
"age": null
56+
}
57+
]
3258
}
3359
"""
3460
When I send the following GraphQL request:
3561
"""
3662
{
3763
dummyDtoInputOutput(id: "/dummy_dto_input_outputs/1") {
38-
_id, id, baz
64+
_id, id, baz,
65+
relatedDummies {
66+
edges {
67+
node {
68+
name
69+
}
70+
}
71+
}
3972
}
4073
}
4174
"""
@@ -49,7 +82,16 @@ Feature: GraphQL DTO input and output
4982
"dummyDtoInputOutput": {
5083
"_id": 1,
5184
"id": "/dummy_dto_input_outputs/1",
52-
"baz": 1
85+
"baz": 1,
86+
"relatedDummies": {
87+
"edges": [
88+
{
89+
"node": {
90+
"name": "RelatedDummy with friends"
91+
}
92+
}
93+
]
94+
}
5395
}
5496
}
5597
}

features/jsonld/input_output.feature

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -151,13 +151,15 @@ Feature: JSON-LD DTO input and output
151151
"hydra": "http://www.w3.org/ns/hydra/core#",
152152
"id": "OutputDto/id",
153153
"baz": "OutputDto/baz",
154-
"bat": "OutputDto/bat"
154+
"bat": "OutputDto/bat",
155+
"relatedDummies": "OutputDto/relatedDummies"
155156
},
156157
"@type": "DummyDtoInputOutput",
157158
"@id": "/dummy_dto_input_outputs/1",
158159
"id": 1,
159160
"baz": 1,
160-
"bat": "test"
161+
"bat": "test",
162+
"relatedDummies": []
161163
}
162164
"""
163165
When I add "Accept" header equal to "application/ld+json"
@@ -178,13 +180,15 @@ Feature: JSON-LD DTO input and output
178180
"hydra": "http://www.w3.org/ns/hydra/core#",
179181
"id": "OutputDto/id",
180182
"baz": "OutputDto/baz",
181-
"bat": "OutputDto/bat"
183+
"bat": "OutputDto/bat",
184+
"relatedDummies": "OutputDto/relatedDummies"
182185
},
183186
"@type": "DummyDtoInputOutput",
184187
"@id": "/dummy_dto_input_outputs/1",
185188
"id": 1,
186189
"baz": 2,
187-
"bat": "test"
190+
"bat": "test",
191+
"relatedDummies": []
188192
}
189193
"""
190194

@@ -237,13 +241,15 @@ Feature: JSON-LD DTO input and output
237241
"hydra": "http://www.w3.org/ns/hydra/core#",
238242
"id": "OutputDto/id",
239243
"baz": "OutputDto/baz",
240-
"bat": "OutputDto/bat"
244+
"bat": "OutputDto/bat",
245+
"relatedDummies": "OutputDto/relatedDummies"
241246
},
242247
"@type": "DummyDtoNoInput",
243248
"@id": "/dummy_dto_no_inputs/1",
244249
"id": 1,
245250
"baz": 1,
246-
"bat": "test"
251+
"bat": "test",
252+
"relatedDummies": []
247253
}
248254
"""
249255

@@ -260,13 +266,15 @@ Feature: JSON-LD DTO input and output
260266
"hydra": "http://www.w3.org/ns/hydra/core#",
261267
"id": "OutputDto/id",
262268
"baz": "OutputDto/baz",
263-
"bat": "OutputDto/bat"
269+
"bat": "OutputDto/bat",
270+
"relatedDummies": "OutputDto/relatedDummies"
264271
},
265272
"@type": "DummyDtoNoInput",
266273
"@id": "/dummy_dto_no_inputs/1",
267274
"id": 1,
268275
"baz": 1,
269-
"bat": "testtest"
276+
"bat": "testtest",
277+
"relatedDummies": []
270278
}
271279
"""
272280

src/GraphQl/Resolver/Stage/ReadStage.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,10 @@ public function __invoke(?string $resourceClass, ?string $rootClass, string $ope
9292
$normalizationContext['filters'] = $this->getNormalizedFilters($args);
9393

9494
$source = $context['source'];
95-
if (isset($source[$rootProperty = $info->fieldName], $source[ItemNormalizer::ITEM_IDENTIFIERS_KEY])) {
95+
if (isset($source[$rootProperty = $info->fieldName], $source[ItemNormalizer::ITEM_IDENTIFIERS_KEY], $source[ItemNormalizer::ITEM_RESOURCE_CLASS_KEY])) {
9696
$rootResolvedFields = $source[ItemNormalizer::ITEM_IDENTIFIERS_KEY];
97-
$subresourceCollection = $this->getSubresource($rootClass, $rootResolvedFields, $rootProperty, $resourceClass, $normalizationContext, $operationName);
97+
$rootResolvedClass = $source[ItemNormalizer::ITEM_RESOURCE_CLASS_KEY];
98+
$subresourceCollection = $this->getSubresource($rootResolvedClass, $rootResolvedFields, $rootProperty, $resourceClass, $normalizationContext, $operationName);
9899
if (!is_iterable($subresourceCollection)) {
99100
throw new \UnexpectedValueException('Expected subresource collection to be iterable');
100101
}
@@ -158,12 +159,12 @@ private function getNormalizedFilters(array $args): array
158159
/**
159160
* @return iterable|object|null
160161
*/
161-
private function getSubresource(string $rootClass, array $rootResolvedFields, string $rootProperty, string $subresourceClass, array $normalizationContext, string $operationName)
162+
private function getSubresource(string $rootResolvedClass, array $rootResolvedFields, string $rootProperty, string $subresourceClass, array $normalizationContext, string $operationName)
162163
{
163164
$resolvedIdentifiers = [];
164165
$rootIdentifiers = array_keys($rootResolvedFields);
165166
foreach ($rootIdentifiers as $rootIdentifier) {
166-
$resolvedIdentifiers[] = [$rootIdentifier, $rootClass];
167+
$resolvedIdentifiers[] = [$rootIdentifier, $rootResolvedClass];
167168
}
168169

169170
return $this->subresourceDataProvider->getSubresource($subresourceClass, $rootResolvedFields, $normalizationContext + [

tests/Bridge/Doctrine/MongoDbOdm/PropertyInfo/DoctrineExtractorTest.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ public function testGetProperties(): void
6060
'integer',
6161
'string',
6262
'key',
63-
'file',
6463
'hash',
6564
'collection',
6665
'objectId',
@@ -149,7 +148,6 @@ public function typesProvider(): array
149148
['integer', [new Type(Type::BUILTIN_TYPE_INT)]],
150149
['string', [new Type(Type::BUILTIN_TYPE_STRING)]],
151150
['key', [new Type(Type::BUILTIN_TYPE_INT)]],
152-
['file', null],
153151
['hash', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true)]],
154152
['collection', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(TYPE::BUILTIN_TYPE_INT))]],
155153
['objectId', [new Type(Type::BUILTIN_TYPE_STRING)]],
@@ -208,8 +206,8 @@ private function createExtractor(): DoctrineExtractor
208206
$config = DoctrineMongoDbOdmSetup::createAnnotationMetadataConfiguration([__DIR__.\DIRECTORY_SEPARATOR.'Fixtures'], true);
209207
$documentManager = DocumentManager::create(null, $config);
210208

211-
if (!MongoDbType::hasType('foo')) {
212-
MongoDbType::addType('foo', DoctrineFooType::class);
209+
if (!MongoDbType::hasType('custom_foo')) {
210+
MongoDbType::addType('custom_foo', DoctrineFooType::class);
213211
}
214212

215213
return new DoctrineExtractor($documentManager);

tests/Bridge/Doctrine/MongoDbOdm/PropertyInfo/Fixtures/DoctrineDummy.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,11 +131,6 @@ class DoctrineDummy
131131
*/
132132
private $key;
133133

134-
/**
135-
* @Field(type="file")
136-
*/
137-
private $file;
138-
139134
/**
140135
* @Field(type="hash")
141136
*/

tests/Fixtures/TestBundle/DataPersister/DummyDtoNoOutputDataPersister.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
use ApiPlatform\Core\DataPersister\DataPersisterInterface;
1717
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\DummyDtoNoOutput as DummyDtoNoOutputDocument;
18+
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Dto\Document\InputDto as InputDtoDocument;
1819
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Dto\InputDto;
1920
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\DummyDtoNoOutput;
2021
use Doctrine\Common\Persistence\ManagerRegistry;
@@ -33,7 +34,7 @@ public function __construct(ManagerRegistry $registry)
3334
*/
3435
public function supports($data): bool
3536
{
36-
return $data instanceof InputDto;
37+
return $data instanceof InputDto || $data instanceof InputDtoDocument;
3738
}
3839

3940
/**

tests/Fixtures/TestBundle/DataProvider/DummyDtoNoInputCollectionDataProvider.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use ApiPlatform\Core\DataProvider\ContextAwareCollectionDataProviderInterface;
1818
use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
1919
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\DummyDtoNoInput as DummyDtoNoInputDocument;
20+
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Dto\Document\OutputDto as OutputDtoDocument;
2021
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Dto\OutputDto;
2122
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\DummyDtoNoInput;
2223
use Doctrine\Common\Persistence\ManagerRegistry;
@@ -50,7 +51,7 @@ public function getCollection(string $resourceClass, string $operationName = nul
5051
$dummyDtos = $this->registry->getManagerForClass($resourceClass)->getRepository($resourceClass)->findAll();
5152
$objects = [];
5253
foreach ($dummyDtos as $dummyDto) {
53-
$object = new OutputDto();
54+
$object = DummyDtoNoInput::class === $resourceClass ? new OutputDto() : new OutputDtoDocument();
5455
$object->bat = $dummyDto->lorem;
5556
$object->baz = $dummyDto->ipsum;
5657
$objects[] = $object;

tests/Fixtures/TestBundle/DataProvider/SerializableItemDataProvider.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@
1717
use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
1818
use ApiPlatform\Core\DataProvider\SerializerAwareDataProviderInterface;
1919
use ApiPlatform\Core\DataProvider\SerializerAwareDataProviderTrait;
20-
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\SerializableResource as SerializableResourceDocument;
21-
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\SerializableResource;
20+
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Model\SerializableResource;
2221

2322
/**
2423
* @author Vincent Chalamon <[email protected]>
@@ -47,6 +46,6 @@ public function getItem(string $resourceClass, $id, string $operationName = null
4746
*/
4847
public function supports(string $resourceClass, string $operationName = null, array $context = []): bool
4948
{
50-
return \in_array($resourceClass, [SerializableResource::class, SerializableResourceDocument::class], true);
49+
return SerializableResource::class === $resourceClass;
5150
}
5251
}

tests/Fixtures/TestBundle/DataTransformer/DummyDtoNoInputToOutputDtoDataTransformer.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
use ApiPlatform\Core\DataTransformer\DataTransformerInterface;
1717
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\DummyDtoNoInput as DummyDtoNoInputDocument;
18+
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Dto\Document\OutputDto as OutputDtoDocument;
1819
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Dto\OutputDto;
1920
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\DummyDtoNoInput;
2021

@@ -29,7 +30,7 @@ public function transform($object, string $to, array $context = [])
2930
throw new \InvalidArgumentException();
3031
}
3132

32-
$output = new OutputDto();
33+
$output = $object instanceof DummyDtoNoInput ? new OutputDto() : new OutputDtoDocument();
3334
$output->id = $object->getId();
3435
$output->bat = (string) $object->lorem;
3536
$output->baz = (float) $object->ipsum;
@@ -42,6 +43,6 @@ public function transform($object, string $to, array $context = [])
4243
*/
4344
public function supportsTransformation($data, string $to, array $context = []): bool
4445
{
45-
return ($data instanceof DummyDtoNoInput || $data instanceof DummyDtoNoInputDocument) && OutputDto::class === $to;
46+
return ($data instanceof DummyDtoNoInput || $data instanceof DummyDtoNoInputDocument) && \in_array($to, [OutputDto::class, OutputDtoDocument::class], true);
4647
}
4748
}

tests/Fixtures/TestBundle/DataTransformer/InputDtoDataTransformer.php

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use ApiPlatform\Core\DataTransformer\DataTransformerInterface;
1717
use ApiPlatform\Core\Serializer\AbstractItemNormalizer;
1818
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\DummyDtoInputOutput as DummyDtoInputOutputDocument;
19+
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Dto\Document\InputDto as InputDtoDocument;
1920
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Dto\InputDto;
2021
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\DummyDtoInputOutput;
2122

@@ -26,17 +27,15 @@ final class InputDtoDataTransformer implements DataTransformerInterface
2627
*/
2728
public function transform($object, string $to, array $context = [])
2829
{
29-
/**
30-
* @var \ApiPlatform\Core\Tests\Fixtures\TestBundle\Dto\InputDto
31-
*/
30+
/** @var InputDtoDocument|InputDto */
3231
$data = $object;
3332

34-
/**
35-
* @var \ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\DummyDtoInputOutput
36-
*/
33+
/** @var DummyDtoInputOutputDocument|DummyDtoInputOutput */
3734
$resourceObject = $context[AbstractItemNormalizer::OBJECT_TO_POPULATE] ?? new $context['resource_class']();
3835
$resourceObject->str = $data->foo;
3936
$resourceObject->num = $data->bar;
37+
// @phpstan-ignore-next-line
38+
$resourceObject->relatedDummies = $data->relatedDummies;
4039

4140
return $resourceObject;
4241
}
@@ -50,6 +49,6 @@ public function supportsTransformation($object, string $to, array $context = [])
5049
return false;
5150
}
5251

53-
return (DummyDtoInputOutput::class === $to || DummyDtoInputOutputDocument::class === $to) && (InputDto::class === $context['input']['class']);
52+
return \in_array($to, [DummyDtoInputOutput::class, DummyDtoInputOutputDocument::class], true) && \in_array($context['input']['class'], [InputDto::class, InputDtoDocument::class], true);
5453
}
5554
}

tests/Fixtures/TestBundle/DataTransformer/OutputDtoDataTransformer.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313

1414
namespace ApiPlatform\Core\Tests\Fixtures\TestBundle\DataTransformer;
1515

16+
use ApiPlatform\Core\DataProvider\ArrayPaginator;
1617
use ApiPlatform\Core\DataTransformer\DataTransformerInterface;
1718
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\DummyDtoInputOutput as DummyDtoInputOutputDocument;
19+
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Dto\Document\OutputDto as OutputDtoDocument;
1820
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Dto\OutputDto;
1921
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\DummyDtoInputOutput;
2022

@@ -29,10 +31,12 @@ public function transform($object, string $to, array $context = [])
2931
throw new \InvalidArgumentException();
3032
}
3133

32-
$output = new OutputDto();
34+
$output = $object instanceof DummyDtoInputOutput ? new OutputDto() : new OutputDtoDocument();
3335
$output->id = $object->id;
3436
$output->bat = (string) $object->str;
3537
$output->baz = (float) $object->num;
38+
// @phpstan-ignore-next-line
39+
$output->relatedDummies = new ArrayPaginator($object->relatedDummies->toArray(), 0, \count($object->relatedDummies->toArray()));
3640

3741
return $output;
3842
}
@@ -42,6 +46,6 @@ public function transform($object, string $to, array $context = [])
4246
*/
4347
public function supportsTransformation($data, string $to, array $context = []): bool
4448
{
45-
return ($data instanceof DummyDtoInputOutput || $data instanceof DummyDtoInputOutputDocument) && OutputDto::class === $to;
49+
return ($data instanceof DummyDtoInputOutput || $data instanceof DummyDtoInputOutputDocument) && \in_array($to, [OutputDto::class, OutputDtoDocument::class], true);
4650
}
4751
}

tests/Fixtures/TestBundle/Document/Dummy.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -216,10 +216,6 @@ public function getDescription()
216216
return $this->description;
217217
}
218218

219-
public function hasRole($role)
220-
{
221-
}
222-
223219
public function getFoo()
224220
{
225221
return $this->foo;

0 commit comments

Comments
 (0)