Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## 2.7.0

* GraphQL: Add ability to use different pagination types for the queries of a resource (#4453)
* Security: **BC** Fix `ApiProperty` `security` attribute expression being passed a class string for the `object` variable on updates/creates - null is now passed instead if the object is not available (#4184)
* Security: `ApiProperty` now supports a `security_post_denormalize` attribute, which provides access to the `object` variable for the object being updated/created and `previous_object` for the object before it was updated (#4184)
* Maker: Add `make:data-provider` and `make :data-persister` commands to generate a data provider / persister (#3850)
Expand Down Expand Up @@ -231,7 +232,7 @@ For compatibility reasons with Symfony 5.2 and PHP 8, we do not test anymore the
* Doctrine: Order filter doesn't throw anymore with numeric key (#3673 and #3687)
* Doctrine: Fix ODM check change tracking deferred (#3629)
* Doctrine: Allow 2inflector version 2.0 (#3607)
* OpenAPI: Allow subresources context to be added (#3685)
* OpenAPI: Allow subresources context to be added (#3685)
* OpenAPI: Fix pagination documentation on subresources (#3678)
* Subresource: Fix query when using a custom identifier (#3529 and #3671)
* GraphQL: Fix relation types without Doctrine (#3591)
Expand Down Expand Up @@ -337,7 +338,7 @@ For compatibility reasons with Symfony 5.2 and PHP 8, we do not test anymore the
## 2.5.0 beta 1

* Add an HTTP client dedicated to functional API testing (#2608)
* Add PATCH support (#2895)
* Add PATCH support (#2895)
Note: with JSON Merge Patch, responses will skip null values. As this may break on some endpoints, you need to manually [add the `merge-patch+json` format](https://api-platform.com/docs/core/content-negotiation/#configuring-patch-formats) to enable PATCH support. This will be the default behavior in API Platform 3.
* Add a command to generate json schemas `api:json-schema:generate` (#2996)
* Add infrastructure to generate a JSON Schema from a Resource `ApiPlatform\Core\JsonSchema\SchemaFactoryInterface` (#2983)
Expand Down
2 changes: 1 addition & 1 deletion features/graphql/collection.feature
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Feature: GraphQL collection support
...dummyFields
}
}
fragment dummyFields on DummyConnection {
fragment dummyFields on DummyCursorConnection {
edges {
node {
id
Expand Down
10 changes: 5 additions & 5 deletions features/graphql/introspection.feature
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Feature: GraphQL introspection support
}
}
}
type2: __type(name: "DummyAggregateOfferConnection") {
type2: __type(name: "DummyAggregateOfferCursorConnection") {
description,
fields {
name
Expand Down Expand Up @@ -76,7 +76,7 @@ Feature: GraphQL introspection support
{
"name":"offers",
"type":{
"name":"DummyAggregateOfferConnection",
"name":"DummyAggregateOfferCursorConnection",
"kind":"OBJECT",
"ofType":null
}
Expand Down Expand Up @@ -546,7 +546,7 @@ Feature: GraphQL introspection support
When I send the following GraphQL request:
"""
{
typeNotAvailable: __type(name: "VoDummyInspectionConnection") {
typeNotAvailable: __type(name: "VoDummyInspectionCursorConnection") {
description
}
typeOwner: __type(name: "VoDummyCar") {
Expand All @@ -563,6 +563,6 @@ Feature: GraphQL introspection support
Then the response status code should be 200
And the response should be in JSON
And the header "Content-Type" should be equal to "application/json"
And the JSON node "errors[0].debugMessage" should be equal to 'Type with id "VoDummyInspectionConnection" is not present in the types container'
And the JSON node "errors[0].debugMessage" should be equal to 'Type with id "VoDummyInspectionCursorConnection" is not present in the types container'
And the JSON node "data.typeNotAvailable" should be null
And the JSON node "data.typeOwner.fields[3].type.name" should be equal to "VoDummyInspectionConnection"
And the JSON node "data.typeOwner.fields[3].type.name" should be equal to "VoDummyInspectionCursorConnection"
2 changes: 1 addition & 1 deletion features/graphql/mutation.feature
Original file line number Diff line number Diff line change
Expand Up @@ -709,7 +709,7 @@ Feature: GraphQL mutation support
And the JSON node "data.updateRelatedDummy.relatedDummy.thirdLevel.__typename" should be equal to "updateThirdLevelNestedPayload"
And the JSON node "data.updateRelatedDummy.relatedDummy.thirdLevel.fourthLevel.id" should be equal to "/fourth_levels/1"
And the JSON node "data.updateRelatedDummy.relatedDummy.thirdLevel.fourthLevel.__typename" should be equal to "updateFourthLevelNestedPayload"
And the JSON node "data.updateRelatedDummy.relatedDummy.relatedToDummyFriend.__typename" should be equal to "updateRelatedToDummyFriendNestedPayloadConnection"
And the JSON node "data.updateRelatedDummy.relatedDummy.relatedToDummyFriend.__typename" should be equal to "updateRelatedToDummyFriendNestedPayloadCursorConnection"
And the JSON node "data.updateRelatedDummy.relatedDummy.relatedToDummyFriend.edges[0].node.name" should be equal to "Relation-1"
And the JSON node "data.updateRelatedDummy.relatedDummy.relatedToDummyFriend.edges[1].node.name" should be equal to "Relation-2"

Expand Down
8 changes: 4 additions & 4 deletions features/graphql/schema.feature
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ Feature: GraphQL schema-related features
name: String!
}

###Connection for DummyFriend.###
type DummyFriendConnection {
###Cursor connection for DummyFriend.###
type DummyFriendCursorConnection {
edges: [DummyFriendEdge]
pageInfo: DummyFriendPageInfo!
totalCount: Int!
Expand Down Expand Up @@ -54,8 +54,8 @@ Feature: GraphQL schema-related features
name: String!
}

# Connection for DummyFriend.
type DummyFriendConnection {
# Cursor connection for DummyFriend.
type DummyFriendCursorConnection {
edges: [DummyFriendEdge]
pageInfo: DummyFriendPageInfo!
totalCount: Int!
Expand Down
14 changes: 7 additions & 7 deletions src/GraphQl/Type/TypeBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -224,25 +224,25 @@ public function getNodeInterface(): InterfaceType
public function getResourcePaginatedCollectionType(GraphQLType $resourceType, string $resourceClass, string $operationName): GraphQLType
{
$shortName = $resourceType->name;
$paginationType = $this->pagination->getGraphQlPaginationType($resourceClass, $operationName);

if ($this->typesContainer->has("{$shortName}Connection")) {
return $this->typesContainer->get("{$shortName}Connection");
$connectionTypeKey = sprintf('%s%sConnection', $shortName, ucfirst($paginationType));
if ($this->typesContainer->has($connectionTypeKey)) {
return $this->typesContainer->get($connectionTypeKey);
}

$paginationType = $this->pagination->getGraphQlPaginationType($resourceClass, $operationName);

$fields = 'cursor' === $paginationType ?
$this->getCursorBasedPaginationFields($resourceType) :
$this->getPageBasedPaginationFields($resourceType);

$configuration = [
'name' => "{$shortName}Connection",
'description' => "Connection for $shortName.",
'name' => $connectionTypeKey,
'description' => sprintf("%s connection for $shortName.", ucfirst($paginationType)),
'fields' => $fields,
];

$resourcePaginatedCollectionType = new ObjectType($configuration);
$this->typesContainer->set("{$shortName}Connection", $resourcePaginatedCollectionType);
$this->typesContainer->set($connectionTypeKey, $resourcePaginatedCollectionType);

return $resourcePaginatedCollectionType;
}
Expand Down
16 changes: 8 additions & 8 deletions tests/GraphQl/Type/TypeBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -472,8 +472,8 @@ public function testGetNodeInterface(): void

public function testCursorBasedGetResourcePaginatedCollectionType(): void
{
$this->typesContainerProphecy->has('StringConnection')->shouldBeCalled()->willReturn(false);
$this->typesContainerProphecy->set('StringConnection', Argument::type(ObjectType::class))->shouldBeCalled();
$this->typesContainerProphecy->has('StringCursorConnection')->shouldBeCalled()->willReturn(false);
$this->typesContainerProphecy->set('StringCursorConnection', Argument::type(ObjectType::class))->shouldBeCalled();
$this->typesContainerProphecy->set('StringEdge', Argument::type(ObjectType::class))->shouldBeCalled();
$this->typesContainerProphecy->set('StringPageInfo', Argument::type(ObjectType::class))->shouldBeCalled();
$this->resourceMetadataCollectionFactoryProphecy->create('StringResourceClass')->shouldBeCalled()->willReturn(new ResourceMetadataCollection('StringResourceClass', [
Expand All @@ -484,8 +484,8 @@ public function testCursorBasedGetResourcePaginatedCollectionType(): void

/** @var ObjectType $resourcePaginatedCollectionType */
$resourcePaginatedCollectionType = $this->typeBuilder->getResourcePaginatedCollectionType(GraphQLType::string(), 'StringResourceClass', 'operationName');
$this->assertSame('StringConnection', $resourcePaginatedCollectionType->name);
$this->assertSame('Connection for String.', $resourcePaginatedCollectionType->description);
$this->assertSame('StringCursorConnection', $resourcePaginatedCollectionType->name);
$this->assertSame('Cursor connection for String.', $resourcePaginatedCollectionType->description);

$resourcePaginatedCollectionTypeFields = $resourcePaginatedCollectionType->getFields();
$this->assertArrayHasKey('edges', $resourcePaginatedCollectionTypeFields);
Expand Down Expand Up @@ -531,8 +531,8 @@ public function testCursorBasedGetResourcePaginatedCollectionType(): void

public function testPageBasedGetResourcePaginatedCollectionType(): void
{
$this->typesContainerProphecy->has('StringConnection')->shouldBeCalled()->willReturn(false);
$this->typesContainerProphecy->set('StringConnection', Argument::type(ObjectType::class))->shouldBeCalled();
$this->typesContainerProphecy->has('StringPageConnection')->shouldBeCalled()->willReturn(false);
$this->typesContainerProphecy->set('StringPageConnection', Argument::type(ObjectType::class))->shouldBeCalled();
$this->typesContainerProphecy->set('StringPaginationInfo', Argument::type(ObjectType::class))->shouldBeCalled();

$this->resourceMetadataCollectionFactoryProphecy->create('StringResourceClass')->shouldBeCalled()->willReturn(new ResourceMetadataCollection('StringResourceClass', [
Expand All @@ -543,8 +543,8 @@ public function testPageBasedGetResourcePaginatedCollectionType(): void

/** @var ObjectType $resourcePaginatedCollectionType */
$resourcePaginatedCollectionType = $this->typeBuilder->getResourcePaginatedCollectionType(GraphQLType::string(), 'StringResourceClass', 'operationName');
$this->assertSame('StringConnection', $resourcePaginatedCollectionType->name);
$this->assertSame('Connection for String.', $resourcePaginatedCollectionType->description);
$this->assertSame('StringPageConnection', $resourcePaginatedCollectionType->name);
$this->assertSame('Page connection for String.', $resourcePaginatedCollectionType->description);

$resourcePaginatedCollectionTypeFields = $resourcePaginatedCollectionType->getFields();
$this->assertArrayHasKey('collection', $resourcePaginatedCollectionTypeFields);
Expand Down