Skip to content

Commit 645a270

Browse files
committed
Put mutation for an item
1 parent be9b7fa commit 645a270

File tree

5 files changed

+82
-10
lines changed

5 files changed

+82
-10
lines changed

features/graphql/mutation.feature

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ Feature: GraphQL mutation support
5050
And the header "Content-Type" should be equal to "application/json"
5151
And the JSON node "data.deleteDummy.id" should be equal to 1
5252

53-
@dropSchema
5453
Scenario: Delete an item with composite identifiers through a mutation
5554
Given there are Composite identifier objects
5655
When I send the following GraphQL request:
@@ -71,3 +70,47 @@ Feature: GraphQL mutation support
7170
And the header "Content-Type" should be equal to "application/json"
7271
And the JSON node "data.deleteCompositeRelation.compositeItem.id" should be equal to 1
7372
And the JSON node "data.deleteCompositeRelation.compositeLabel.id" should be equal to 1
73+
74+
Scenario: Modify an item through a mutation
75+
Given there is 1 dummy objects
76+
When I send the following GraphQL request:
77+
"""
78+
mutation {
79+
putDummy(input: {id: 1, description: "Modified description."}) {
80+
id,
81+
name,
82+
description
83+
}
84+
}
85+
"""
86+
Then the response status code should be 200
87+
And the response should be in JSON
88+
And the header "Content-Type" should be equal to "application/json"
89+
And the JSON node "data.putDummy.id" should be equal to 1
90+
And the JSON node "data.putDummy.name" should be equal to "Dummy #1"
91+
And the JSON node "data.putDummy.description" should be equal to "Modified description."
92+
93+
@dropSchema
94+
# @TODO Find a way to manage composite identifiers.
95+
Scenario: Modify an item with composite identifiers through a mutation
96+
Given there are Composite identifier objects
97+
When I send the following GraphQL request:
98+
"""
99+
mutation {
100+
putCompositeRelation(input: {compositeItem: {id: 1}, compositeLabel: {id: 1}, value: "Modified value."}) {
101+
compositeItem {
102+
id
103+
},
104+
compositeLabel {
105+
id
106+
},
107+
value
108+
}
109+
}
110+
"""
111+
#Then the response status code should be 200
112+
#And the response should be in JSON
113+
#And the header "Content-Type" should be equal to "application/json"
114+
#And the JSON node "data.putCompositeRelation.compositeItem.id" should be equal to 1
115+
#And the JSON node "data.putCompositeRelation.compositeLabel.id" should be equal to 1
116+
#And the JSON node "data.putCompositeRelation.value" should be equal to "Modified value."

src/Bridge/Graphql/Resolver/ItemMutationResolverFactory.php

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616
use ApiPlatform\Core\Api\IdentifiersExtractorInterface;
1717
use ApiPlatform\Core\DataPersister\DataPersisterInterface;
1818
use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
19+
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
1920
use GraphQL\Error\Error;
2021
use GraphQL\Type\Definition\ResolveInfo;
22+
use Symfony\Component\Serializer\Serializer;
2123

