Skip to content

Commit 08f9c93

Browse files
committed
GraphQl: parse input&messenger metadata
1 parent 294afdc commit 08f9c93

File tree

10 files changed

+87
-11
lines changed

10 files changed

+87
-11
lines changed

features/main/input_output.feature

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,3 +287,29 @@ Feature: DTO input and output
287287
"data": 123
288288
}
289289
"""
290+
291+
@!mongodb
292+
Scenario: Use messenger with graphql and an input where the handler gives a synchronous result
293+
When I send the following GraphQL request:
294+
"""
295+
mutation {
296+
createMessengerWithInput(input: {var: "test"}) {
297+
messengerWithInput { id, name }
298+
}
299+
}
300+
"""
301+
Then the response status code should be 200
302+
And the response should be in JSON
303+
And the JSON should be equal to:
304+
"""
305+
{
306+
"data": {
307+
"createMessengerWithInput": {
308+
"messengerWithInput": {
309+
"id": "/messenger_with_inputs/1",
310+
"name": "test"
311+
}
312+
}
313+
}
314+
}
315+
"""

src/Bridge/Symfony/Messenger/DataPersister.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ public function supports($data, array $context = []): bool
6363
);
6464
}
6565

66+
if (isset($context['graphql_operation_name'])) {
67+
return false !== $resourceMetadata->getGraphqlAttribute($context['graphql_operation_name'], 'messenger', false, true);
68+
}
69+
6670
return false !== $resourceMetadata->getAttribute('messenger', false);
6771
}
6872

src/Bridge/Symfony/Messenger/DataTransformer.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ public function supportsTransformation($data, string $to, array $context = []):
5555

5656
$metadata = $this->resourceMetadataFactory->create($context['resource_class'] ?? $to);
5757

58+
if (isset($context['graphql_operation_name'])) {
59+
return 'input' === $metadata->getGraphqlAttribute($context['graphql_operation_name'], 'messenger', null, true);
60+
}
61+
5862
if (!isset($context['operation_type'])) {
5963
return 'input' === $metadata->getAttribute('messenger');
6064
}

src/GraphQl/Resolver/Factory/ItemMutationResolverFactory.php

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,19 +94,27 @@ public function __invoke(string $resourceClass = null, string $rootClass = null,
9494

9595
$this->canAccess($this->resourceAccessChecker, $resourceMetadata, $resourceClass, $info, $item, $operationName);
9696

97-
$inputMetadata = $resourceMetadata->getAttribute('input', ['class' => $resourceClass]);
98-
if (null === $resourceClass = $inputMetadata['class'] ?? null) {
99-
return $data;
97+
$inputMetadata = $resourceMetadata->getGraphqlAttribute($operationName, 'input', null, true);
98+
$inputClass = null;
99+
if (\is_array($inputMetadata) && \array_key_exists('class', $inputMetadata)) {
100+
if (null === $inputMetadata['class']) {
101+
return $data;
102+
}
103+
104+
$inputClass = $inputMetadata['class'];
100105
}
101106

102107
switch ($operationName) {
103108
case 'create':
104109
case 'update':
105-
$context = null === $item ? ['resource_class' => $resourceClass] : ['resource_class' => $resourceClass, 'object_to_populate' => $item];
110+
$context = ['resource_class' => $resourceClass, 'graphql_operation_name' => $operationName];
111+
if (null !== $item) {
112+
$context['object_to_populate'] = $item;
113+
}
106114
$context += $resourceMetadata->getGraphqlAttribute($operationName, 'denormalization_context', [], true);
107-
$item = $this->normalizer->denormalize($args['input'], $resourceClass, ItemNormalizer::FORMAT, $context);
115+
$item = $this->normalizer->denormalize($args['input'], $inputClass ?: $resourceClass, ItemNormalizer::FORMAT, $context);
108116
$this->validate($item, $info, $resourceMetadata, $operationName);
109-
$persistResult = $this->dataPersister->persist($item);
117+
$persistResult = $this->dataPersister->persist($item, $context);
110118

111119
if (null === $persistResult) {
112120
@trigger_error(sprintf('Returning void from %s::persist() is deprecated since API Platform 2.3 and will not be supported in API Platform 3, an object should always be returned.', DataPersisterInterface::class), E_USER_DEPRECATED);

src/GraphQl/Type/SchemaBuilder.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -419,8 +419,7 @@ private function getResourceObjectType(?string $resourceClass, ResourceMetadata
419419
return $this->graphqlTypes[$shortName];
420420
}
421421

422-
$ioMetadata = $resourceMetadata->getAttribute($input ? 'input' : 'output');
423-
422+
$ioMetadata = $resourceMetadata->getGraphqlAttribute(null === $mutationName ? 'query' : $mutationName, $input ? 'input' : 'output', null, true);
424423
if (null !== $ioMetadata && \array_key_exists('class', $ioMetadata) && null !== $ioMetadata['class']) {
425424
$resourceClass = $ioMetadata['class'];
426425
}

src/Metadata/Resource/Factory/InputOutputResourceMetadataFactory.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ public function create(string $resourceClass): ResourceMetadata
4848
$resourceMetadata = $resourceMetadata->withItemOperations($this->getTransformedOperations($itemOperations, $attributes));
4949
}
5050

51+
if (null !== $graphQlAttributes = $resourceMetadata->getGraphql()) {
52+
$resourceMetadata = $resourceMetadata->withGraphql($this->getTransformedOperations($graphQlAttributes, $attributes));
53+
}
54+
5155
return $resourceMetadata->withAttributes($attributes);
5256
}
5357

tests/Bridge/Symfony/Messenger/DataPersisterTest.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,13 @@ public function testHandle()
8585
$dataPersister = new DataPersister($this->prophesize(ResourceMetadataFactoryInterface::class)->reveal(), $messageBus->reveal());
8686
$this->assertSame($dummy, $dataPersister->persist($dummy));
8787
}
88+
89+
public function testSupportWithGraphqlContext()
90+
{
91+
$metadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class);
92+
$metadataFactoryProphecy->create(Dummy::class)->willReturn((new ResourceMetadata(null, null, null, null, null, []))->withGraphQl(['create' => ['messenger' => 'input']]));
93+
94+
$dataPersister = new DataPersister($metadataFactoryProphecy->reveal(), $this->prophesize(MessageBusInterface::class)->reveal());
95+
$this->assertTrue($dataPersister->supports(new DummyCar(), ['resource_class' => Dummy::class, 'graphql_operation_name' => 'create']));
96+
}
8897
}

tests/Bridge/Symfony/Messenger/DataTransformerTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,12 @@ public function testTransform()
8686
$dataTransformer = new DataTransformer($metadataFactoryProphecy->reveal());
8787
$this->assertSame($dummy, $dataTransformer->transform($dummy, Dummy::class));
8888
}
89+
90+
public function testSupportWithGraphqlContext()
91+
{
92+
$metadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class);
93+
$metadataFactoryProphecy->create(Dummy::class)->willReturn((new ResourceMetadata(null, null, null, null, null, []))->withGraphQl(['create' => ['messenger' => 'input']]));
94+
$dataTransformer = new DataTransformer($metadataFactoryProphecy->reveal());
95+
$this->assertTrue($dataTransformer->supportsTransformation([], Dummy::class, ['input' => ['class' => 'smth'], 'graphql_operation_name' => 'create']));
96+
}
8997
}

tests/Fixtures/TestBundle/Entity/MessengerWithInput.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Dto\MessengerInput;
1919

2020
/**
21-
* @ApiResource(messenger="input", input=MessengerInput::class)
21+
* @ApiResource(messenger="input", input=MessengerInput::class, graphql={"create"={"input"=MessengerInput::class, "messenger"="input"}})
2222
*/
2323
class MessengerWithInput
2424
{

tests/Metadata/Resource/Factory/InputOutputResourceMetadataFactoryTest.php

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ class InputOutputResourceMetadataFactoryTest extends TestCase
2424
/**
2525
* @dataProvider getAttributes
2626
*/
27-
public function testExistingDescription($attributes, $expected)
27+
public function testInputOutputMetadata($attributes, $expected)
2828
{
29-
$resourceMetadata = (new ResourceMetadata(null, 'My desc'))->withAttributes($attributes);
29+
$resourceMetadata = (new ResourceMetadata(null))->withAttributes($attributes);
3030
$decoratedProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class);
3131
$decoratedProphecy->create('Foo')->willReturn($resourceMetadata)->shouldBeCalled();
3232
$decorated = $decoratedProphecy->reveal();
@@ -35,6 +35,20 @@ public function testExistingDescription($attributes, $expected)
3535
$this->assertSame($expected, $factory->create('Foo')->getAttributes()['input']);
3636
}
3737

38+
/**
39+
* @dataProvider getAttributes
40+
*/
41+
public function testInputOutputViaGraphQlMetadata($attributes, $expected)
42+
{
43+
$resourceMetadata = (new ResourceMetadata(null))->withGraphQl(['create' => $attributes]);
44+
$decoratedProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class);
45+
$decoratedProphecy->create('Foo')->willReturn($resourceMetadata)->shouldBeCalled();
46+
$decorated = $decoratedProphecy->reveal();
47+
48+
$factory = new InputOutputResourceMetadataFactory($decorated);
49+
$this->assertSame($expected, $factory->create('Foo')->getGraphqlAttribute('create', 'input'));
50+
}
51+
3852
public function getAttributes(): array
3953
{
4054
return [

0 commit comments

Comments
 (0)