diff --git a/features/graphql/mutation.feature b/features/graphql/mutation.feature
index 2ac8de7b7da..0bb5caf44eb 100644
--- a/features/graphql/mutation.feature
+++ b/features/graphql/mutation.feature
@@ -425,7 +425,7 @@ Feature: GraphQL mutation support
And the JSON node "data.createFoo.foo.name" should be equal to "Created without mutation id"
And the JSON node "data.createFoo.foo.bar" should be equal to "works"
- Scenario: Create an item with a subresource
+ Scenario: Create an item with a relation to an existing resource
Given there are 1 dummy objects with relatedDummy
When I send the following GraphQL request:
"""
@@ -666,15 +666,26 @@ Feature: GraphQL mutation support
Scenario: Use serialization groups with relations
Given there is 1 dummy object with relatedDummy and its thirdLevel
And there is a RelatedDummy with 2 friends
+ And there is a dummy object with a fourth level relation
When I send the following GraphQL request:
"""
mutation {
- updateRelatedDummy(input: {id: "/related_dummies/2", symfony: "laravel", embeddedDummy: "{}", thirdLevel: "/third_levels/1"}) {
+ updateRelatedDummy(input: {
+ id: "/related_dummies/2",
+ symfony: "laravel",
+ thirdLevel: {
+ fourthLevel: "/fourth_levels/1"
+ }
+ }) {
relatedDummy {
id
symfony
thirdLevel {
id
+ fourthLevel {
+ id
+ __typename
+ }
__typename
}
relatedToDummyFriend {
@@ -694,8 +705,10 @@ Feature: GraphQL mutation support
And the header "Content-Type" should be equal to "application/json"
And the JSON node "data.updateRelatedDummy.relatedDummy.id" should be equal to "/related_dummies/2"
And the JSON node "data.updateRelatedDummy.relatedDummy.symfony" should be equal to "laravel"
- And the JSON node "data.updateRelatedDummy.relatedDummy.thirdLevel.id" should be equal to "/third_levels/1"
+ And the JSON node "data.updateRelatedDummy.relatedDummy.thirdLevel.id" should be equal to "/third_levels/3"
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.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"
diff --git a/src/Core/Bridge/Symfony/Bundle/Resources/config/graphql.xml b/src/Core/Bridge/Symfony/Bundle/Resources/config/graphql.xml
index e612cbae965..c4494439e01 100644
--- a/src/Core/Bridge/Symfony/Bundle/Resources/config/graphql.xml
+++ b/src/Core/Bridge/Symfony/Bundle/Resources/config/graphql.xml
@@ -130,6 +130,7 @@
+
diff --git a/src/Core/Serializer/AbstractItemNormalizer.php b/src/Core/Serializer/AbstractItemNormalizer.php
index df7ab523192..5d06aecf1b2 100644
--- a/src/Core/Serializer/AbstractItemNormalizer.php
+++ b/src/Core/Serializer/AbstractItemNormalizer.php
@@ -864,6 +864,9 @@ private function createAttributeValue($attribute, $value, $format = null, array
$resourceClass = $this->resourceClassResolver->getResourceClass(null, $className);
$childContext = $this->createChildContext($context, $attribute, $format);
$childContext['resource_class'] = $resourceClass;
+ if ($this->resourceMetadataFactory instanceof ResourceMetadataCollectionFactoryInterface) {
+ $childContext['operation'] = $this->resourceMetadataFactory->create($resourceClass)->getOperation();
+ }
return $this->denormalizeRelation($attribute, $propertyMetadata, $resourceClass, $value, $format, $childContext);
}
diff --git a/src/GraphQl/Type/FieldsBuilder.php b/src/GraphQl/Type/FieldsBuilder.php
index 720fa116d79..f7e392a57bd 100644
--- a/src/GraphQl/Type/FieldsBuilder.php
+++ b/src/GraphQl/Type/FieldsBuilder.php
@@ -94,15 +94,12 @@ public function getNodeQueryFields(): array
/**
* {@inheritdoc}
*/
- public function getItemQueryFields(string $resourceClass, Operation $operation, string $queryName, array $configuration): array
+ public function getItemQueryFields(string $resourceClass, Operation $operation, array $configuration): array
{
- $shortName = $operation->getShortName();
- $fieldName = lcfirst('item_query' === $queryName ? $shortName : $queryName.$shortName);
- $description = $operation->getDescription();
- $deprecationReason = $operation->getDeprecationReason();
+ $fieldName = lcfirst('item_query' === $operation->getName() ? $operation->getShortName() : $operation->getName().$operation->getShortName());
- if ($fieldConfiguration = $this->getResourceFieldConfiguration(null, $description, $deprecationReason, new Type(Type::BUILTIN_TYPE_OBJECT, true, $resourceClass), $resourceClass, false, $queryName)) {
- $args = $this->resolveResourceArgs($configuration['args'] ?? [], $queryName, $shortName);
+ if ($fieldConfiguration = $this->getResourceFieldConfiguration(null, $operation->getDescription(), $operation->getDeprecationReason(), new Type(Type::BUILTIN_TYPE_OBJECT, true, $resourceClass), $resourceClass, false, $operation)) {
+ $args = $this->resolveResourceArgs($configuration['args'] ?? [], $operation);
$configuration['args'] = $args ?: $configuration['args'] ?? ['id' => ['type' => GraphQLType::nonNull(GraphQLType::id())]];
return [$fieldName => array_merge($fieldConfiguration, $configuration)];
@@ -114,15 +111,12 @@ public function getItemQueryFields(string $resourceClass, Operation $operation,
/**
* {@inheritdoc}
*/
- public function getCollectionQueryFields(string $resourceClass, Operation $operation, string $queryName, array $configuration): array
+ public function getCollectionQueryFields(string $resourceClass, Operation $operation, array $configuration): array
{
- $shortName = $operation->getShortName();
- $fieldName = lcfirst('collection_query' === $queryName ? $shortName : $queryName.$shortName);
- $description = $operation->getDescription();
- $deprecationReason = $operation->getDeprecationReason();
+ $fieldName = lcfirst('collection_query' === $operation->getName() ? $operation->getShortName() : $operation->getName().$operation->getShortName());
- if ($fieldConfiguration = $this->getResourceFieldConfiguration(null, $description, $deprecationReason, new Type(Type::BUILTIN_TYPE_OBJECT, false, null, true, null, new Type(Type::BUILTIN_TYPE_OBJECT, false, $resourceClass)), $resourceClass, false, $queryName)) {
- $args = $this->resolveResourceArgs($configuration['args'] ?? [], $queryName, $shortName);
+ if ($fieldConfiguration = $this->getResourceFieldConfiguration(null, $operation->getDescription(), $operation->getDeprecationReason(), new Type(Type::BUILTIN_TYPE_OBJECT, false, null, true, null, new Type(Type::BUILTIN_TYPE_OBJECT, false, $resourceClass)), $resourceClass, false, $operation)) {
+ $args = $this->resolveResourceArgs($configuration['args'] ?? [], $operation);
$configuration['args'] = $args ?: $configuration['args'] ?? $fieldConfiguration['args'];
return [Inflector::pluralize($fieldName) => array_merge($fieldConfiguration, $configuration)];
@@ -134,19 +128,17 @@ public function getCollectionQueryFields(string $resourceClass, Operation $opera
/**
* {@inheritdoc}
*/
- public function getMutationFields(string $resourceClass, Operation $operation, string $mutationName): array
+ public function getMutationFields(string $resourceClass, Operation $operation): array
{
$mutationFields = [];
- $shortName = $operation->getShortName();
$resourceType = new Type(Type::BUILTIN_TYPE_OBJECT, true, $resourceClass);
- $description = $operation->getDescription() ?? ucfirst("{$mutationName}s a $shortName.");
- $deprecationReason = $operation->getDeprecationReason();
+ $description = $operation->getDescription() ?? ucfirst("{$operation->getName()}s a {$operation->getShortName()}.");
- if ($fieldConfiguration = $this->getResourceFieldConfiguration(null, $description, $deprecationReason, $resourceType, $resourceClass, false, $mutationName)) {
- $fieldConfiguration['args'] += ['input' => $this->getResourceFieldConfiguration(null, null, $deprecationReason, $resourceType, $resourceClass, true, $mutationName)];
+ if ($fieldConfiguration = $this->getResourceFieldConfiguration(null, $description, $operation->getDeprecationReason(), $resourceType, $resourceClass, false, $operation)) {
+ $fieldConfiguration['args'] += ['input' => $this->getResourceFieldConfiguration(null, null, $operation->getDeprecationReason(), $resourceType, $resourceClass, true, $operation)];
}
- $mutationFields[$mutationName.$shortName] = $fieldConfiguration ?? [];
+ $mutationFields[$operation->getName().$operation->getShortName()] = $fieldConfiguration ?? [];
return $mutationFields;
}
@@ -154,22 +146,21 @@ public function getMutationFields(string $resourceClass, Operation $operation, s
/**
* {@inheritdoc}
*/
- public function getSubscriptionFields(string $resourceClass, Operation $operation, string $subscriptionName): array
+ public function getSubscriptionFields(string $resourceClass, Operation $operation): array
{
$subscriptionFields = [];
- $shortName = $operation->getShortName();
$resourceType = new Type(Type::BUILTIN_TYPE_OBJECT, true, $resourceClass);
- $description = $operation->getDescription() ?? sprintf('Subscribes to the action event of a %s.', $shortName);
- $deprecationReason = $operation->getDeprecationReason();
+ $description = $operation->getDescription() ?? sprintf('Subscribes to the action event of a %s.', $operation->getShortName());
- if ($fieldConfiguration = $this->getResourceFieldConfiguration(null, $description, $deprecationReason, $resourceType, $resourceClass, false, $subscriptionName)) {
- $fieldConfiguration['args'] += ['input' => $this->getResourceFieldConfiguration(null, null, $deprecationReason, $resourceType, $resourceClass, true, $subscriptionName)];
+ if ($fieldConfiguration = $this->getResourceFieldConfiguration(null, $description, $operation->getDeprecationReason(), $resourceType, $resourceClass, false, $operation)) {
+ $fieldConfiguration['args'] += ['input' => $this->getResourceFieldConfiguration(null, null, $operation->getDeprecationReason(), $resourceType, $resourceClass, true, $operation)];
}
if (!$fieldConfiguration) {
return [];
}
+ $subscriptionName = $operation->getName();
// TODO: 3.0 change this
if ('update_subscription' === $subscriptionName) {
$subscriptionName = 'update';
@@ -183,10 +174,11 @@ public function getSubscriptionFields(string $resourceClass, Operation $operatio
/**
* {@inheritdoc}
*/
- public function getResourceObjectTypeFields(?string $resourceClass, Operation $operation, bool $input, string $operationName, int $depth = 0, ?array $ioMetadata = null): array
+ public function getResourceObjectTypeFields(?string $resourceClass, Operation $operation, bool $input, int $depth = 0, ?array $ioMetadata = null): array
{
$fields = [];
$idField = ['type' => GraphQLType::nonNull(GraphQLType::id())];
+ $optionalIdField = ['type' => GraphQLType::id()];
$clientMutationId = GraphQLType::string();
$clientSubscriptionId = GraphQLType::string();
@@ -205,7 +197,7 @@ public function getResourceObjectTypeFields(?string $resourceClass, Operation $o
];
}
- if ('delete' === $operationName) {
+ if ('delete' === $operation->getName()) {
$fields = [
'id' => $idField,
];
@@ -217,9 +209,12 @@ public function getResourceObjectTypeFields(?string $resourceClass, Operation $o
return $fields;
}
- if (!$input || 'create' !== $operationName) {
+ if (!$input || 'create' !== $operation->getName()) {
$fields['id'] = $idField;
}
+ if ($input && $depth >= 1) {
+ $fields['id'] = $optionalIdField;
+ }
++$depth; // increment the depth for the call to getResourceFieldConfiguration.
@@ -239,7 +234,7 @@ public function getResourceObjectTypeFields(?string $resourceClass, Operation $o
continue;
}
- if ($fieldConfiguration = $this->getResourceFieldConfiguration($property, $propertyMetadata->getDescription(), $propertyMetadata->getDeprecationReason(), $propertyType, $resourceClass, $input, $operationName, $depth, null !== $propertyMetadata->getSecurity())) {
+ if ($fieldConfiguration = $this->getResourceFieldConfiguration($property, $propertyMetadata->getDescription(), $propertyMetadata->getDeprecationReason(), $propertyType, $resourceClass, $input, $operation, $depth, null !== $propertyMetadata->getSecurity())) {
$fields['id' === $property ? '_id' : $this->normalizePropertyName($property, $resourceClass)] = $fieldConfiguration;
}
}
@@ -255,11 +250,11 @@ public function getResourceObjectTypeFields(?string $resourceClass, Operation $o
/**
* {@inheritdoc}
*/
- public function resolveResourceArgs(array $args, string $operationName, string $shortName): array
+ public function resolveResourceArgs(array $args, Operation $operation): array
{
foreach ($args as $id => $arg) {
if (!isset($arg['type'])) {
- throw new \InvalidArgumentException(sprintf('The argument "%s" of the custom operation "%s" in %s needs a "type" option.', $id, $operationName, $shortName));
+ throw new \InvalidArgumentException(sprintf('The argument "%s" of the custom operation "%s" in %s needs a "type" option.', $id, $operation->getName(), $operation->getShortName()));
}
$args[$id]['type'] = $this->typeConverter->resolveType($arg['type']);
@@ -273,7 +268,7 @@ public function resolveResourceArgs(array $args, string $operationName, string $
*
* @see http://webonyx.github.io/graphql-php/type-system/object-types/
*/
- private function getResourceFieldConfiguration(?string $property, ?string $fieldDescription, ?string $deprecationReason, Type $type, string $rootResource, bool $input, string $operationName, int $depth = 0, bool $forceNullable = false): ?array
+ private function getResourceFieldConfiguration(?string $property, ?string $fieldDescription, ?string $deprecationReason, Type $type, string $rootResource, bool $input, Operation $rootOperation, int $depth = 0, bool $forceNullable = false): ?array
{
try {
if (
@@ -285,7 +280,7 @@ private function getResourceFieldConfiguration(?string $property, ?string $field
$resourceClass = $type->getClassName();
}
- if (null === $graphqlType = $this->convertType($type, $input, $operationName, $resourceClass ?? '', $rootResource, $property, $depth, $forceNullable)) {
+ if (null === $graphqlType = $this->convertType($type, $input, $rootOperation, $resourceClass ?? '', $rootResource, $property, $depth, $forceNullable)) {
return null;
}
@@ -295,24 +290,24 @@ private function getResourceFieldConfiguration(?string $property, ?string $field
$resourceClass = '';
}
+ // Check mercure attribute if it's a subscription at the root level.
+ if ($rootOperation instanceof Subscription && null === $property && !$rootOperation->getMercure()) {
+ return null;
+ }
+
$resourceMetadataCollection = $operation = null;
if (!empty($resourceClass)) {
$resourceMetadataCollection = $this->resourceMetadataCollectionFactory->create($resourceClass);
try {
- $operation = $resourceMetadataCollection->getGraphQlOperation($operationName);
+ $operation = $resourceMetadataCollection->getGraphQlOperation($rootOperation->getName());
} catch (OperationNotFoundException $e) {
}
}
- // Check mercure attribute if it's a subscription at the root level.
- if ($operation instanceof Subscription && null === $property && !$operation->getMercure()) {
- return null;
- }
-
$args = [];
- if (!$input && !$operation instanceof Mutation && !$operation instanceof Subscription && !$isStandardGraphqlType && $this->typeBuilder->isCollection($type)) {
- if ($this->pagination->isGraphQlEnabled($resourceClass, $operationName)) {
- $args = $this->getGraphQlPaginationArgs($resourceClass, $operationName);
+ if (!$input && !$rootOperation instanceof Mutation && !$rootOperation instanceof Subscription && !$isStandardGraphqlType && $this->typeBuilder->isCollection($type)) {
+ if ($this->pagination->isGraphQlEnabled($resourceClass, $rootOperation->getName())) {
+ $args = $this->getGraphQlPaginationArgs($resourceClass, $rootOperation->getName());
}
// Look for the collection operation if it exists
@@ -323,17 +318,17 @@ private function getResourceFieldConfiguration(?string $property, ?string $field
}
}
- $args = $this->getFilterArgs($args, $resourceClass, $operation, $rootResource, $property, $operationName, $depth);
+ $args = $this->getFilterArgs($args, $resourceClass, $operation, $rootResource, $rootOperation, $property, $depth);
}
if ($isStandardGraphqlType || $input) {
$resolve = null;
- } elseif (($operation instanceof Mutation || $operation instanceof Subscription) && $depth <= 0) {
- $resolve = $operation instanceof Mutation ? ($this->itemMutationResolverFactory)($resourceClass, $rootResource, $operationName) : ($this->itemSubscriptionResolverFactory)($resourceClass, $rootResource, $operationName);
+ } elseif (($rootOperation instanceof Mutation || $rootOperation instanceof Subscription) && $depth <= 0) {
+ $resolve = $rootOperation instanceof Mutation ? ($this->itemMutationResolverFactory)($resourceClass, $rootResource, $rootOperation->getName()) : ($this->itemSubscriptionResolverFactory)($resourceClass, $rootResource, $rootOperation->getName());
} elseif ($this->typeBuilder->isCollection($type)) {
- $resolve = ($this->collectionResolverFactory)($resourceClass, $rootResource, $operationName);
+ $resolve = ($this->collectionResolverFactory)($resourceClass, $rootResource, $rootOperation->getName());
} else {
- $resolve = ($this->itemResolverFactory)($resourceClass, $rootResource, $operationName);
+ $resolve = ($this->itemResolverFactory)($resourceClass, $rootResource, $rootOperation->getName());
}
return [
@@ -397,7 +392,7 @@ private function getGraphQlPaginationArgs(string $resourceClass, string $queryNa
/**
* @param Operation|ApiOperation|null $operation
*/
- private function getFilterArgs(array $args, ?string $resourceClass, $operation, string $rootResource, ?string $property, string $operationName, int $depth): array
+ private function getFilterArgs(array $args, ?string $resourceClass, $operation, string $rootResource, Operation $rootOperation, ?string $property, int $depth): array
{
if (null === $operation || null === $resourceClass) {
return $args;
@@ -411,7 +406,7 @@ private function getFilterArgs(array $args, ?string $resourceClass, $operation,
foreach ($this->filterLocator->get($filterId)->getDescription($resourceClass) as $key => $value) {
$nullable = isset($value['required']) ? !$value['required'] : true;
$filterType = \in_array($value['type'], Type::$builtinTypes, true) ? new Type($value['type'], $nullable) : new Type('object', $nullable, $value['type']);
- $graphqlFilterType = $this->convertType($filterType, false, $operationName, $resourceClass, $rootResource, $property, $depth);
+ $graphqlFilterType = $this->convertType($filterType, false, $rootOperation, $resourceClass, $rootResource, $property, $depth);
if ('[]' === substr($key, -2)) {
$graphqlFilterType = GraphQLType::listOf($graphqlFilterType);
@@ -502,9 +497,9 @@ private function convertFilterArgsToTypes(array $args): array
*
* @throws InvalidTypeException
*/
- private function convertType(Type $type, bool $input, string $operationName, string $resourceClass, string $rootResource, ?string $property, int $depth, bool $forceNullable = false)
+ private function convertType(Type $type, bool $input, Operation $rootOperation, string $resourceClass, string $rootResource, ?string $property, int $depth, bool $forceNullable = false)
{
- $graphqlType = $this->typeConverter->convertType($type, $input, $operationName, $resourceClass, $rootResource, $property, $depth);
+ $graphqlType = $this->typeConverter->convertType($type, $input, $rootOperation, $resourceClass, $rootResource, $property, $depth);
if (null === $graphqlType) {
throw new InvalidTypeException(sprintf('The type "%s" is not supported.', $type->getBuiltinType()));
@@ -519,20 +514,10 @@ private function convertType(Type $type, bool $input, string $operationName, str
}
if ($this->typeBuilder->isCollection($type)) {
- return $this->pagination->isGraphQlEnabled($resourceClass, $operationName) && !$input ? $this->typeBuilder->getResourcePaginatedCollectionType($graphqlType, $resourceClass, $operationName) : GraphQLType::listOf($graphqlType);
- }
-
- $operation = null;
- $resourceClass = '' === $resourceClass ? $rootResource : $resourceClass;
- if ($resourceClass) {
- $resourceMetadataCollection = $this->resourceMetadataCollectionFactory->create($resourceClass);
- try {
- $operation = $resourceMetadataCollection->getGraphQlOperation($operationName);
- } catch (OperationNotFoundException $e) {
- }
+ return $this->pagination->isGraphQlEnabled($resourceClass, $rootOperation->getName()) && !$input ? $this->typeBuilder->getResourcePaginatedCollectionType($graphqlType, $resourceClass, $rootOperation->getName()) : GraphQLType::listOf($graphqlType);
}
- return $forceNullable || !$graphqlType instanceof NullableType || $type->isNullable() || ($operation instanceof Mutation && 'update' === $operationName)
+ return $forceNullable || !$graphqlType instanceof NullableType || $type->isNullable() || ($rootOperation instanceof Mutation && 'update' === $rootOperation->getName())
? $graphqlType
: GraphQLType::nonNull($graphqlType);
}
diff --git a/src/GraphQl/Type/FieldsBuilderInterface.php b/src/GraphQl/Type/FieldsBuilderInterface.php
index 988e5f4e731..1361b388fe3 100644
--- a/src/GraphQl/Type/FieldsBuilderInterface.php
+++ b/src/GraphQl/Type/FieldsBuilderInterface.php
@@ -32,30 +32,30 @@ public function getNodeQueryFields(): array;
/**
* Gets the item query fields of the schema.
*/
- public function getItemQueryFields(string $resourceClass, Operation $operation, string $queryName, array $configuration): array;
+ public function getItemQueryFields(string $resourceClass, Operation $operation, array $configuration): array;
/**
* Gets the collection query fields of the schema.
*/
- public function getCollectionQueryFields(string $resourceClass, Operation $operation, string $queryName, array $configuration): array;
+ public function getCollectionQueryFields(string $resourceClass, Operation $operation, array $configuration): array;
/**
* Gets the mutation fields of the schema.
*/
- public function getMutationFields(string $resourceClass, Operation $operation, string $mutationName): array;
+ public function getMutationFields(string $resourceClass, Operation $operation): array;
/**
* Gets the subscription fields of the schema.
*/
- public function getSubscriptionFields(string $resourceClass, Operation $operation, string $subscriptionName): array;
+ public function getSubscriptionFields(string $resourceClass, Operation $operation): array;
/**
* Gets the fields of the type of the given resource.
*/
- public function getResourceObjectTypeFields(?string $resourceClass, Operation $operation, bool $input, string $operationName, int $depth = 0, ?array $ioMetadata = null): array;
+ public function getResourceObjectTypeFields(?string $resourceClass, Operation $operation, bool $input, int $depth = 0, ?array $ioMetadata = null): array;
/**
* Resolve the args of a resource by resolving its types.
*/
- public function resolveResourceArgs(array $args, string $operationName, string $shortName): array;
+ public function resolveResourceArgs(array $args, Operation $operation): array;
}
diff --git a/src/GraphQl/Type/SchemaBuilder.php b/src/GraphQl/Type/SchemaBuilder.php
index 607e4e29e32..d7067f676ec 100644
--- a/src/GraphQl/Type/SchemaBuilder.php
+++ b/src/GraphQl/Type/SchemaBuilder.php
@@ -66,35 +66,35 @@ public function getSchema(): Schema
//TODO: 3.0 remove these
if ('item_query' === $operationName) {
- $queryFields += $this->fieldsBuilder->getItemQueryFields($resourceClass, $operation, $operationName, $configuration);
+ $queryFields += $this->fieldsBuilder->getItemQueryFields($resourceClass, $operation, $configuration);
continue;
}
if ('collection_query' === $operationName) {
- $queryFields += $this->fieldsBuilder->getCollectionQueryFields($resourceClass, $operation, $operationName, $configuration);
+ $queryFields += $this->fieldsBuilder->getCollectionQueryFields($resourceClass, $operation, $configuration);
continue;
}
if ($operation instanceof Query && !$operation->isCollection()) {
- $queryFields += $this->fieldsBuilder->getItemQueryFields($resourceClass, $operation, $operationName, $configuration);
+ $queryFields += $this->fieldsBuilder->getItemQueryFields($resourceClass, $operation, $configuration);
continue;
}
if ($operation instanceof Query && $operation->isCollection()) {
- $queryFields += $this->fieldsBuilder->getCollectionQueryFields($resourceClass, $operation, $operationName, $configuration);
+ $queryFields += $this->fieldsBuilder->getCollectionQueryFields($resourceClass, $operation, $configuration);
continue;
}
if ($operation instanceof Subscription && $operation->getMercure()) {
- $subscriptionFields += $this->fieldsBuilder->getSubscriptionFields($resourceClass, $operation, $operationName);
+ $subscriptionFields += $this->fieldsBuilder->getSubscriptionFields($resourceClass, $operation);
continue;
}
- $mutationFields += $this->fieldsBuilder->getMutationFields($resourceClass, $operation, $operationName);
+ $mutationFields += $this->fieldsBuilder->getMutationFields($resourceClass, $operation);
}
}
}
diff --git a/src/GraphQl/Type/TypeBuilder.php b/src/GraphQl/Type/TypeBuilder.php
index a47c9dff003..68bc15b736c 100644
--- a/src/GraphQl/Type/TypeBuilder.php
+++ b/src/GraphQl/Type/TypeBuilder.php
@@ -54,18 +54,10 @@ public function __construct(TypesContainerInterface $typesContainer, callable $d
/**
* {@inheritdoc}
*/
- public function getResourceObjectType(?string $resourceClass, ResourceMetadataCollection $resourceMetadataCollection, string $operationName, bool $input, bool $wrapped = false, int $depth = 0): GraphQLType
+ public function getResourceObjectType(?string $resourceClass, ResourceMetadataCollection $resourceMetadataCollection, Operation $operation, bool $input, bool $wrapped = false, int $depth = 0): GraphQLType
{
- try {
- $operation = $resourceMetadataCollection->getGraphQlOperation($operationName);
- } catch (OperationNotFoundException $e) {
- $operation = (new Query())
- ->withResource($resourceMetadataCollection[0])
- ->withName($operationName)
- ->withCollection('collection_query' === $operationName);
- }
-
$shortName = $operation->getShortName();
+ $operationName = $operation->getName();
if ($operation instanceof Mutation) {
$shortName = $operationName.ucfirst($shortName);
@@ -76,6 +68,9 @@ public function getResourceObjectType(?string $resourceClass, ResourceMetadataCo
}
if ($input) {
+ if ($depth > 0) {
+ $shortName .= 'Nested';
+ }
$shortName .= 'Input';
} elseif ($operation instanceof Mutation || $operation instanceof Subscription) {
if ($depth > 0) {
@@ -141,8 +136,17 @@ public function getResourceObjectType(?string $resourceClass, ResourceMetadataCo
$wrappedOperationName = $operation instanceof Query ? $operationName : 'item_query';
}
+ try {
+ $wrappedOperation = $resourceMetadataCollection->getGraphQlOperation($wrappedOperationName);
+ } catch (OperationNotFoundException $e) {
+ $wrappedOperation = (new Query())
+ ->withResource($resourceMetadataCollection[0])
+ ->withName($wrappedOperationName)
+ ->withCollection('collection_query' === $wrappedOperationName);
+ }
+
$fields = [
- lcfirst($operation->getShortName()) => $this->getResourceObjectType($resourceClass, $resourceMetadataCollection, $wrappedOperationName, $input, true, $depth),
+ lcfirst($wrappedOperation->getShortName()) => $this->getResourceObjectType($resourceClass, $resourceMetadataCollection, $wrappedOperation, $input, true, $depth),
];
if ($operation instanceof Subscription) {
@@ -158,10 +162,10 @@ public function getResourceObjectType(?string $resourceClass, ResourceMetadataCo
}
$fieldsBuilder = $this->fieldsBuilderLocator->get('api_platform.graphql.fields_builder');
- $fields = $fieldsBuilder->getResourceObjectTypeFields($resourceClass, $operation, $input, $operationName, $depth, $ioMetadata);
+ $fields = $fieldsBuilder->getResourceObjectTypeFields($resourceClass, $operation, $input, $depth, $ioMetadata);
if ($input && $operation instanceof Mutation && null !== $mutationArgs = $operation->getArgs()) {
- return $fieldsBuilder->resolveResourceArgs($mutationArgs, $operationName, $operation->getShortName()) + ['clientMutationId' => $fields['clientMutationId']];
+ return $fieldsBuilder->resolveResourceArgs($mutationArgs, $operation) + ['clientMutationId' => $fields['clientMutationId']];
}
return $fields;
diff --git a/src/GraphQl/Type/TypeBuilderInterface.php b/src/GraphQl/Type/TypeBuilderInterface.php
index 21e7a285688..6ee17ec1861 100644
--- a/src/GraphQl/Type/TypeBuilderInterface.php
+++ b/src/GraphQl/Type/TypeBuilderInterface.php
@@ -13,6 +13,7 @@
namespace ApiPlatform\GraphQl\Type;
+use ApiPlatform\Metadata\GraphQl\Operation;
use ApiPlatform\Metadata\Resource\ResourceMetadataCollection;
use GraphQL\Type\Definition\InterfaceType;
use GraphQL\Type\Definition\NonNull;
@@ -34,7 +35,7 @@ interface TypeBuilderInterface
*
* @return ObjectType|NonNull the object type, possibly wrapped by NonNull
*/
- public function getResourceObjectType(?string $resourceClass, ResourceMetadataCollection $resourceMetadataCollection, string $operationName, bool $input, bool $wrapped = false, int $depth = 0): GraphQLType;
+ public function getResourceObjectType(?string $resourceClass, ResourceMetadataCollection $resourceMetadataCollection, Operation $operation, bool $input, bool $wrapped = false, int $depth = 0): GraphQLType;
/**
* Get the interface type of a node.
diff --git a/src/GraphQl/Type/TypeConverter.php b/src/GraphQl/Type/TypeConverter.php
index 0e68c1c1903..66d3d069ea1 100644
--- a/src/GraphQl/Type/TypeConverter.php
+++ b/src/GraphQl/Type/TypeConverter.php
@@ -14,7 +14,11 @@
namespace ApiPlatform\GraphQl\Type;
use ApiPlatform\Exception\InvalidArgumentException;
+use ApiPlatform\Exception\OperationNotFoundException;
use ApiPlatform\Exception\ResourceClassNotFoundException;
+use ApiPlatform\Metadata\GraphQl\Operation;
+use ApiPlatform\Metadata\GraphQl\Query;
+use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
use GraphQL\Error\SyntaxError;
use GraphQL\Language\AST\ListTypeNode;
@@ -38,18 +42,24 @@ final class TypeConverter implements TypeConverterInterface
private $typeBuilder;
private $typesContainer;
private $resourceMetadataCollectionFactory;
+ private $propertyMetadataFactory;
- public function __construct(TypeBuilderInterface $typeBuilder, TypesContainerInterface $typesContainer, ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory)
+ public function __construct(TypeBuilderInterface $typeBuilder, TypesContainerInterface $typesContainer, ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory = null)
{
$this->typeBuilder = $typeBuilder;
$this->typesContainer = $typesContainer;
$this->resourceMetadataCollectionFactory = $resourceMetadataCollectionFactory;
+ $this->propertyMetadataFactory = $propertyMetadataFactory;
+
+ if (null === $this->propertyMetadataFactory) {
+ @trigger_error(sprintf('Not injecting %s in the TypeConverter is deprecated since 2.7 and will not be supported in 3.0.', PropertyMetadataFactoryInterface::class), \E_USER_DEPRECATED);
+ }
}
/**
* {@inheritdoc}
*/
- public function convertType(Type $type, bool $input, string $operationName, string $resourceClass, string $rootResource, ?string $property, int $depth)
+ public function convertType(Type $type, bool $input, Operation $rootOperation, string $resourceClass, string $rootResource, ?string $property, int $depth)
{
switch ($type->getBuiltinType()) {
case Type::BUILTIN_TYPE_BOOL:
@@ -62,21 +72,17 @@ public function convertType(Type $type, bool $input, string $operationName, stri
return GraphQLType::string();
case Type::BUILTIN_TYPE_ARRAY:
case Type::BUILTIN_TYPE_ITERABLE:
- if ($resourceType = $this->getResourceType($type, $input, $operationName, $depth)) {
+ if ($resourceType = $this->getResourceType($type, $input, $rootOperation, $rootResource, $property, $depth)) {
return $resourceType;
}
return 'Iterable';
case Type::BUILTIN_TYPE_OBJECT:
- if ($input && $depth > 0) {
- return GraphQLType::string();
- }
-
if (is_a($type->getClassName(), \DateTimeInterface::class, true)) {
return GraphQLType::string();
}
- return $this->getResourceType($type, $input, $operationName, $depth);
+ return $this->getResourceType($type, $input, $rootOperation, $rootResource, $property, $depth);
default:
return null;
}
@@ -100,7 +106,7 @@ public function resolveType(string $type): ?GraphQLType
throw new InvalidArgumentException(sprintf('The type "%s" was not resolved.', $type));
}
- private function getResourceType(Type $type, bool $input, string $operationName, int $depth): ?GraphQLType
+ private function getResourceType(Type $type, bool $input, Operation $rootOperation, string $rootResource, ?string $property, int $depth): ?GraphQLType
{
if (
$this->typeBuilder->isCollection($type) &&
@@ -122,7 +128,6 @@ private function getResourceType(Type $type, bool $input, string $operationName,
}
$hasGraphQl = false;
- $operation = null;
foreach ($resourceMetadataCollection as $resourceMetadata) {
if (null !== $resourceMetadata->getGraphQlOperations()) {
$hasGraphQl = true;
@@ -138,7 +143,29 @@ private function getResourceType(Type $type, bool $input, string $operationName,
return null;
}
- return $this->typeBuilder->getResourceObjectType($resourceClass, $resourceMetadataCollection, $operationName, $input, false, $depth);
+ $propertyMetadata = null;
+ if ($property && $this->propertyMetadataFactory) {
+ $context = [
+ 'normalization_groups' => $rootOperation->getNormalizationContext()['groups'] ?? null,
+ 'denormalization_groups' => $rootOperation->getDenormalizationContext()['groups'] ?? null,
+ ];
+ $propertyMetadata = $this->propertyMetadataFactory->create($rootResource, $property, $context);
+ }
+
+ if ($input && $depth > 0 && (!$propertyMetadata || !$propertyMetadata->isWritableLink())) {
+ return GraphQLType::string();
+ }
+
+ try {
+ $operation = $resourceMetadataCollection->getGraphQlOperation($rootOperation->getName());
+ } catch (OperationNotFoundException $e) {
+ $operation = (new Query())
+ ->withResource($resourceMetadataCollection[0])
+ ->withName($rootOperation->getName())
+ ->withCollection('collection_query' === $rootOperation->getName());
+ }
+
+ return $this->typeBuilder->getResourceObjectType($resourceClass, $resourceMetadataCollection, $operation, $input, false, $depth);
}
private function resolveAstTypeNode(TypeNode $astTypeNode, string $fromType): ?GraphQLType
diff --git a/src/GraphQl/Type/TypeConverterInterface.php b/src/GraphQl/Type/TypeConverterInterface.php
index 5af5f286a42..3206a3163dc 100644
--- a/src/GraphQl/Type/TypeConverterInterface.php
+++ b/src/GraphQl/Type/TypeConverterInterface.php
@@ -13,6 +13,7 @@
namespace ApiPlatform\GraphQl\Type;
+use ApiPlatform\Metadata\GraphQl\Operation;
use GraphQL\Type\Definition\Type as GraphQLType;
use Symfony\Component\PropertyInfo\Type;
@@ -31,7 +32,7 @@ interface TypeConverterInterface
*
* @return string|GraphQLType|null
*/
- public function convertType(Type $type, bool $input, string $operationName, string $resourceClass, string $rootResource, ?string $property, int $depth);
+ public function convertType(Type $type, bool $input, Operation $rootOperation, string $resourceClass, string $rootResource, ?string $property, int $depth);
/**
* Resolves a type written with the GraphQL type system to its object representation.
diff --git a/tests/Fixtures/TestBundle/Document/RelatedDummy.php b/tests/Fixtures/TestBundle/Document/RelatedDummy.php
index eddac4c06b8..4c25449c3f6 100644
--- a/tests/Fixtures/TestBundle/Document/RelatedDummy.php
+++ b/tests/Fixtures/TestBundle/Document/RelatedDummy.php
@@ -27,7 +27,7 @@
* @author Kévin Dunglas
* @author Alexandre Delplace
*
- * @ApiResource(graphql={"update"={"normalization_context"={"groups"={"chicago", "fakemanytomany"}}}}, iri="https://schema.org/Product", attributes={"normalization_context"={"groups"={"friends"}}, "filters"={"related_dummy.mongodb.friends"}})
+ * @ApiResource(graphql={"update"={"normalization_context"={"groups"={"chicago", "fakemanytomany"}}, "denormalization_context"={"groups"={"friends"}}}}, iri="https://schema.org/Product", attributes={"normalization_context"={"groups"={"friends"}}, "filters"={"related_dummy.mongodb.friends"}})
* @ODM\Document
*/
class RelatedDummy extends ParentDummy
diff --git a/tests/Fixtures/TestBundle/Entity/RelatedDummy.php b/tests/Fixtures/TestBundle/Entity/RelatedDummy.php
index 8328ab9f52f..932c4fd5ee2 100644
--- a/tests/Fixtures/TestBundle/Entity/RelatedDummy.php
+++ b/tests/Fixtures/TestBundle/Entity/RelatedDummy.php
@@ -26,7 +26,7 @@
*
* @author Kévin Dunglas
*
- * @ApiResource(graphql={"update"={"normalization_context"={"groups"={"chicago", "fakemanytomany"}}}}, iri="https://schema.org/Product", attributes={"normalization_context"={"groups"={"friends"}}, "filters"={"related_dummy.friends", "related_dummy.complex_sub_query"}})
+ * @ApiResource(graphql={"update"={"normalization_context"={"groups"={"chicago", "fakemanytomany"}}, "denormalization_context"={"groups"={"friends"}}}}, iri="https://schema.org/Product", attributes={"normalization_context"={"groups"={"friends"}}, "filters"={"related_dummy.friends", "related_dummy.complex_sub_query"}})
* @ORM\Entity
*/
class RelatedDummy extends ParentDummy
diff --git a/tests/Fixtures/TestBundle/GraphQl/Type/TypeConverter.php b/tests/Fixtures/TestBundle/GraphQl/Type/TypeConverter.php
index 0b650b07f7f..58d473a24c4 100644
--- a/tests/Fixtures/TestBundle/GraphQl/Type/TypeConverter.php
+++ b/tests/Fixtures/TestBundle/GraphQl/Type/TypeConverter.php
@@ -14,6 +14,7 @@
namespace ApiPlatform\Tests\Fixtures\TestBundle\GraphQl\Type;
use ApiPlatform\GraphQl\Type\TypeConverterInterface;
+use ApiPlatform\Metadata\GraphQl\Operation;
use ApiPlatform\Tests\Fixtures\TestBundle\Document\Dummy as DummyDocument;
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Dummy;
use GraphQL\Type\Definition\Type as GraphQLType;
@@ -36,7 +37,7 @@ public function __construct(TypeConverterInterface $defaultTypeConverter)
/**
* {@inheritdoc}
*/
- public function convertType(Type $type, bool $input, string $operationName, string $resourceClass, string $rootResource, ?string $property, int $depth)
+ public function convertType(Type $type, bool $input, Operation $rootOperation, string $resourceClass, string $rootResource, ?string $property, int $depth)
{
if ('dummyDate' === $property
&& \in_array($rootResource, [Dummy::class, DummyDocument::class], true)
@@ -46,7 +47,7 @@ public function convertType(Type $type, bool $input, string $operationName, stri
return 'DateTime';
}
- return $this->defaultTypeConverter->convertType($type, $input, $operationName, $resourceClass, $rootResource, $property, $depth);
+ return $this->defaultTypeConverter->convertType($type, $input, $rootOperation, $resourceClass, $rootResource, $property, $depth);
}
/**
diff --git a/tests/GraphQl/Resolver/Factory/CollectionResolverFactoryTest.php b/tests/GraphQl/Resolver/Factory/CollectionResolverFactoryTest.php
index 2d6568c6fa1..a40e2e222bf 100644
--- a/tests/GraphQl/Resolver/Factory/CollectionResolverFactoryTest.php
+++ b/tests/GraphQl/Resolver/Factory/CollectionResolverFactoryTest.php
@@ -20,7 +20,7 @@
use ApiPlatform\GraphQl\Resolver\Stage\SecurityStageInterface;
use ApiPlatform\GraphQl\Resolver\Stage\SerializeStageInterface;
use ApiPlatform\Metadata\ApiResource;
-use ApiPlatform\Metadata\GraphQl\Query;
+use ApiPlatform\Metadata\GraphQl\QueryCollection;
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
use ApiPlatform\Metadata\Resource\ResourceMetadataCollection;
use GraphQL\Type\Definition\ResolveInfo;
@@ -92,7 +92,7 @@ public function testResolve(): void
$readStageCollection = [new \stdClass()];
$this->readStageProphecy->__invoke($resourceClass, $rootClass, $operationName, $resolverContext)->shouldBeCalled()->willReturn($readStageCollection);
- $this->resourceMetadataCollectionFactoryProphecy->create($resourceClass)->willReturn(new ResourceMetadataCollection($resourceClass, [(new ApiResource())->withGraphQlOperations([$operationName => (new Query())->withCollection(true)])]));
+ $this->resourceMetadataCollectionFactoryProphecy->create($resourceClass)->willReturn(new ResourceMetadataCollection($resourceClass, [(new ApiResource())->withGraphQlOperations([$operationName => new QueryCollection()])]));
$this->securityStageProphecy->__invoke($resourceClass, $operationName, $resolverContext + [
'extra_variables' => [
@@ -162,7 +162,7 @@ public function testResolveNullSource(): void
$readStageCollection = [new \stdClass()];
$this->readStageProphecy->__invoke($resourceClass, $rootClass, $operationName, $resolverContext)->shouldBeCalled()->willReturn($readStageCollection);
- $this->resourceMetadataCollectionFactoryProphecy->create($resourceClass)->willReturn(new ResourceMetadataCollection($resourceClass, [(new ApiResource())->withGraphQlOperations([$operationName => (new Query())->withCollection(true)])]));
+ $this->resourceMetadataCollectionFactoryProphecy->create($resourceClass)->willReturn(new ResourceMetadataCollection($resourceClass, [(new ApiResource())->withGraphQlOperations([$operationName => new QueryCollection()])]));
$this->securityStageProphecy->__invoke($resourceClass, $operationName, $resolverContext + [
'extra_variables' => [
@@ -238,7 +238,7 @@ public function testResolveCustom(): void
$readStageCollection = [new \stdClass()];
$this->readStageProphecy->__invoke($resourceClass, $rootClass, $operationName, $resolverContext)->shouldBeCalled()->willReturn($readStageCollection);
- $this->resourceMetadataCollectionFactoryProphecy->create($resourceClass)->willReturn(new ResourceMetadataCollection($resourceClass, [(new ApiResource())->withGraphQlOperations([$operationName => (new Query())->withCollection(true)->withResolver('query_resolver_id')])]));
+ $this->resourceMetadataCollectionFactoryProphecy->create($resourceClass)->willReturn(new ResourceMetadataCollection($resourceClass, [(new ApiResource())->withGraphQlOperations([$operationName => (new QueryCollection())->withResolver('query_resolver_id')])]));
$customCollection = [new \stdClass()];
$customCollection[0]->field = 'foo';
diff --git a/tests/GraphQl/Resolver/Stage/SerializeStageTest.php b/tests/GraphQl/Resolver/Stage/SerializeStageTest.php
index 49d7e6e2a90..75844fd421d 100644
--- a/tests/GraphQl/Resolver/Stage/SerializeStageTest.php
+++ b/tests/GraphQl/Resolver/Stage/SerializeStageTest.php
@@ -23,6 +23,7 @@
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\GraphQl\Mutation;
use ApiPlatform\Metadata\GraphQl\Query;
+use ApiPlatform\Metadata\GraphQl\QueryCollection;
use ApiPlatform\Metadata\GraphQl\Subscription;
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
use ApiPlatform\Metadata\Resource\ResourceMetadataCollection;
@@ -134,7 +135,7 @@ public function testApplyCollectionWithPagination(iterable $collection, array $a
'args' => $args,
'info' => $this->prophesize(ResolveInfo::class)->reveal(),
];
- $resourceMetadata = new ResourceMetadataCollection($resourceClass, [(new ApiResource())->withGraphQlOperations([$operationName => (new Query())->withShortName('shortName')->withCollection(true)])]);
+ $resourceMetadata = new ResourceMetadataCollection($resourceClass, [(new ApiResource())->withGraphQlOperations([$operationName => (new QueryCollection())->withShortName('shortName')])]);
$this->resourceMetadataCollectionFactoryProphecy->create($resourceClass)->willReturn($resourceMetadata);
$normalizationContext = ['normalization' => true];
diff --git a/tests/GraphQl/Type/FieldsBuilderTest.php b/tests/GraphQl/Type/FieldsBuilderTest.php
index 15694c34d46..8b637c84a32 100644
--- a/tests/GraphQl/Type/FieldsBuilderTest.php
+++ b/tests/GraphQl/Type/FieldsBuilderTest.php
@@ -26,6 +26,7 @@
use ApiPlatform\Metadata\GraphQl\Mutation;
use ApiPlatform\Metadata\GraphQl\Operation;
use ApiPlatform\Metadata\GraphQl\Query;
+use ApiPlatform\Metadata\GraphQl\QueryCollection;
use ApiPlatform\Metadata\GraphQl\Subscription;
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
use ApiPlatform\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
@@ -140,15 +141,17 @@ public function testGetNodeQueryFields(): void
/**
* @dataProvider itemQueryFieldsProvider
*/
- public function testGetItemQueryFields(string $resourceClass, Operation $operation, string $queryName, array $configuration, ?GraphQLType $graphqlType, ?callable $resolver, array $expectedQueryFields): void
+ public function testGetItemQueryFields(string $resourceClass, Operation $operation, array $configuration, ?GraphQLType $graphqlType, ?callable $resolver, array $expectedQueryFields): void
{
- $this->typeConverterProphecy->convertType(Argument::type(Type::class), false, $queryName, $resourceClass, $resourceClass, null, 0)->willReturn($graphqlType);
+ $this->typeConverterProphecy->convertType(Argument::type(Type::class), false, Argument::that(static function (Operation $arg) use ($operation): bool {
+ return $arg->getName() === $operation->getName();
+ }), $resourceClass, $resourceClass, null, 0)->willReturn($graphqlType);
$this->typeConverterProphecy->resolveType(Argument::type('string'))->willReturn(GraphQLType::string());
$this->typeBuilderProphecy->isCollection(Argument::type(Type::class))->willReturn(false);
- $this->resourceMetadataCollectionFactoryProphecy->create($resourceClass)->willReturn(new ResourceMetadataCollection($resourceClass, [(new ApiResource())->withGraphQlOperations([$queryName => $operation])]));
- $this->itemResolverFactoryProphecy->__invoke($resourceClass, $resourceClass, $queryName)->willReturn($resolver);
+ $this->resourceMetadataCollectionFactoryProphecy->create($resourceClass)->willReturn(new ResourceMetadataCollection($resourceClass, [(new ApiResource())->withGraphQlOperations([$operation->getName() => $operation])]));
+ $this->itemResolverFactoryProphecy->__invoke($resourceClass, $resourceClass, $operation->getName())->willReturn($resolver);
- $queryFields = $this->fieldsBuilder->getItemQueryFields($resourceClass, $operation, $queryName, $configuration);
+ $queryFields = $this->fieldsBuilder->getItemQueryFields($resourceClass, $operation, $configuration);
$this->assertEquals($expectedQueryFields, $queryFields);
}
@@ -156,8 +159,8 @@ public function testGetItemQueryFields(string $resourceClass, Operation $operati
public function itemQueryFieldsProvider(): array
{
return [
- 'no resource field configuration' => ['resourceClass', (new Query()), 'action', [], null, null, []],
- 'nominal standard type case with deprecation reason and description' => ['resourceClass', (new Query())->withShortName('ShortName')->withDeprecationReason('not useful')->withDescription('Custom description.'), 'action', [], GraphQLType::string(), null,
+ 'no resource field configuration' => ['resourceClass', (new Query())->withName('action'), [], null, null, []],
+ 'nominal standard type case with deprecation reason and description' => ['resourceClass', (new Query())->withName('action')->withShortName('ShortName')->withDeprecationReason('not useful')->withDescription('Custom description.'), [], GraphQLType::string(), null,
[
'actionShortName' => [
'type' => GraphQLType::string(),
@@ -170,7 +173,7 @@ public function itemQueryFieldsProvider(): array
],
],
],
- 'nominal item case' => ['resourceClass', (new Query())->withShortName('ShortName'), 'action', [], $graphqlType = new ObjectType(['name' => 'item']), $resolver = function () {
+ 'nominal item case' => ['resourceClass', (new Query())->withName('action')->withShortName('ShortName'), [], $graphqlType = new ObjectType(['name' => 'item']), $resolver = function () {
},
[
'actionShortName' => [
@@ -185,7 +188,7 @@ public function itemQueryFieldsProvider(): array
],
],
'empty overridden args and add fields' => [
- 'resourceClass', (new Query())->withShortName('ShortName'), 'item_query', ['args' => [], 'name' => 'customActionName'], GraphQLType::string(), null,
+ 'resourceClass', (new Query())->withShortName('ShortName'), ['args' => [], 'name' => 'customActionName'], GraphQLType::string(), null,
[
'shortName' => [
'type' => GraphQLType::string(),
@@ -198,7 +201,7 @@ public function itemQueryFieldsProvider(): array
],
],
'override args with custom ones' => [
- 'resourceClass', (new Query())->withShortName('ShortName'), 'item_query', ['args' => ['customArg' => ['type' => 'a type']]], GraphQLType::string(), null,
+ 'resourceClass', (new Query())->withShortName('ShortName'), ['args' => ['customArg' => ['type' => 'a type']]], GraphQLType::string(), null,
[
'shortName' => [
'type' => GraphQLType::string(),
@@ -219,14 +222,16 @@ public function itemQueryFieldsProvider(): array
/**
* @dataProvider collectionQueryFieldsProvider
*/
- public function testGetCollectionQueryFields(string $resourceClass, Operation $operation, string $queryName, array $configuration, ?GraphQLType $graphqlType, ?callable $resolver, array $expectedQueryFields): void
+ public function testGetCollectionQueryFields(string $resourceClass, Operation $operation, array $configuration, ?GraphQLType $graphqlType, ?callable $resolver, array $expectedQueryFields): void
{
- $this->typeConverterProphecy->convertType(Argument::type(Type::class), false, $queryName, $resourceClass, $resourceClass, null, 0)->willReturn($graphqlType);
+ $this->typeConverterProphecy->convertType(Argument::type(Type::class), false, Argument::that(static function (Operation $arg) use ($operation): bool {
+ return $arg->getName() === $operation->getName();
+ }), $resourceClass, $resourceClass, null, 0)->willReturn($graphqlType);
$this->typeConverterProphecy->resolveType(Argument::type('string'))->willReturn(GraphQLType::string());
$this->typeBuilderProphecy->isCollection(Argument::type(Type::class))->willReturn(true);
- $this->typeBuilderProphecy->getResourcePaginatedCollectionType($graphqlType, $resourceClass, $queryName)->willReturn($graphqlType);
- $this->resourceMetadataCollectionFactoryProphecy->create($resourceClass)->willReturn(new ResourceMetadataCollection($resourceClass, [(new ApiResource())->withGraphQlOperations([$queryName => $operation])]));
- $this->collectionResolverFactoryProphecy->__invoke($resourceClass, $resourceClass, $queryName)->willReturn($resolver);
+ $this->typeBuilderProphecy->getResourcePaginatedCollectionType($graphqlType, $resourceClass, $operation->getName())->willReturn($graphqlType);
+ $this->resourceMetadataCollectionFactoryProphecy->create($resourceClass)->willReturn(new ResourceMetadataCollection($resourceClass, [(new ApiResource())->withGraphQlOperations([$operation->getName() => $operation])]));
+ $this->collectionResolverFactoryProphecy->__invoke($resourceClass, $resourceClass, $operation->getName())->willReturn($resolver);
$this->filterLocatorProphecy->has('my_filter')->willReturn(true);
$filterProphecy = $this->prophesize(FilterInterface::class);
$filterProphecy->getDescription($resourceClass)->willReturn([
@@ -241,7 +246,7 @@ public function testGetCollectionQueryFields(string $resourceClass, Operation $o
$this->typesContainerProphecy->set('ShortNameFilter_dateField', Argument::type(ListOfType::class));
$this->typesContainerProphecy->set('ShortNameFilter_parent__child', Argument::type(ListOfType::class));
- $queryFields = $this->fieldsBuilder->getCollectionQueryFields($resourceClass, $operation, $queryName, $configuration);
+ $queryFields = $this->fieldsBuilder->getCollectionQueryFields($resourceClass, $operation, $configuration);
$this->assertEquals($expectedQueryFields, $queryFields);
}
@@ -249,8 +254,8 @@ public function testGetCollectionQueryFields(string $resourceClass, Operation $o
public function collectionQueryFieldsProvider(): array
{
return [
- 'no resource field configuration' => ['resourceClass', new Query(), 'action', [], null, null, []],
- 'nominal collection case with deprecation reason and description' => ['resourceClass', (new Query())->withCollection(true)->withShortName('ShortName')->withDeprecationReason('not useful')->withDescription('Custom description.'), 'action', [], $graphqlType = GraphQLType::listOf(new ObjectType(['name' => 'collection'])), $resolver = function () {
+ 'no resource field configuration' => ['resourceClass', (new QueryCollection())->withName('action'), [], null, null, []],
+ 'nominal collection case with deprecation reason and description' => ['resourceClass', (new QueryCollection())->withName('action')->withShortName('ShortName')->withDeprecationReason('not useful')->withDescription('Custom description.'), [], $graphqlType = GraphQLType::listOf(new ObjectType(['name' => 'collection'])), $resolver = function () {
},
[
'actionShortNames' => [
@@ -279,7 +284,7 @@ public function collectionQueryFieldsProvider(): array
],
],
],
- 'collection with filters' => ['resourceClass', (new Query())->withShortName('ShortName')->withCollection(true)->withFilters(['my_filter']), 'action', [], $graphqlType = GraphQLType::listOf(new ObjectType(['name' => 'collection'])), $resolver = function () {
+ 'collection with filters' => ['resourceClass', (new QueryCollection())->withName('action')->withShortName('ShortName')->withFilters(['my_filter']), [], $graphqlType = GraphQLType::listOf(new ObjectType(['name' => 'collection'])), $resolver = function () {
},
[
'actionShortNames' => [
@@ -313,7 +318,7 @@ public function collectionQueryFieldsProvider(): array
],
],
'collection empty overridden args and add fields' => [
- 'resourceClass', (new Query())->withCollection(true)->withShortName('ShortName')->withArgs([]), 'action', ['args' => [], 'name' => 'customActionName'], $graphqlType = GraphQLType::listOf(new ObjectType(['name' => 'collection'])), $resolver = function () {
+ 'resourceClass', (new QueryCollection())->withName('action')->withShortName('ShortName')->withArgs([]), ['args' => [], 'name' => 'customActionName'], $graphqlType = GraphQLType::listOf(new ObjectType(['name' => 'collection'])), $resolver = function () {
},
[
'actionShortNames' => [
@@ -327,7 +332,7 @@ public function collectionQueryFieldsProvider(): array
],
],
'collection override args with custom ones' => [
- 'resourceClass', (new Query())->withCollection(true)->withShortName('ShortName'), 'action', ['args' => ['customArg' => ['type' => 'a type']]], $graphqlType = GraphQLType::listOf(new ObjectType(['name' => 'collection'])), $resolver = function () {
+ 'resourceClass', (new QueryCollection())->withName('action')->withShortName('ShortName'), ['args' => ['customArg' => ['type' => 'a type']]], $graphqlType = GraphQLType::listOf(new ObjectType(['name' => 'collection'])), $resolver = function () {
},
[
'actionShortNames' => [
@@ -343,7 +348,7 @@ public function collectionQueryFieldsProvider(): array
],
],
],
- 'collection with page-based pagination enabled' => ['resourceClass', (new Query())->withCollection(true)->withShortName('ShortName')->withPaginationType('page')->withFilters(['my_filter']), 'action', [], $graphqlType = GraphQLType::listOf(new ObjectType(['name' => 'collection'])), $resolver = function () {
+ 'collection with page-based pagination enabled' => ['resourceClass', (new QueryCollection())->withName('action')->withShortName('ShortName')->withPaginationType('page')->withFilters(['my_filter']), [], $graphqlType = GraphQLType::listOf(new ObjectType(['name' => 'collection'])), $resolver = function () {
},
[
'actionShortNames' => [
@@ -370,16 +375,20 @@ public function collectionQueryFieldsProvider(): array
/**
* @dataProvider mutationFieldsProvider
*/
- public function testGetMutationFields(string $resourceClass, Operation $operation, string $mutationName, GraphQLType $graphqlType, GraphQLType $inputGraphqlType, ?callable $mutationResolver, array $expectedMutationFields): void
+ public function testGetMutationFields(string $resourceClass, Operation $operation, GraphQLType $graphqlType, GraphQLType $inputGraphqlType, ?callable $mutationResolver, array $expectedMutationFields): void
{
- $this->typeConverterProphecy->convertType(Argument::type(Type::class), false, $mutationName, $resourceClass, $resourceClass, null, 0)->willReturn($graphqlType);
- $this->typeConverterProphecy->convertType(Argument::type(Type::class), true, $mutationName, $resourceClass, $resourceClass, null, 0)->willReturn($inputGraphqlType);
+ $this->typeConverterProphecy->convertType(Argument::type(Type::class), false, Argument::that(static function (Operation $arg) use ($operation): bool {
+ return $arg->getName() === $operation->getName();
+ }), $resourceClass, $resourceClass, null, 0)->willReturn($graphqlType);
+ $this->typeConverterProphecy->convertType(Argument::type(Type::class), true, Argument::that(static function (Operation $arg) use ($operation): bool {
+ return $arg->getName() === $operation->getName();
+ }), $resourceClass, $resourceClass, null, 0)->willReturn($inputGraphqlType);
$this->typeBuilderProphecy->isCollection(Argument::type(Type::class))->willReturn(false);
- $this->typeBuilderProphecy->getResourcePaginatedCollectionType($graphqlType, $resourceClass, $mutationName)->willReturn($graphqlType);
- $this->resourceMetadataCollectionFactoryProphecy->create($resourceClass)->willReturn(new ResourceMetadataCollection($resourceClass, [(new ApiResource())->withGraphQlOperations([$mutationName => $operation])]));
- $this->itemMutationResolverFactoryProphecy->__invoke($resourceClass, $resourceClass, $mutationName)->willReturn($mutationResolver);
+ $this->typeBuilderProphecy->getResourcePaginatedCollectionType($graphqlType, $resourceClass, $operation->getName())->willReturn($graphqlType);
+ $this->resourceMetadataCollectionFactoryProphecy->create($resourceClass)->willReturn(new ResourceMetadataCollection($resourceClass, [(new ApiResource())->withGraphQlOperations([$operation->getName() => $operation])]));
+ $this->itemMutationResolverFactoryProphecy->__invoke($resourceClass, $resourceClass, $operation->getName())->willReturn($mutationResolver);
- $mutationFields = $this->fieldsBuilder->getMutationFields($resourceClass, $operation, $mutationName);
+ $mutationFields = $this->fieldsBuilder->getMutationFields($resourceClass, $operation);
$this->assertEquals($expectedMutationFields, $mutationFields);
}
@@ -387,7 +396,7 @@ public function testGetMutationFields(string $resourceClass, Operation $operatio
public function mutationFieldsProvider(): array
{
return [
- 'nominal case with deprecation reason' => ['resourceClass', (new Mutation())->withShortName('ShortName')->withDeprecationReason('not useful'), 'action', $graphqlType = new ObjectType(['name' => 'mutation']), $inputGraphqlType = new ObjectType(['name' => 'input']), $mutationResolver = function () {
+ 'nominal case with deprecation reason' => ['resourceClass', (new Mutation())->withName('action')->withShortName('ShortName')->withDeprecationReason('not useful'), $graphqlType = new ObjectType(['name' => 'mutation']), $inputGraphqlType = new ObjectType(['name' => 'input']), $mutationResolver = function () {
},
[
'actionShortName' => [
@@ -407,7 +416,7 @@ public function mutationFieldsProvider(): array
],
],
],
- 'custom description' => ['resourceClass', (new Mutation())->withShortName('ShortName')->withDescription('Custom description.'), 'action', $graphqlType = new ObjectType(['name' => 'mutation']), $inputGraphqlType = new ObjectType(['name' => 'input']), $mutationResolver = function () {
+ 'custom description' => ['resourceClass', (new Mutation())->withName('action')->withShortName('ShortName')->withDescription('Custom description.'), $graphqlType = new ObjectType(['name' => 'mutation']), $inputGraphqlType = new ObjectType(['name' => 'input']), $mutationResolver = function () {
},
[
'actionShortName' => [
@@ -433,16 +442,20 @@ public function mutationFieldsProvider(): array
/**
* @dataProvider subscriptionFieldsProvider
*/
- public function testGetSubscriptionFields(string $resourceClass, Operation $operation, string $subscriptionName, GraphQLType $graphqlType, GraphQLType $inputGraphqlType, ?callable $subscriptionResolver, array $expectedSubscriptionFields): void
+ public function testGetSubscriptionFields(string $resourceClass, Operation $operation, GraphQLType $graphqlType, GraphQLType $inputGraphqlType, ?callable $subscriptionResolver, array $expectedSubscriptionFields): void
{
- $this->typeConverterProphecy->convertType(Argument::type(Type::class), false, $subscriptionName, $resourceClass, $resourceClass, null, 0)->willReturn($graphqlType);
- $this->typeConverterProphecy->convertType(Argument::type(Type::class), true, $subscriptionName, $resourceClass, $resourceClass, null, 0)->willReturn($inputGraphqlType);
+ $this->typeConverterProphecy->convertType(Argument::type(Type::class), false, Argument::that(static function (Operation $arg) use ($operation): bool {
+ return $arg->getName() === $operation->getName();
+ }), $resourceClass, $resourceClass, null, 0)->willReturn($graphqlType);
+ $this->typeConverterProphecy->convertType(Argument::type(Type::class), true, Argument::that(static function (Operation $arg) use ($operation): bool {
+ return $arg->getName() === $operation->getName();
+ }), $resourceClass, $resourceClass, null, 0)->willReturn($inputGraphqlType);
$this->typeBuilderProphecy->isCollection(Argument::type(Type::class))->willReturn(false);
- $this->typeBuilderProphecy->getResourcePaginatedCollectionType($graphqlType, $resourceClass, $subscriptionName)->willReturn($graphqlType);
- $this->resourceMetadataCollectionFactoryProphecy->create($resourceClass)->willReturn(new ResourceMetadataCollection($resourceClass, [(new ApiResource())->withGraphQlOperations([$subscriptionName => $operation])]));
- $this->itemSubscriptionResolverFactoryProphecy->__invoke($resourceClass, $resourceClass, $subscriptionName)->willReturn($subscriptionResolver);
+ $this->typeBuilderProphecy->getResourcePaginatedCollectionType($graphqlType, $resourceClass, $operation->getName())->willReturn($graphqlType);
+ $this->resourceMetadataCollectionFactoryProphecy->create($resourceClass)->willReturn(new ResourceMetadataCollection($resourceClass, [(new ApiResource())->withGraphQlOperations([$operation->getName() => $operation])]));
+ $this->itemSubscriptionResolverFactoryProphecy->__invoke($resourceClass, $resourceClass, $operation->getName())->willReturn($subscriptionResolver);
- $subscriptionFields = $this->fieldsBuilder->getSubscriptionFields($resourceClass, $operation, $subscriptionName);
+ $subscriptionFields = $this->fieldsBuilder->getSubscriptionFields($resourceClass, $operation);
$this->assertEquals($expectedSubscriptionFields, $subscriptionFields);
}
@@ -450,9 +463,9 @@ public function testGetSubscriptionFields(string $resourceClass, Operation $oper
public function subscriptionFieldsProvider(): array
{
return [
- 'mercure not enabled' => ['resourceClass', (new Subscription())->withShortName('ShortName'), 'action', new ObjectType(['name' => 'subscription']), new ObjectType(['name' => 'input']), null, [],
+ 'mercure not enabled' => ['resourceClass', (new Subscription())->withName('action')->withShortName('ShortName'), new ObjectType(['name' => 'subscription']), new ObjectType(['name' => 'input']), null, [],
],
- 'nominal case with deprecation reason' => ['resourceClass', (new Subscription())->withShortName('ShortName')->withMercure(true)->withDeprecationReason('not useful'), 'action', $graphqlType = new ObjectType(['name' => 'subscription']), $inputGraphqlType = new ObjectType(['name' => 'input']), $subscriptionResolver = function () {
+ 'nominal case with deprecation reason' => ['resourceClass', (new Subscription())->withName('action')->withShortName('ShortName')->withMercure(true)->withDeprecationReason('not useful'), $graphqlType = new ObjectType(['name' => 'subscription']), $inputGraphqlType = new ObjectType(['name' => 'input']), $subscriptionResolver = function () {
},
[
'actionShortNameSubscribe' => [
@@ -472,7 +485,7 @@ public function subscriptionFieldsProvider(): array
],
],
],
- 'custom description' => ['resourceClass', (new Subscription())->withShortName('ShortName')->withMercure(true)->withDescription('Custom description.'), 'action', $graphqlType = new ObjectType(['name' => 'subscription']), $inputGraphqlType = new ObjectType(['name' => 'input']), $subscriptionResolver = function () {
+ 'custom description' => ['resourceClass', (new Subscription())->withName('action')->withShortName('ShortName')->withMercure(true)->withDescription('Custom description.'), $graphqlType = new ObjectType(['name' => 'subscription']), $inputGraphqlType = new ObjectType(['name' => 'input']), $subscriptionResolver = function () {
},
[
'actionShortNameSubscribe' => [
@@ -498,40 +511,46 @@ public function subscriptionFieldsProvider(): array
/**
* @dataProvider resourceObjectTypeFieldsProvider
*/
- public function testGetResourceObjectTypeFields(string $resourceClass, Operation $operation, array $properties, bool $input, ?string $queryName, ?string $mutationName, ?string $subscriptionName, ?array $ioMetadata, array $expectedResourceObjectTypeFields, ?AdvancedNameConverterInterface $advancedNameConverter = null): void
+ public function testGetResourceObjectTypeFields(string $resourceClass, Operation $operation, array $properties, bool $input, int $depth, ?array $ioMetadata, array $expectedResourceObjectTypeFields, ?AdvancedNameConverterInterface $advancedNameConverter = null): void
{
$this->propertyNameCollectionFactoryProphecy->create($resourceClass)->willReturn(new PropertyNameCollection(array_keys($properties)));
foreach ($properties as $propertyName => $propertyMetadata) {
$this->propertyMetadataFactoryProphecy->create($resourceClass, $propertyName, ['normalization_groups' => null, 'denormalization_groups' => null])->willReturn($propertyMetadata);
- $this->typeConverterProphecy->convertType(new Type(Type::BUILTIN_TYPE_NULL), Argument::type('bool'), $queryName, '', $resourceClass, $propertyName, 1)->willReturn(null);
- $this->typeConverterProphecy->convertType(new Type(Type::BUILTIN_TYPE_CALLABLE), Argument::type('bool'), $queryName, '', $resourceClass, $propertyName, 1)->willReturn('NotRegisteredType');
- $this->typeConverterProphecy->convertType(Argument::type(Type::class), Argument::type('bool'), $queryName, '', $resourceClass, $propertyName, 1)->willReturn(GraphQLType::string());
- $this->typeConverterProphecy->convertType(Argument::type(Type::class), Argument::type('bool'), $mutationName, '', $resourceClass, $propertyName, 1)->willReturn(GraphQLType::string());
+ $this->typeConverterProphecy->convertType(new Type(Type::BUILTIN_TYPE_NULL), Argument::type('bool'), Argument::that(static function (Operation $arg) use ($operation): bool {
+ return $arg->getName() === $operation->getName();
+ }), '', $resourceClass, $propertyName, $depth + 1)->willReturn(null);
+ $this->typeConverterProphecy->convertType(new Type(Type::BUILTIN_TYPE_CALLABLE), Argument::type('bool'), Argument::that(static function (Operation $arg) use ($operation): bool {
+ return $arg->getName() === $operation->getName();
+ }), '', $resourceClass, $propertyName, $depth + 1)->willReturn('NotRegisteredType');
+ $this->typeConverterProphecy->convertType(Argument::type(Type::class), Argument::type('bool'), Argument::that(static function (Operation $arg) use ($operation): bool {
+ return $arg->getName() === $operation->getName();
+ }), '', $resourceClass, $propertyName, $depth + 1)->willReturn(GraphQLType::string());
if ('propertyObject' === $propertyName) {
- $this->typeConverterProphecy->convertType(Argument::type(Type::class), Argument::type('bool'), $mutationName, 'objectClass', $resourceClass, $propertyName, 1)->willReturn(new ObjectType(['name' => 'objectType']));
+ $this->typeConverterProphecy->convertType(Argument::type(Type::class), Argument::type('bool'), Argument::that(static function (Operation $arg) use ($operation): bool {
+ return $arg->getName() === $operation->getName();
+ }), 'objectClass', $resourceClass, $propertyName, $depth + 1)->willReturn(new ObjectType(['name' => 'objectType']));
$this->resourceMetadataCollectionFactoryProphecy->create('objectClass')->willReturn(new ResourceMetadataCollection($resourceClass, [(new ApiResource())->withGraphQlOperations(['item_query' => new Query()])]));
- $this->itemResolverFactoryProphecy->__invoke('objectClass', $resourceClass, $queryName ?? $mutationName ?? $subscriptionName)->willReturn(static function () {
+ $this->itemResolverFactoryProphecy->__invoke('objectClass', $resourceClass, $operation->getName())->willReturn(static function () {
});
}
- $this->typeConverterProphecy->convertType(Argument::type(Type::class), Argument::type('bool'), $subscriptionName, '', $resourceClass, $propertyName, 1)->willReturn(GraphQLType::string());
- $this->typeConverterProphecy->convertType(Argument::type(Type::class), true, $mutationName, 'subresourceClass', $propertyName, 1)->willReturn(GraphQLType::string());
- $this->typeConverterProphecy->convertType(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING)), Argument::type('bool'), $queryName ?? $mutationName ?? $subscriptionName, '', $resourceClass, $propertyName, 1)->willReturn(GraphQLType::nonNull(GraphQLType::listOf(GraphQLType::nonNull(GraphQLType::string()))));
+ $this->typeConverterProphecy->convertType(Argument::type(Type::class), true, Argument::that(static function (Operation $arg) use ($operation): bool {
+ return $arg->getName() === $operation->getName();
+ }), 'subresourceClass', $propertyName, $depth + 1)->willReturn(GraphQLType::string());
+ $this->typeConverterProphecy->convertType(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING)), Argument::type('bool'), Argument::that(static function (Operation $arg) use ($operation): bool {
+ return $arg->getName() === $operation->getName();
+ }), '', $resourceClass, $propertyName, $depth + 1)->willReturn(GraphQLType::nonNull(GraphQLType::listOf(GraphQLType::nonNull(GraphQLType::string()))));
}
$this->typesContainerProphecy->has('NotRegisteredType')->willReturn(false);
$this->typesContainerProphecy->all()->willReturn([]);
$this->typeBuilderProphecy->isCollection(Argument::type(Type::class))->willReturn(false);
- $operation = $queryName ? new Query() : new Mutation();
- if ($subscriptionName) {
- $operation = new Subscription();
- }
- $this->resourceMetadataCollectionFactoryProphecy->create('resourceClass')->willReturn(new ResourceMetadataCollection($resourceClass, [(new ApiResource())->withGraphQlOperations([$queryName ?? $mutationName ?? $subscriptionName => $operation])]));
+ $this->resourceMetadataCollectionFactoryProphecy->create('resourceClass')->willReturn(new ResourceMetadataCollection($resourceClass, [(new ApiResource())->withGraphQlOperations([$operation->getName() => $operation])]));
$this->resourceMetadataCollectionFactoryProphecy->create('subresourceClass')->willReturn(new ResourceMetadataCollection($resourceClass, [(new ApiResource())->withGraphQlOperations(['item_query' => new Query()])]));
$fieldsBuilder = $this->fieldsBuilder;
if ($advancedNameConverter) {
$fieldsBuilder = $this->buildFieldsBuilder($advancedNameConverter);
}
- $resourceObjectTypeFields = $fieldsBuilder->getResourceObjectTypeFields($resourceClass, $operation, $input, $queryName ?? $mutationName ?? $subscriptionName, 0, $ioMetadata);
+ $resourceObjectTypeFields = $fieldsBuilder->getResourceObjectTypeFields($resourceClass, $operation, $input, $depth, $ioMetadata);
$this->assertEquals($expectedResourceObjectTypeFields, $resourceObjectTypeFields);
}
@@ -549,7 +568,7 @@ public function resourceObjectTypeFieldsProvider(): array
'propertyNotReadable' => (new ApiProperty())->withBuiltinTypes([new Type(Type::BUILTIN_TYPE_BOOL)])->withReadable(false)->withWritable(false),
'nameConverted' => (new ApiProperty())->withBuiltinTypes([new Type(Type::BUILTIN_TYPE_STRING)])->withReadable(true)->withWritable(false),
],
- false, 'item_query', null, null, null,
+ false, 0, null,
[
'id' => [
'type' => GraphQLType::nonNull(GraphQLType::id()),
@@ -574,7 +593,7 @@ public function resourceObjectTypeFieldsProvider(): array
[
'field' => (new ApiProperty())->withBuiltinTypes([new Type(Type::BUILTIN_TYPE_STRING)])->withReadable(true)->withWritable(false),
],
- false, 'item_query', null, null, null,
+ false, 0, null,
[
'id' => [
'type' => GraphQLType::nonNull(GraphQLType::id()),
@@ -594,7 +613,7 @@ public function resourceObjectTypeFieldsProvider(): array
'property' => new ApiProperty(),
'propertyBool' => (new ApiProperty())->withBuiltinTypes([new Type(Type::BUILTIN_TYPE_BOOL)])->withReadable(false)->withWritable(false),
],
- true, 'item_query', null, null, null,
+ true, 0, null,
[
'id' => [
'type' => GraphQLType::nonNull(GraphQLType::id()),
@@ -614,7 +633,7 @@ public function resourceObjectTypeFieldsProvider(): array
new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING)),
])->withReadable(true)->withWritable(false),
],
- false, 'item_query', null, null, null,
+ false, 0, null,
[
'id' => [
'type' => GraphQLType::nonNull(GraphQLType::id()),
@@ -628,14 +647,14 @@ public function resourceObjectTypeFieldsProvider(): array
],
],
],
- 'mutation non input' => ['resourceClass', new Mutation(),
+ 'mutation non input' => ['resourceClass', (new Mutation())->withName('mutation'),
[
'property' => new ApiProperty(),
'propertyBool' => (new ApiProperty())->withBuiltinTypes([new Type(Type::BUILTIN_TYPE_BOOL)])->withReadable(false)->withWritable(true),
'propertyReadable' => (new ApiProperty())->withBuiltinTypes([new Type(Type::BUILTIN_TYPE_BOOL)])->withReadable(true)->withWritable(true),
'propertyObject' => (new ApiProperty())->withBuiltinTypes([new Type(Type::BUILTIN_TYPE_BOOL, false, 'objectClass')])->withReadable(true)->withWritable(true),
],
- false, null, 'mutation', null, null,
+ false, 0, null,
[
'id' => [
'type' => GraphQLType::nonNull(GraphQLType::id()),
@@ -657,14 +676,14 @@ public function resourceObjectTypeFieldsProvider(): array
],
],
],
- 'mutation input' => ['resourceClass', new Mutation(),
+ 'mutation input' => ['resourceClass', (new Mutation())->withName('mutation'),
[
'property' => new ApiProperty(),
'propertyBool' => (new ApiProperty())->withBuiltinTypes([new Type(Type::BUILTIN_TYPE_BOOL)])->withDescription('propertyBool description')->withReadable(false)->withWritable(true)->withDeprecationReason('not useful'),
'propertySubresource' => (new ApiProperty())->withBuiltinTypes([new Type(Type::BUILTIN_TYPE_BOOL)])->withReadable(false)->withWritable(true),
'id' => (new ApiProperty())->withBuiltinTypes([new Type(Type::BUILTIN_TYPE_INT)])->withReadable(false)->withWritable(true),
],
- true, null, 'mutation', null, null,
+ true, 0, null,
[
'id' => [
'type' => GraphQLType::nonNull(GraphQLType::id()),
@@ -693,11 +712,30 @@ public function resourceObjectTypeFieldsProvider(): array
'clientMutationId' => GraphQLType::string(),
],
],
- 'delete mutation input' => ['resourceClass', new Mutation(),
+ 'mutation nested input' => ['resourceClass', (new Mutation())->withName('mutation'),
+ [
+ 'propertyBool' => (new ApiProperty())->withBuiltinTypes([new Type(Type::BUILTIN_TYPE_BOOL)])->withReadable(false)->withWritable(true),
+ ],
+ true, 1, null,
+ [
+ 'id' => [
+ 'type' => GraphQLType::id(),
+ ],
+ 'propertyBool' => [
+ 'type' => GraphQLType::nonNull(GraphQLType::string()),
+ 'description' => null,
+ 'args' => [],
+ 'resolve' => null,
+ 'deprecationReason' => null,
+ ],
+ 'clientMutationId' => GraphQLType::string(),
+ ],
+ ],
+ 'delete mutation input' => ['resourceClass', (new Mutation())->withName('delete'),
[
'propertyBool' => (new ApiProperty())->withBuiltinTypes([new Type(Type::BUILTIN_TYPE_BOOL)])->withReadable(false)->withWritable(true),
],
- true, null, 'delete', null, null,
+ true, 0, null,
[
'id' => [
'type' => GraphQLType::nonNull(GraphQLType::id()),
@@ -705,11 +743,11 @@ public function resourceObjectTypeFieldsProvider(): array
'clientMutationId' => GraphQLType::string(),
],
],
- 'create mutation input' => ['resourceClass', new Mutation(),
+ 'create mutation input' => ['resourceClass', (new Mutation())->withName('create'),
[
'propertyBool' => (new ApiProperty())->withBuiltinTypes([new Type(Type::BUILTIN_TYPE_BOOL)])->withReadable(false)->withWritable(true),
],
- true, null, 'create', null, null,
+ true, 0, null,
[
'propertyBool' => [
'type' => GraphQLType::nonNull(GraphQLType::string()),
@@ -721,11 +759,11 @@ public function resourceObjectTypeFieldsProvider(): array
'clientMutationId' => GraphQLType::string(),
],
],
- 'update mutation input' => ['resourceClass', new Mutation(),
+ 'update mutation input' => ['resourceClass', (new Mutation())->withName('update'),
[
'propertyBool' => (new ApiProperty())->withBuiltinTypes([new Type(Type::BUILTIN_TYPE_BOOL)])->withReadable(false)->withWritable(true),
],
- true, null, 'update', null, null,
+ true, 0, null,
[
'id' => [
'type' => GraphQLType::nonNull(GraphQLType::id()),
@@ -746,7 +784,7 @@ public function resourceObjectTypeFieldsProvider(): array
'propertyBool' => (new ApiProperty())->withBuiltinTypes([new Type(Type::BUILTIN_TYPE_BOOL)])->withReadable(false)->withWritable(true),
'propertyReadable' => (new ApiProperty())->withBuiltinTypes([new Type(Type::BUILTIN_TYPE_BOOL)])->withReadable(true)->withWritable(true),
],
- false, null, null, 'subscription', null,
+ false, 0, null,
[
'id' => [
'type' => GraphQLType::nonNull(GraphQLType::id()),
@@ -767,7 +805,7 @@ public function resourceObjectTypeFieldsProvider(): array
'propertySubresource' => (new ApiProperty())->withBuiltinTypes([new Type(Type::BUILTIN_TYPE_BOOL)])->withReadable(false)->withWritable(true),
'id' => (new ApiProperty())->withBuiltinTypes([new Type(Type::BUILTIN_TYPE_INT)])->withReadable(false)->withWritable(true),
],
- true, null, null, 'subscription', null,
+ true, 0, null,
[
'id' => [
'type' => GraphQLType::nonNull(GraphQLType::id()),
@@ -779,13 +817,13 @@ public function resourceObjectTypeFieldsProvider(): array
[
'propertyBool' => (new ApiProperty())->withBuiltinTypes([new Type(Type::BUILTIN_TYPE_BOOL)])->withReadable(false)->withWritable(true),
],
- false, null, 'update', null, ['class' => null], [],
+ false, 0, ['class' => null], [],
],
'null io metadata input' => ['resourceClass', new Query(),
[
'propertyBool' => (new ApiProperty())->withBuiltinTypes([new Type(Type::BUILTIN_TYPE_BOOL)])->withReadable(false)->withWritable(true),
],
- true, null, 'update', null, ['class' => null],
+ true, 0, ['class' => null],
[
'clientMutationId' => GraphQLType::string(),
],
@@ -795,7 +833,7 @@ public function resourceObjectTypeFieldsProvider(): array
'propertyInvalidType' => (new ApiProperty())->withBuiltinTypes([new Type(Type::BUILTIN_TYPE_NULL)])->withReadable(true)->withWritable(false),
'propertyNotRegisteredType' => (new ApiProperty())->withBuiltinTypes([new Type(Type::BUILTIN_TYPE_CALLABLE)])->withReadable(true)->withWritable(false),
],
- false, 'item_query', null, null, null,
+ false, 0, null,
[
'id' => [
'type' => GraphQLType::nonNull(GraphQLType::id()),
@@ -816,7 +854,7 @@ public function testResolveResourceArgs(array $args, array $expectedResolvedArgs
$this->typeConverterProphecy->resolveType(Argument::type('string'))->willReturn(GraphQLType::string());
- $args = $this->fieldsBuilder->resolveResourceArgs($args, 'operation', 'shortName');
+ $args = $this->fieldsBuilder->resolveResourceArgs($args, (new Operation())->withName('operation')->withShortName('shortName'));
$this->assertSame($expectedResolvedArgs, $args);
}
diff --git a/tests/GraphQl/Type/SchemaBuilderTest.php b/tests/GraphQl/Type/SchemaBuilderTest.php
index 5ad82af77ad..3f88a700d7e 100644
--- a/tests/GraphQl/Type/SchemaBuilderTest.php
+++ b/tests/GraphQl/Type/SchemaBuilderTest.php
@@ -24,6 +24,7 @@
use ApiPlatform\Metadata\GraphQl\Mutation;
use ApiPlatform\Metadata\GraphQl\Operation;
use ApiPlatform\Metadata\GraphQl\Query;
+use ApiPlatform\Metadata\GraphQl\QueryCollection;
use ApiPlatform\Metadata\GraphQl\Subscription;
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
use ApiPlatform\Metadata\Resource\ResourceMetadataCollection;
@@ -85,12 +86,24 @@ public function testGetSchema(string $resourceClass, ResourceMetadataCollection
$typeFoo->name = 'Foo';
$this->typesContainerProphecy->get('Foo')->willReturn(GraphQLType::listOf($typeFoo));
$this->fieldsBuilderProphecy->getNodeQueryFields()->shouldBeCalled()->willReturn(['node_fields']);
- $this->fieldsBuilderProphecy->getItemQueryFields($resourceClass, Argument::type(Operation::class), 'item_query', [])->willReturn(['query' => ['query_fields']]);
- $this->fieldsBuilderProphecy->getCollectionQueryFields($resourceClass, Argument::type(Operation::class), 'collection_query', [])->willReturn(['query' => ['query_fields']]);
- $this->fieldsBuilderProphecy->getItemQueryFields($resourceClass, Argument::type(Operation::class), 'custom_item_query', [])->willReturn(['custom_item_query' => ['custom_item_query_fields']]);
- $this->fieldsBuilderProphecy->getCollectionQueryFields($resourceClass, Argument::type(Operation::class), 'custom_collection_query', [])->willReturn(['custom_collection_query' => ['custom_collection_query_fields']]);
- $this->fieldsBuilderProphecy->getMutationFields($resourceClass, Argument::type(Operation::class), 'mutation')->willReturn(['mutation' => ['mutation_fields']]);
- $this->fieldsBuilderProphecy->getSubscriptionFields($resourceClass, Argument::type(Operation::class), 'update')->willReturn(['subscription' => ['subscription_fields']]);
+ $this->fieldsBuilderProphecy->getItemQueryFields($resourceClass, Argument::that(static function (Operation $arg): bool {
+ return 'item_query' === $arg->getName();
+ }), [])->willReturn(['query' => ['query_fields']]);
+ $this->fieldsBuilderProphecy->getCollectionQueryFields($resourceClass, Argument::that(static function (Operation $arg): bool {
+ return 'collection_query' === $arg->getName();
+ }), [])->willReturn(['query' => ['query_fields']]);
+ $this->fieldsBuilderProphecy->getItemQueryFields($resourceClass, Argument::that(static function (Operation $arg): bool {
+ return 'custom_item_query' === $arg->getName();
+ }), [])->willReturn(['custom_item_query' => ['custom_item_query_fields']]);
+ $this->fieldsBuilderProphecy->getCollectionQueryFields($resourceClass, Argument::that(static function (Operation $arg): bool {
+ return 'custom_collection_query' === $arg->getName();
+ }), [])->willReturn(['custom_collection_query' => ['custom_collection_query_fields']]);
+ $this->fieldsBuilderProphecy->getMutationFields($resourceClass, Argument::that(static function (Operation $arg): bool {
+ return 'mutation' === $arg->getName();
+ }))->willReturn(['mutation' => ['mutation_fields']]);
+ $this->fieldsBuilderProphecy->getSubscriptionFields($resourceClass, Argument::that(static function (Operation $arg): bool {
+ return 'update' === $arg->getName();
+ }))->willReturn(['subscription' => ['subscription_fields']]);
$this->resourceNameCollectionFactoryProphecy->create()->willReturn(new ResourceNameCollection([$resourceClass]));
$this->resourceMetadataCollectionFactoryProphecy->create($resourceClass)->willReturn($resourceMetadata);
@@ -123,7 +136,7 @@ public function schemaProvider(): array
],
]), null, null,
],
- 'collection query' => [$resourceClass = 'resourceClass', new ResourceMetadataCollection($resourceClass, [(new ApiResource())->withGraphQlOperations(['collection_query' => (new Query())->withCollection(true)])]),
+ 'collection query' => [$resourceClass = 'resourceClass', new ResourceMetadataCollection($resourceClass, [(new ApiResource())->withGraphQlOperations(['collection_query' => new QueryCollection()])]),
new ObjectType([
'name' => 'Query',
'fields' => [
@@ -132,7 +145,7 @@ public function schemaProvider(): array
],
]), null, null,
],
- 'custom item query' => [$resourceClass = 'resourceClass', new ResourceMetadataCollection($resourceClass, [(new ApiResource())->withGraphQlOperations(['custom_item_query' => (new Query())->withResolver('item_query_resolver')])]),
+ 'custom item query' => [$resourceClass = 'resourceClass', new ResourceMetadataCollection($resourceClass, [(new ApiResource())->withGraphQlOperations(['custom_item_query' => (new Query())->withName('custom_item_query')->withResolver('item_query_resolver')])]),
new ObjectType([
'name' => 'Query',
'fields' => [
@@ -141,7 +154,7 @@ public function schemaProvider(): array
],
]), null, null,
],
- 'custom collection query' => [$resourceClass = 'resourceClass', new ResourceMetadataCollection($resourceClass, [(new ApiResource())->withGraphQlOperations(['custom_collection_query' => (new Query())->withCollection(true)->withResolver('collection_query_resolver')])]),
+ 'custom collection query' => [$resourceClass = 'resourceClass', new ResourceMetadataCollection($resourceClass, [(new ApiResource())->withGraphQlOperations(['custom_collection_query' => (new QueryCollection())->withName('custom_collection_query')->withResolver('collection_query_resolver')])]),
new ObjectType([
'name' => 'Query',
'fields' => [
@@ -150,7 +163,7 @@ public function schemaProvider(): array
],
]), null, null,
],
- 'mutation' => [$resourceClass = 'resourceClass', new ResourceMetadataCollection($resourceClass, [(new ApiResource())->withGraphQlOperations(['mutation' => new Mutation()])]),
+ 'mutation' => [$resourceClass = 'resourceClass', new ResourceMetadataCollection($resourceClass, [(new ApiResource())->withGraphQlOperations(['mutation' => (new Mutation())->withName('mutation')])]),
new ObjectType([
'name' => 'Query',
'fields' => [
@@ -165,7 +178,7 @@ public function schemaProvider(): array
]),
null,
],
- 'subscription' => [$resourceClass = 'resourceClass', new ResourceMetadataCollection($resourceClass, [(new ApiResource())->withGraphQlOperations(['update' => (new Subscription())->withMercure(true)])]),
+ 'subscription' => [$resourceClass = 'resourceClass', new ResourceMetadataCollection($resourceClass, [(new ApiResource())->withGraphQlOperations(['update' => (new Subscription())->withName('update')->withMercure(true)])]),
new ObjectType([
'name' => 'Query',
'fields' => [
diff --git a/tests/GraphQl/Type/TypeBuilderTest.php b/tests/GraphQl/Type/TypeBuilderTest.php
index f4576bcf879..19b0feaaaaa 100644
--- a/tests/GraphQl/Type/TypeBuilderTest.php
+++ b/tests/GraphQl/Type/TypeBuilderTest.php
@@ -21,7 +21,9 @@
use ApiPlatform\GraphQl\Type\TypesContainerInterface;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\GraphQl\Mutation;
+use ApiPlatform\Metadata\GraphQl\Operation;
use ApiPlatform\Metadata\GraphQl\Query;
+use ApiPlatform\Metadata\GraphQl\QueryCollection;
use ApiPlatform\Metadata\GraphQl\Subscription;
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
use ApiPlatform\Metadata\Resource\ResourceMetadataCollection;
@@ -81,14 +83,15 @@ protected function setUp(): void
public function testGetResourceObjectType(): void
{
- $resourceMetadata = new ResourceMetadataCollection('resourceClass', [(new ApiResource())->withGraphQlOperations(['item_query' => (new Query())->withShortName('shortName')->withDescription('description')])]);
+ $resourceMetadataCollection = new ResourceMetadataCollection('resourceClass', []);
$this->typesContainerProphecy->has('shortName')->shouldBeCalled()->willReturn(false);
$this->typesContainerProphecy->set('shortName', Argument::type(ObjectType::class))->shouldBeCalled();
$this->typesContainerProphecy->has('Node')->shouldBeCalled()->willReturn(false);
$this->typesContainerProphecy->set('Node', Argument::type(InterfaceType::class))->shouldBeCalled();
+ $operation = (new Query())->withShortName('shortName')->withDescription('description');
/** @var ObjectType $resourceObjectType */
- $resourceObjectType = $this->typeBuilder->getResourceObjectType('resourceClass', $resourceMetadata, 'item_query', false);
+ $resourceObjectType = $this->typeBuilder->getResourceObjectType('resourceClass', $resourceMetadataCollection, $operation, false);
$this->assertSame('shortName', $resourceObjectType->name);
$this->assertSame('description', $resourceObjectType->description);
$this->assertSame($this->defaultFieldResolver, $resourceObjectType->resolveFieldFn);
@@ -96,21 +99,22 @@ public function testGetResourceObjectType(): void
$this->assertArrayHasKey('fields', $resourceObjectType->config);
$fieldsBuilderProphecy = $this->prophesize(FieldsBuilderInterface::class);
- $fieldsBuilderProphecy->getResourceObjectTypeFields('resourceClass', $resourceMetadata->getGraphQlOperation('item_query'), false, 'item_query', 0, null)->shouldBeCalled();
+ $fieldsBuilderProphecy->getResourceObjectTypeFields('resourceClass', $operation, false, 0, null)->shouldBeCalled();
$this->fieldsBuilderLocatorProphecy->get('api_platform.graphql.fields_builder')->shouldBeCalled()->willReturn($fieldsBuilderProphecy->reveal());
$resourceObjectType->config['fields']();
}
public function testGetResourceObjectTypeOutputClass(): void
{
- $resourceMetadata = new ResourceMetadataCollection('resourceClass', [(new ApiResource())->withGraphQlOperations(['item_query' => (new Query())->withShortName('shortName')->withDescription('description')->withOutput(['class' => 'outputClass'])])]);
+ $resourceMetadata = new ResourceMetadataCollection('resourceClass', []);
$this->typesContainerProphecy->has('shortName')->shouldBeCalled()->willReturn(false);
$this->typesContainerProphecy->set('shortName', Argument::type(ObjectType::class))->shouldBeCalled();
$this->typesContainerProphecy->has('Node')->shouldBeCalled()->willReturn(false);
$this->typesContainerProphecy->set('Node', Argument::type(InterfaceType::class))->shouldBeCalled();
+ $operation = (new Query())->withShortName('shortName')->withDescription('description')->withOutput(['class' => 'outputClass']);
/** @var ObjectType $resourceObjectType */
- $resourceObjectType = $this->typeBuilder->getResourceObjectType('resourceClass', $resourceMetadata, 'item_query', false);
+ $resourceObjectType = $this->typeBuilder->getResourceObjectType('resourceClass', $resourceMetadata, $operation, false);
$this->assertSame('shortName', $resourceObjectType->name);
$this->assertSame('description', $resourceObjectType->description);
$this->assertSame($this->defaultFieldResolver, $resourceObjectType->resolveFieldFn);
@@ -118,7 +122,7 @@ public function testGetResourceObjectTypeOutputClass(): void
$this->assertArrayHasKey('fields', $resourceObjectType->config);
$fieldsBuilderProphecy = $this->prophesize(FieldsBuilderInterface::class);
- $fieldsBuilderProphecy->getResourceObjectTypeFields('outputClass', $resourceMetadata->getGraphQlOperation('item_query'), false, 'item_query', 0, ['class' => 'outputClass'])->shouldBeCalled();
+ $fieldsBuilderProphecy->getResourceObjectTypeFields('outputClass', $operation, false, 0, ['class' => 'outputClass'])->shouldBeCalled();
$this->fieldsBuilderLocatorProphecy->get('api_platform.graphql.fields_builder')->shouldBeCalled()->willReturn($fieldsBuilderProphecy->reveal());
$resourceObjectType->config['fields']();
}
@@ -126,11 +130,11 @@ public function testGetResourceObjectTypeOutputClass(): void
/**
* @dataProvider resourceObjectTypeQuerySerializationGroupsProvider
*/
- public function testGetResourceObjectTypeQuerySerializationGroups(string $itemSerializationGroup, string $collectionSerializationGroup, string $shortName, string $queryName)
+ public function testGetResourceObjectTypeQuerySerializationGroups(string $itemSerializationGroup, string $collectionSerializationGroup, Operation $operation, string $shortName)
{
$resourceMetadata = new ResourceMetadataCollection('resourceClass', [(new ApiResource())->withGraphQlOperations([
- 'item_query' => (new Query())->withShortName('shortName')->withDescription('description')->withNormalizationContext(['groups' => [$itemSerializationGroup]]),
- 'collection_query' => (new Query())->withShortName('shortName')->withDescription('description')->withCollection(true)->withNormalizationContext(['groups' => [$collectionSerializationGroup]]),
+ 'item_query' => (new Query())->withShortName('shortName')->withNormalizationContext(['groups' => [$itemSerializationGroup]]),
+ 'collection_query' => (new QueryCollection())->withShortName('shortName')->withNormalizationContext(['groups' => [$collectionSerializationGroup]]),
])]);
$this->typesContainerProphecy->has($shortName)->shouldBeCalled()->willReturn(false);
$this->typesContainerProphecy->set($shortName, Argument::type(ObjectType::class))->shouldBeCalled();
@@ -138,7 +142,7 @@ public function testGetResourceObjectTypeQuerySerializationGroups(string $itemSe
$this->typesContainerProphecy->set('Node', Argument::type(InterfaceType::class))->shouldBeCalled();
/** @var ObjectType $resourceObjectType */
- $resourceObjectType = $this->typeBuilder->getResourceObjectType('resourceClass', $resourceMetadata, $queryName, false);
+ $resourceObjectType = $this->typeBuilder->getResourceObjectType('resourceClass', $resourceMetadata, $operation, false);
$this->assertSame($shortName, $resourceObjectType->name);
}
@@ -148,34 +152,35 @@ public function resourceObjectTypeQuerySerializationGroupsProvider(): array
'same serialization groups for item_query and collection_query' => [
'group',
'group',
+ (new Query())->withShortName('shortName')->withNormalizationContext(['groups' => ['group']]),
'shortName',
- 'item_query',
],
'different serialization groups for item_query and collection_query when using item_query' => [
'item_group',
'collection_group',
+ (new Query())->withShortName('shortName')->withNormalizationContext(['groups' => ['item_group']]),
'shortNameItem',
- 'item_query',
],
'different serialization groups for item_query and collection_query when using collection_query' => [
'item_group',
'collection_group',
+ (new QueryCollection())->withName('collection_query')->withShortName('shortName')->withNormalizationContext(['groups' => ['collection_group']]),
'shortNameCollection',
- 'collection_query',
],
];
}
public function testGetResourceObjectTypeInput(): void
{
- $resourceMetadata = new ResourceMetadataCollection('resourceClass', [(new ApiResource())->withGraphQlOperations(['custom' => (new Mutation())->withShortName('shortName')->withDescription('description')])]);
+ $resourceMetadata = new ResourceMetadataCollection('resourceClass', []);
$this->typesContainerProphecy->has('customShortNameInput')->shouldBeCalled()->willReturn(false);
$this->typesContainerProphecy->set('customShortNameInput', Argument::type(NonNull::class))->shouldBeCalled();
$this->typesContainerProphecy->has('Node')->shouldBeCalled()->willReturn(false);
$this->typesContainerProphecy->set('Node', Argument::type(InterfaceType::class))->shouldBeCalled();
+ $operation = (new Mutation())->withName('custom')->withShortName('shortName')->withDescription('description');
/** @var NonNull $resourceObjectType */
- $resourceObjectType = $this->typeBuilder->getResourceObjectType('resourceClass', $resourceMetadata, 'custom', true);
+ $resourceObjectType = $this->typeBuilder->getResourceObjectType('resourceClass', $resourceMetadata, $operation, true);
/** @var InputObjectType $wrappedType */
$wrappedType = $resourceObjectType->getWrappedType();
$this->assertInstanceOf(InputObjectType::class, $wrappedType);
@@ -185,21 +190,47 @@ public function testGetResourceObjectTypeInput(): void
$this->assertArrayHasKey('fields', $wrappedType->config);
$fieldsBuilderProphecy = $this->prophesize(FieldsBuilderInterface::class);
- $fieldsBuilderProphecy->getResourceObjectTypeFields('resourceClass', $resourceMetadata->getGraphQlOperation('custom'), true, 'custom', 0, null)->shouldBeCalled();
+ $fieldsBuilderProphecy->getResourceObjectTypeFields('resourceClass', $operation, true, 0, null)->shouldBeCalled();
+ $this->fieldsBuilderLocatorProphecy->get('api_platform.graphql.fields_builder')->shouldBeCalled()->willReturn($fieldsBuilderProphecy->reveal());
+ $wrappedType->config['fields']();
+ }
+
+ public function testGetResourceObjectTypeNestedInput(): void
+ {
+ $resourceMetadata = new ResourceMetadataCollection('resourceClass', []);
+ $this->typesContainerProphecy->has('customShortNameNestedInput')->shouldBeCalled()->willReturn(false);
+ $this->typesContainerProphecy->set('customShortNameNestedInput', Argument::type(NonNull::class))->shouldBeCalled();
+ $this->typesContainerProphecy->has('Node')->shouldBeCalled()->willReturn(false);
+ $this->typesContainerProphecy->set('Node', Argument::type(InterfaceType::class))->shouldBeCalled();
+
+ $operation = (new Mutation())->withName('custom')->withShortName('shortName')->withDescription('description');
+ /** @var NonNull $resourceObjectType */
+ $resourceObjectType = $this->typeBuilder->getResourceObjectType('resourceClass', $resourceMetadata, $operation, true, false, 1);
+ /** @var InputObjectType $wrappedType */
+ $wrappedType = $resourceObjectType->getWrappedType();
+ $this->assertInstanceOf(InputObjectType::class, $wrappedType);
+ $this->assertSame('customShortNameNestedInput', $wrappedType->name);
+ $this->assertSame('description', $wrappedType->description);
+ $this->assertArrayHasKey('interfaces', $wrappedType->config);
+ $this->assertArrayHasKey('fields', $wrappedType->config);
+
+ $fieldsBuilderProphecy = $this->prophesize(FieldsBuilderInterface::class);
+ $fieldsBuilderProphecy->getResourceObjectTypeFields('resourceClass', $operation, true, 1, null)->shouldBeCalled();
$this->fieldsBuilderLocatorProphecy->get('api_platform.graphql.fields_builder')->shouldBeCalled()->willReturn($fieldsBuilderProphecy->reveal());
$wrappedType->config['fields']();
}
public function testGetResourceObjectTypeCustomMutationInputArgs(): void
{
- $resourceMetadata = new ResourceMetadataCollection('resourceClass', [(new ApiResource())->withGraphQlOperations(['custom' => (new Mutation())->withShortName('shortName')->withDescription('description')->withArgs([])])]);
+ $resourceMetadata = new ResourceMetadataCollection('resourceClass', []);
$this->typesContainerProphecy->has('customShortNameInput')->shouldBeCalled()->willReturn(false);
$this->typesContainerProphecy->set('customShortNameInput', Argument::type(NonNull::class))->shouldBeCalled();
$this->typesContainerProphecy->has('Node')->shouldBeCalled()->willReturn(false);
$this->typesContainerProphecy->set('Node', Argument::type(InterfaceType::class))->shouldBeCalled();
+ $operation = (new Mutation())->withName('custom')->withShortName('shortName')->withDescription('description')->withArgs([]);
/** @var NonNull $resourceObjectType */
- $resourceObjectType = $this->typeBuilder->getResourceObjectType('resourceClass', $resourceMetadata, 'custom', true);
+ $resourceObjectType = $this->typeBuilder->getResourceObjectType('resourceClass', $resourceMetadata, $operation, true);
/** @var InputObjectType $wrappedType */
$wrappedType = $resourceObjectType->getWrappedType();
$this->assertInstanceOf(InputObjectType::class, $wrappedType);
@@ -209,9 +240,9 @@ public function testGetResourceObjectTypeCustomMutationInputArgs(): void
$this->assertArrayHasKey('fields', $wrappedType->config);
$fieldsBuilderProphecy = $this->prophesize(FieldsBuilderInterface::class);
- $fieldsBuilderProphecy->getResourceObjectTypeFields('resourceClass', $resourceMetadata->getGraphQlOperation('custom'), true, 'custom', 0, null)
+ $fieldsBuilderProphecy->getResourceObjectTypeFields('resourceClass', $operation, true, 0, null)
->shouldBeCalled()->willReturn(['clientMutationId' => GraphQLType::string()]);
- $fieldsBuilderProphecy->resolveResourceArgs([], 'custom', 'shortName')->shouldBeCalled();
+ $fieldsBuilderProphecy->resolveResourceArgs([], $operation)->shouldBeCalled();
$this->fieldsBuilderLocatorProphecy->get('api_platform.graphql.fields_builder')->shouldBeCalled()->willReturn($fieldsBuilderProphecy->reveal());
$wrappedType->config['fields']();
}
@@ -219,7 +250,7 @@ public function testGetResourceObjectTypeCustomMutationInputArgs(): void
public function testGetResourceObjectTypeMutation(): void
{
$resourceMetadata = new ResourceMetadataCollection('resourceClass', [(new ApiResource())->withGraphQlOperations([
- 'create' => (new Mutation())->withShortName('shortName')->withDescription('description'),
+ 'create' => (new Mutation())->withName('create')->withShortName('shortName')->withDescription('description'),
'item_query' => (new Query())->withShortName('shortName')->withDescription('description'),
]),
]);
@@ -228,8 +259,9 @@ public function testGetResourceObjectTypeMutation(): void
$this->typesContainerProphecy->has('Node')->shouldBeCalled()->willReturn(false);
$this->typesContainerProphecy->set('Node', Argument::type(InterfaceType::class))->shouldBeCalled();
+ $operation = (new Mutation())->withName('create')->withShortName('shortName')->withDescription('description');
/** @var ObjectType $resourceObjectType */
- $resourceObjectType = $this->typeBuilder->getResourceObjectType('resourceClass', $resourceMetadata, 'create', false);
+ $resourceObjectType = $this->typeBuilder->getResourceObjectType('resourceClass', $resourceMetadata, $operation, false);
$this->assertSame('createShortNamePayload', $resourceObjectType->name);
$this->assertSame('description', $resourceObjectType->description);
$this->assertSame($this->defaultFieldResolver, $resourceObjectType->resolveFieldFn);
@@ -251,15 +283,16 @@ public function testGetResourceObjectTypeMutationWrappedType(): void
{
$resourceMetadata = new ResourceMetadataCollection('resourceClass', [(new ApiResource())->withGraphQlOperations([
'item_query' => (new Query())->withShortName('shortName')->withDescription('description')->withNormalizationContext(['groups' => ['item_query']]),
- 'create' => (new Mutation())->withShortName('shortName')->withDescription('description')->withNormalizationContext(['groups' => ['create']]),
+ 'create' => (new Mutation())->withName('create')->withShortName('shortName')->withDescription('description')->withNormalizationContext(['groups' => ['create']]),
])]);
$this->typesContainerProphecy->has('createShortNamePayload')->shouldBeCalled()->willReturn(false);
$this->typesContainerProphecy->set('createShortNamePayload', Argument::type(ObjectType::class))->shouldBeCalled();
$this->typesContainerProphecy->has('Node')->shouldBeCalled()->willReturn(false);
$this->typesContainerProphecy->set('Node', Argument::type(InterfaceType::class))->shouldBeCalled();
+ $operation = (new Mutation())->withName('create')->withShortName('shortName')->withDescription('description')->withNormalizationContext(['groups' => ['create']]);
/** @var ObjectType $resourceObjectType */
- $resourceObjectType = $this->typeBuilder->getResourceObjectType('resourceClass', $resourceMetadata, 'create', false);
+ $resourceObjectType = $this->typeBuilder->getResourceObjectType('resourceClass', $resourceMetadata, $operation, false);
$this->assertSame('createShortNamePayload', $resourceObjectType->name);
$this->assertSame('description', $resourceObjectType->description);
$this->assertSame($this->defaultFieldResolver, $resourceObjectType->resolveFieldFn);
@@ -285,21 +318,22 @@ public function testGetResourceObjectTypeMutationWrappedType(): void
$this->assertArrayHasKey('fields', $wrappedType->config);
$fieldsBuilderProphecy = $this->prophesize(FieldsBuilderInterface::class);
- $fieldsBuilderProphecy->getResourceObjectTypeFields('resourceClass', $resourceMetadata->getGraphQlOperation('create'), false, 'create', 0, null)->shouldBeCalled();
+ $fieldsBuilderProphecy->getResourceObjectTypeFields('resourceClass', $operation, false, 0, null)->shouldBeCalled();
$this->fieldsBuilderLocatorProphecy->get('api_platform.graphql.fields_builder')->shouldBeCalled()->willReturn($fieldsBuilderProphecy->reveal());
$wrappedType->config['fields']();
}
public function testGetResourceObjectTypeMutationNested(): void
{
- $resourceMetadata = new ResourceMetadataCollection('resourceClass', [(new ApiResource())->withGraphQlOperations(['create' => (new Mutation())->withShortName('shortName')->withDescription('description')])]);
+ $resourceMetadata = new ResourceMetadataCollection('resourceClass', []);
$this->typesContainerProphecy->has('createShortNameNestedPayload')->shouldBeCalled()->willReturn(false);
$this->typesContainerProphecy->set('createShortNameNestedPayload', Argument::type(ObjectType::class))->shouldBeCalled();
$this->typesContainerProphecy->has('Node')->shouldBeCalled()->willReturn(false);
$this->typesContainerProphecy->set('Node', Argument::type(InterfaceType::class))->shouldBeCalled();
+ $operation = (new Mutation())->withName('create')->withShortName('shortName')->withDescription('description');
/** @var ObjectType $resourceObjectType */
- $resourceObjectType = $this->typeBuilder->getResourceObjectType('resourceClass', $resourceMetadata, 'create', false, false, 1);
+ $resourceObjectType = $this->typeBuilder->getResourceObjectType('resourceClass', $resourceMetadata, $operation, false, false, 1);
$this->assertSame('createShortNameNestedPayload', $resourceObjectType->name);
$this->assertSame('description', $resourceObjectType->description);
$this->assertSame($this->defaultFieldResolver, $resourceObjectType->resolveFieldFn);
@@ -307,7 +341,7 @@ public function testGetResourceObjectTypeMutationNested(): void
$this->assertArrayHasKey('fields', $resourceObjectType->config);
$fieldsBuilderProphecy = $this->prophesize(FieldsBuilderInterface::class);
- $fieldsBuilderProphecy->getResourceObjectTypeFields('resourceClass', $resourceMetadata->getGraphQlOperation('create'), false, 'create', 1, null)->shouldBeCalled();
+ $fieldsBuilderProphecy->getResourceObjectTypeFields('resourceClass', $operation, false, 1, null)->shouldBeCalled();
$this->fieldsBuilderLocatorProphecy->get('api_platform.graphql.fields_builder')->shouldBeCalled()->willReturn($fieldsBuilderProphecy->reveal());
$resourceObjectType->config['fields']();
}
@@ -315,7 +349,7 @@ public function testGetResourceObjectTypeMutationNested(): void
public function testGetResourceObjectTypeSubscription(): void
{
$resourceMetadata = new ResourceMetadataCollection('resourceClass', [(new ApiResource())->withGraphQlOperations([
- 'update' => (new Subscription())->withShortName('shortName')->withDescription('description')->withMercure(true),
+ 'update' => (new Subscription())->withName('update')->withShortName('shortName')->withDescription('description')->withMercure(true),
'item_query' => (new Query())->withShortName('shortName')->withDescription('description'),
]),
]);
@@ -324,8 +358,9 @@ public function testGetResourceObjectTypeSubscription(): void
$this->typesContainerProphecy->has('Node')->shouldBeCalled()->willReturn(false);
$this->typesContainerProphecy->set('Node', Argument::type(InterfaceType::class))->shouldBeCalled();
+ $operation = (new Subscription())->withName('update')->withShortName('shortName')->withDescription('description')->withMercure(true);
/** @var ObjectType $resourceObjectType */
- $resourceObjectType = $this->typeBuilder->getResourceObjectType('resourceClass', $resourceMetadata, 'update', false);
+ $resourceObjectType = $this->typeBuilder->getResourceObjectType('resourceClass', $resourceMetadata, $operation, false);
$this->assertSame('updateShortNameSubscriptionPayload', $resourceObjectType->name);
$this->assertSame('description', $resourceObjectType->description);
$this->assertSame($this->defaultFieldResolver, $resourceObjectType->resolveFieldFn);
@@ -349,15 +384,16 @@ public function testGetResourceObjectTypeSubscriptionWrappedType(): void
{
$resourceMetadata = new ResourceMetadataCollection('resourceClass', [(new ApiResource())->withGraphQlOperations([
'item_query' => (new Query())->withShortName('shortName')->withDescription('description')->withNormalizationContext(['groups' => ['item_query']]),
- 'update' => (new Subscription())->withShortName('shortName')->withDescription('description')->withNormalizationContext(['groups' => ['update']]),
+ 'update' => (new Subscription())->withName('update')->withShortName('shortName')->withDescription('description')->withNormalizationContext(['groups' => ['update']]),
])]);
$this->typesContainerProphecy->has('updateShortNameSubscriptionPayload')->shouldBeCalled()->willReturn(false);
$this->typesContainerProphecy->set('updateShortNameSubscriptionPayload', Argument::type(ObjectType::class))->shouldBeCalled();
$this->typesContainerProphecy->has('Node')->shouldBeCalled()->willReturn(false);
$this->typesContainerProphecy->set('Node', Argument::type(InterfaceType::class))->shouldBeCalled();
+ $operation = (new Subscription())->withName('update')->withShortName('shortName')->withDescription('description')->withNormalizationContext(['groups' => ['update']]);
/** @var ObjectType $resourceObjectType */
- $resourceObjectType = $this->typeBuilder->getResourceObjectType('resourceClass', $resourceMetadata, 'update', false);
+ $resourceObjectType = $this->typeBuilder->getResourceObjectType('resourceClass', $resourceMetadata, $operation, false);
$this->assertSame('updateShortNameSubscriptionPayload', $resourceObjectType->name);
$this->assertSame('description', $resourceObjectType->description);
$this->assertSame($this->defaultFieldResolver, $resourceObjectType->resolveFieldFn);
@@ -384,21 +420,22 @@ public function testGetResourceObjectTypeSubscriptionWrappedType(): void
$this->assertArrayHasKey('fields', $wrappedType->config);
$fieldsBuilderProphecy = $this->prophesize(FieldsBuilderInterface::class);
- $fieldsBuilderProphecy->getResourceObjectTypeFields('resourceClass', $resourceMetadata->getGraphQlOperation('update'), false, 'update', 0, null)->shouldBeCalled();
+ $fieldsBuilderProphecy->getResourceObjectTypeFields('resourceClass', $operation, false, 0, null)->shouldBeCalled();
$this->fieldsBuilderLocatorProphecy->get('api_platform.graphql.fields_builder')->shouldBeCalled()->willReturn($fieldsBuilderProphecy->reveal());
$wrappedType->config['fields']();
}
public function testGetResourceObjectTypeSubscriptionNested(): void
{
- $resourceMetadata = new ResourceMetadataCollection('resourceClass', [(new ApiResource())->withGraphQlOperations(['update' => (new Subscription())->withShortName('shortName')->withDescription('description')->withMercure(true)])]);
+ $resourceMetadata = new ResourceMetadataCollection('resourceClass', [(new ApiResource())->withGraphQlOperations([])]);
$this->typesContainerProphecy->has('updateShortNameSubscriptionNestedPayload')->shouldBeCalled()->willReturn(false);
$this->typesContainerProphecy->set('updateShortNameSubscriptionNestedPayload', Argument::type(ObjectType::class))->shouldBeCalled();
$this->typesContainerProphecy->has('Node')->shouldBeCalled()->willReturn(false);
$this->typesContainerProphecy->set('Node', Argument::type(InterfaceType::class))->shouldBeCalled();
+ $operation = (new Subscription())->withName('update')->withShortName('shortName')->withDescription('description')->withMercure(true);
/** @var ObjectType $resourceObjectType */
- $resourceObjectType = $this->typeBuilder->getResourceObjectType('resourceClass', $resourceMetadata, 'update', false, false, 1);
+ $resourceObjectType = $this->typeBuilder->getResourceObjectType('resourceClass', $resourceMetadata, $operation, false, false, 1);
$this->assertSame('updateShortNameSubscriptionNestedPayload', $resourceObjectType->name);
$this->assertSame('description', $resourceObjectType->description);
$this->assertSame($this->defaultFieldResolver, $resourceObjectType->resolveFieldFn);
@@ -406,7 +443,7 @@ public function testGetResourceObjectTypeSubscriptionNested(): void
$this->assertArrayHasKey('fields', $resourceObjectType->config);
$fieldsBuilderProphecy = $this->prophesize(FieldsBuilderInterface::class);
- $fieldsBuilderProphecy->getResourceObjectTypeFields('resourceClass', $resourceMetadata->getGraphQlOperation('update'), false, 'update', 1, null)->shouldBeCalled();
+ $fieldsBuilderProphecy->getResourceObjectTypeFields('resourceClass', $operation, false, 1, null)->shouldBeCalled();
$this->fieldsBuilderLocatorProphecy->get('api_platform.graphql.fields_builder')->shouldBeCalled()->willReturn($fieldsBuilderProphecy->reveal());
$resourceObjectType->config['fields']();
}
diff --git a/tests/GraphQl/Type/TypeConverterTest.php b/tests/GraphQl/Type/TypeConverterTest.php
index 7950525d650..df08e0d5611 100644
--- a/tests/GraphQl/Type/TypeConverterTest.php
+++ b/tests/GraphQl/Type/TypeConverterTest.php
@@ -13,19 +13,23 @@
namespace ApiPlatform\Core\Tests\GraphQl\Type;
+use ApiPlatform\Core\Metadata\Property\PropertyMetadata;
use ApiPlatform\Core\Tests\ProphecyTrait;
use ApiPlatform\Exception\ResourceClassNotFoundException;
use ApiPlatform\GraphQl\Type\TypeBuilderInterface;
use ApiPlatform\GraphQl\Type\TypeConverter;
use ApiPlatform\GraphQl\Type\TypesContainerInterface;
use ApiPlatform\Metadata\ApiResource;
+use ApiPlatform\Metadata\GraphQl\Operation;
use ApiPlatform\Metadata\GraphQl\Query;
+use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
use ApiPlatform\Metadata\Resource\ResourceMetadataCollection;
use ApiPlatform\Tests\Fixtures\TestBundle\GraphQl\Type\Definition\DateTimeType;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type as GraphQLType;
use PHPUnit\Framework\TestCase;
+use Prophecy\Argument;
use Prophecy\Prophecy\ObjectProphecy;
use Symfony\Component\PropertyInfo\Type;
@@ -45,6 +49,9 @@ class TypeConverterTest extends TestCase
/** @var ObjectProphecy */
private $resourceMetadataCollectionFactoryProphecy;
+ /** @var ObjectProphecy */
+ private $propertyMetadataFactoryProphecy;
+
/** @var TypeConverter */
private $typeConverter;
@@ -56,7 +63,8 @@ protected function setUp(): void
$this->typeBuilderProphecy = $this->prophesize(TypeBuilderInterface::class);
$this->typesContainerProphecy = $this->prophesize(TypesContainerInterface::class);
$this->resourceMetadataCollectionFactoryProphecy = $this->prophesize(ResourceMetadataCollectionFactoryInterface::class);
- $this->typeConverter = new TypeConverter($this->typeBuilderProphecy->reveal(), $this->typesContainerProphecy->reveal(), $this->resourceMetadataCollectionFactoryProphecy->reveal());
+ $this->propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
+ $this->typeConverter = new TypeConverter($this->typeBuilderProphecy->reveal(), $this->typesContainerProphecy->reveal(), $this->resourceMetadataCollectionFactoryProphecy->reveal(), $this->propertyMetadataFactoryProphecy->reveal());
}
/**
@@ -68,7 +76,7 @@ public function testConvertType(Type $type, bool $input, int $depth, $expectedGr
{
$this->typeBuilderProphecy->isCollection($type)->willReturn(false);
- $graphqlType = $this->typeConverter->convertType($type, $input, 'test', 'resourceClass', 'rootClass', null, $depth);
+ $graphqlType = $this->typeConverter->convertType($type, $input, (new Operation())->withName('test'), 'resourceClass', 'rootClass', null, $depth);
$this->assertEquals($expectedGraphqlType, $graphqlType);
}
@@ -81,7 +89,6 @@ public function convertTypeProvider(): array
[new Type(Type::BUILTIN_TYPE_STRING), false, 0, GraphQLType::string()],
[new Type(Type::BUILTIN_TYPE_ARRAY), false, 0, 'Iterable'],
[new Type(Type::BUILTIN_TYPE_ITERABLE), false, 0, 'Iterable'],
- [new Type(Type::BUILTIN_TYPE_OBJECT), true, 1, GraphQLType::string()],
[new Type(Type::BUILTIN_TYPE_OBJECT, false, \DateTimeInterface::class), false, 0, GraphQLType::string()],
[new Type(Type::BUILTIN_TYPE_OBJECT), false, 0, null],
[new Type(Type::BUILTIN_TYPE_CALLABLE), false, 0, null],
@@ -97,7 +104,7 @@ public function testConvertTypeNoGraphQlResourceMetadata(): void
$this->typeBuilderProphecy->isCollection($type)->shouldBeCalled()->willReturn(false);
$this->resourceMetadataCollectionFactoryProphecy->create('dummy')->shouldBeCalled()->willReturn(new ResourceMetadataCollection('dummy', [new ApiResource()]));
- $graphqlType = $this->typeConverter->convertType($type, false, 'test', 'resourceClass', 'rootClass', null, 0);
+ $graphqlType = $this->typeConverter->convertType($type, false, (new Operation())->withName('test'), 'resourceClass', 'rootClass', null, 0);
$this->assertNull($graphqlType);
}
@@ -111,7 +118,7 @@ public function testConvertTypeNodeResource(): void
$this->expectException(\UnexpectedValueException::class);
$this->expectExceptionMessage('A "Node" resource cannot be used with GraphQL because the type is already used by the Relay specification.');
- $this->typeConverter->convertType($type, false, 'test', 'resourceClass', 'rootClass', null, 0);
+ $this->typeConverter->convertType($type, false, (new Operation())->withName('test'), 'resourceClass', 'rootClass', null, 0);
}
public function testConvertTypeResourceClassNotFound(): void
@@ -121,22 +128,52 @@ public function testConvertTypeResourceClassNotFound(): void
$this->typeBuilderProphecy->isCollection($type)->shouldBeCalled()->willReturn(false);
$this->resourceMetadataCollectionFactoryProphecy->create('dummy')->shouldBeCalled()->willThrow(new ResourceClassNotFoundException());
- $graphqlType = $this->typeConverter->convertType($type, false, 'test', 'resourceClass', 'rootClass', null, 0);
+ $graphqlType = $this->typeConverter->convertType($type, false, (new Operation())->withName('test'), 'resourceClass', 'rootClass', null, 0);
$this->assertNull($graphqlType);
}
+ public function testConvertTypeResourceIri(): void
+ {
+ $type = new Type(Type::BUILTIN_TYPE_OBJECT, false, 'dummy');
+
+ $graphqlResourceMetadata = new ResourceMetadataCollection('dummy', [(new ApiResource())->withGraphQlOperations(['test' => new Query()])]);
+ $this->resourceMetadataCollectionFactoryProphecy->create('dummy')->willReturn($graphqlResourceMetadata);
+ $this->typeBuilderProphecy->isCollection($type)->willReturn(false);
+ $this->propertyMetadataFactoryProphecy->create('rootClass', 'dummyProperty', Argument::type('array'))->shouldBeCalled()->willReturn((new PropertyMetadata())->withWritableLink(false));
+
+ $graphqlType = $this->typeConverter->convertType($type, true, (new Operation())->withName('test'), 'dummy', 'rootClass', 'dummyProperty', 1);
+ $this->assertEquals(GraphQLType::string(), $graphqlType);
+ }
+
+ public function testConvertTypeInputResource(): void
+ {
+ $type = new Type(Type::BUILTIN_TYPE_OBJECT, false, 'dummy');
+ $operation = new Query();
+ $graphqlResourceMetadata = new ResourceMetadataCollection('dummy', [(new ApiResource())->withGraphQlOperations(['test' => $operation])]);
+ $expectedGraphqlType = new ObjectType(['name' => 'resourceObjectType']);
+
+ $this->resourceMetadataCollectionFactoryProphecy->create('dummy')->willReturn($graphqlResourceMetadata);
+ $this->typeBuilderProphecy->isCollection($type)->willReturn(false);
+ $this->propertyMetadataFactoryProphecy->create('rootClass', 'dummyProperty', Argument::type('array'))->shouldBeCalled()->willReturn((new PropertyMetadata())->withWritableLink(true));
+ $this->typeBuilderProphecy->getResourceObjectType('dummy', $graphqlResourceMetadata, $operation, true, false, 1)->shouldBeCalled()->willReturn($expectedGraphqlType);
+
+ $graphqlType = $this->typeConverter->convertType($type, true, (new Operation())->withName('test'), 'dummy', 'rootClass', 'dummyProperty', 1);
+ $this->assertEquals($expectedGraphqlType, $graphqlType);
+ }
+
/**
* @dataProvider convertTypeResourceProvider
*/
- public function testConvertTypeResource(Type $type, ObjectType $expectedGraphqlType): void
+ public function testConvertTypeCollectionResource(Type $type, ObjectType $expectedGraphqlType): void
{
- $graphqlResourceMetadata = new ResourceMetadataCollection('dummyValue', [(new ApiResource())->withShortName('DummyValue')->withGraphQlOperations(['test' => new Query()])]);
+ $operation = (new Query())->withName('test');
+ $graphqlResourceMetadata = new ResourceMetadataCollection('dummyValue', [(new ApiResource())->withShortName('DummyValue')->withGraphQlOperations(['test' => $operation])]);
$this->typeBuilderProphecy->isCollection($type)->shouldBeCalled()->willReturn(true);
$this->resourceMetadataCollectionFactoryProphecy->create('dummyValue')->shouldBeCalled()->willReturn($graphqlResourceMetadata);
- $this->typeBuilderProphecy->getResourceObjectType('dummyValue', $graphqlResourceMetadata, 'test', false, false, 0)->shouldBeCalled()->willReturn($expectedGraphqlType);
+ $this->typeBuilderProphecy->getResourceObjectType('dummyValue', $graphqlResourceMetadata, $operation, false, false, 0)->shouldBeCalled()->willReturn($expectedGraphqlType);
- $graphqlType = $this->typeConverter->convertType($type, false, 'test', 'resourceClass', 'rootClass', null, 0);
+ $graphqlType = $this->typeConverter->convertType($type, false, (new Operation())->withName('test'), 'resourceClass', 'rootClass', null, 0);
$this->assertEquals($expectedGraphqlType, $graphqlType);
}