2224
/**
2325
* Creates a function resolving a GraphQL mutation of an item.
@@ -30,12 +32,16 @@ final class ItemMutationResolverFactory implements ItemMutationResolverFactoryIn
3032
{
3133
private $identifiersExtractor;
3234
private $itemDataProvider;
35+
private $serializer;
36+
private $resourceMetadataFactory;
3337
private $dataPersister;
3438

35-
public function __construct(IdentifiersExtractorInterface $identifiersExtractor, ItemDataProviderInterface $itemDataProvider, DataPersisterInterface $dataPersister)
39+
public function __construct(IdentifiersExtractorInterface $identifiersExtractor, ItemDataProviderInterface $itemDataProvider, Serializer $serializer, ResourceMetadataFactoryInterface $resourceMetadataFactory, DataPersisterInterface $dataPersister)
3640
{
3741
$this->identifiersExtractor = $identifiersExtractor;
3842
$this->itemDataProvider = $itemDataProvider;
43+
$this->serializer = $serializer;
44+
$this->resourceMetadataFactory = $resourceMetadataFactory;
3945
$this->dataPersister = $dataPersister;
4046
}
4147

@@ -59,17 +65,30 @@ public function createItemMutationResolver(string $resourceClass, string $operat
5965
} else {
6066
$id = $args['input'][$identifiers[0]];
6167
}
62-
$item = $this->itemDataProvider->getItem($resourceClass, $id);
63-
64-
if (null === $item) {
65-
throw Error::createLocatedError("Item $resourceClass $id not found", $info->fieldNodes, $info->path);
66-
}
6768

6869
if ('delete' === $operationName) {
70+
$item = $this->itemDataProvider->getItem($resourceClass, $id);
71+
72+
if (null === $item) {
73+
throw Error::createLocatedError("Item $resourceClass $id not found", $info->fieldNodes, $info->path);
74+
}
75+
6976
$this->dataPersister->remove($item);
70-
}
7177

72-
return $args['input'];
78+
return $args['input'];
79+
} elseif ('put' === $operationName) {
80+
$item = $this->serializer->denormalize($args['input'], $resourceClass, null, ['resource_class' => $resourceClass]);
81+
82+
$this->dataPersister->persist($item);
83+
84+
return $this->serializer->normalize(
85+
$item,
86+
null,
87+
['graphql' => true] + $this->resourceMetadataFactory
88+
->create($resourceClass)
89+
->getItemOperationAttribute($operationName, 'normalization_context', [], true)
90+
);
91+
}
7392
};
7493
}
7594
}

src/Bridge/Graphql/Type/SchemaBuilder.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ private function convertType(Type $type, string $operationName, bool $isInput =
259259
return $this->paginationEnabled ? $this->getResourcePaginatedCollectionType($graphqlType, $isInput) : GraphQLType::listOf($graphqlType);
260260
}
261261

262-
return $type->isNullable() ? $graphqlType : GraphQLType::nonNull($graphqlType);
262+
return $type->isNullable() || ($isMutation && 'put' === $operationName) ? $graphqlType : GraphQLType::nonNull($graphqlType);
263263
}
264264

265265
/**

src/Bridge/Symfony/Bundle/Resources/config/graphql.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
<service id="api_platform.graphql.item_mutation_resolver_factory" class="ApiPlatform\Core\Bridge\Graphql\Resolver\ItemMutationResolverFactory" public="false">
2929
<argument type="service" id="api_platform.identifiers_extractor.cached" />
3030
<argument type="service" id="api_platform.item_data_provider" />
31+
<argument type="service" id="serializer" />
32+
<argument type="service" id="api_platform.metadata.resource.metadata_factory" />
3133
<argument type="service" id="api_platform.data_persister" />
3234
</service>
3335

tests/Bridge/Graphql/Resolver/ItemMutationResolverFactoryTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@
1717
use ApiPlatform\Core\Bridge\Graphql\Resolver\ItemMutationResolverFactory;
1818
use ApiPlatform\Core\DataPersister\DataPersisterInterface;
1919
use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
20+
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
2021
use GraphQL\Type\Definition\ResolveInfo;
2122
use PHPUnit\Framework\TestCase;
2223
use Prophecy\Argument;
2324
use Prophecy\Prophecy\ObjectProphecy;
25+
use Symfony\Component\Serializer\Serializer;
2426

2527
/**
2628
* @author Alan Poulain <[email protected]>
@@ -107,9 +109,15 @@ private function mockItemMutationResolverFactory($item, array $identifiers, $fla
107109
$itemDataProviderProphecy = $this->prophesize(ItemDataProviderInterface::class);
108110
$itemDataProviderProphecy->getItem('resourceClass', $flatId)->willReturn($item);
109111

112+
$serializerProphecy = $this->prophesize(Serializer::class);
113+
114+
$resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class);
115+
110116
return new ItemMutationResolverFactory(
111117
$identifiersExtractorProphecy->reveal(),
112118
$itemDataProviderProphecy->reveal(),
119+
$serializerProphecy->reveal(),
120+
$resourceMetadataFactoryProphecy->reveal(),
113121
$dataPersisterProphecy->reveal()
114122
);
115123
}

0 commit comments

Comments
 (0)