-
Notifications
You must be signed in to change notification settings - Fork 637
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[5.x]: GraphQL type name conflict when overriding Matrix field handle #16020
Comments
I am not sure if it's the same issue, but #15708 is reporting a similar error message. |
@brandonkelly as this issue is blocking us going forward with a current project it would be great to hear if this problem is something that can be addressed or if we should apply workaround (ex. not to use same handles for different matrix fields). |
@denisyilmaz Yeah there have always been some gotchas with GraphQL when multiple fields have the same handle. Your best bet is to choose unique names. |
@brandonkelly thanks for the info. So this will not be addressed any time soon? What about the suggested solution we provided:
|
Field IDs will change from environment to environment, and can’t change the GraphQL names without breaking every existing GraphQL implementation. You can get the original handle via |
@brandonkelly Thanks, while this is actually helping in not throwing an error, it still does not return the corresponding field values: /**
* @inheritdoc
* @since 3.3.0
*/
public function getContentGqlType(): Type|array
{
$typeArray = EntryTypeGenerator::generateTypes($this);
$typeName = $this->layoutElement?->getOriginalHandle() . '_MatrixField';
return [
'name' => $this->handle,
'type' => Type::nonNull(Type::listOf(Gql::getUnionType($typeName, $typeArray))),
'args' => EntryArguments::getArguments(),
'resolve' => EntryResolver::class . '::resolve',
'complexity' => Gql::eagerLoadComplexity(),
];
} in so we will not use overlapping field handles for now. Still, this feature (renaming field names) is great and we would love to see it working globally with GraphQL.. Hope this is possible somewhere in the future. |
What happened?
Description
If two entry types use two different matrix fields, which support different entry-types, but use the same handle for these matrix fields, GraphQL throws an error indicating the nested entry types are not available for the matrix field.
It seems like the Matrix field uses the overridden handle to generate it's GraphQL content type name, and that creates a conflict meaning that the schema is missing some types.
Steps to reproduce
I have quickly setup a small Craft-CMS project repository which you can clone, with a simple project config that reproduces the error (steps 1 to 8 below). To recreate the issue in another Craft-CMS project, setup the following project config:
textBlock
)imageBlock
)galleryBlock
)simpleBodyBlocks
) with support for the following nested entry-types:textBlock
)imageBlock
)bodyBlocks
.complexBodyBlocks
) with support for the following nested entry-types:textBlock
)imageBlock
)galleryBlock
)bodyBlocks
.Once you have the project config setup:
bodyBlocks
field.bodyBlocks
field.Expected behavior
The GraphQL API should return the data for the two entries and the nested entries created in their matrix field (steps 9-11):
See Data
Actual behavior
The GraphQL API returns the following error data:
See Data
```json { "errors": [ { "message": "Fragment cannot be spread here as objects of type \"bodyBlocks_MatrixField\" can never be of type \"galleryBlock_Entry\".", "extensions": { "category": "graphql" }, "locations": [ { "line": 32, "column": 9 } ] } ] } ```If we remove the
... on galleryBlock_Entry {}
fragment from the GraphQL query, another error is returned and thegalleryBlock
entry is missing from the data:See Data
```json { "errors": [ { "debugMessage": "Runtime Object type \"galleryBlock_Entry\" is not a possible type for \"bodyBlocks_MatrixField\".", "message": "Internal server error", "extensions": { "category": "internal" }, "trace": [ { "file": "/var/www/html/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php", "line": 974, "call": "GraphQL\\Executor\\ReferenceExecutor::ensureValidRuntimeType('galleryBlock_Entry', GraphQLType: bodyBlocks_MatrixField, instance of GraphQL\\Type\\Definition\\ResolveInfo, instance of craft\\elements\\Entry)" }, { "file": "/var/www/html/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php", "line": 789, "call": "GraphQL\\Executor\\ReferenceExecutor::completeAbstractValue(GraphQLType: bodyBlocks_MatrixField, instance of ArrayObject(1), instance of GraphQL\\Type\\Definition\\ResolveInfo, array(4), instance of craft\\elements\\Entry)" }, { "file": "/var/www/html/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php", "line": 654, "call": "GraphQL\\Executor\\ReferenceExecutor::completeValue(GraphQLType: bodyBlocks_MatrixField, instance of ArrayObject(1), instance of GraphQL\\Type\\Definition\\ResolveInfo, array(4), instance of craft\\elements\\Entry)" }, { "file": "/var/www/html/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php", "line": 887, "call": "GraphQL\\Executor\\ReferenceExecutor::completeValueCatchingError(GraphQLType: bodyBlocks_MatrixField, instance of ArrayObject(1), instance of GraphQL\\Type\\Definition\\ResolveInfo, array(4), instance of craft\\elements\\Entry)" }, { "file": "/var/www/html/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php", "line": 761, "call": "GraphQL\\Executor\\ReferenceExecutor::completeListValue(GraphQLType: bodyBlocks_MatrixField, instance of ArrayObject(1), instance of GraphQL\\Type\\Definition\\ResolveInfo, array(3), array(3))" }, { "file": "/var/www/html/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php", "line": 740, "call": "GraphQL\\Executor\\ReferenceExecutor::completeValue(GraphQLType: bodyBlocks_MatrixField, instance of ArrayObject(1), instance of GraphQL\\Type\\Definition\\ResolveInfo, array(3), array(3))" }, { "file": "/var/www/html/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php", "line": 654, "call": "GraphQL\\Executor\\ReferenceExecutor::completeValue(GraphQLType: bodyBlocks_MatrixField, instance of ArrayObject(1), instance of GraphQL\\Type\\Definition\\ResolveInfo, array(3), array(3))" }, { "file": "/var/www/html/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php", "line": 556, "call": "GraphQL\\Executor\\ReferenceExecutor::completeValueCatchingError(GraphQLType: bodyBlocks_MatrixField, instance of ArrayObject(1), instance of GraphQL\\Type\\Definition\\ResolveInfo, array(3), array(3))" }, { "file": "/var/www/html/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php", "line": 1195, "call": "GraphQL\\Executor\\ReferenceExecutor::resolveField(GraphQLType: complexPage_Entry, instance of craft\\elements\\Entry, instance of ArrayObject(1), array(3))" }, { "file": "/var/www/html/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php", "line": 1145, "call": "GraphQL\\Executor\\ReferenceExecutor::executeFields(GraphQLType: complexPage_Entry, instance of craft\\elements\\Entry, array(2), instance of ArrayObject(1))" }, { "file": "/var/www/html/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php", "line": 1105, "call": "GraphQL\\Executor\\ReferenceExecutor::collectAndExecuteSubfields(GraphQLType: complexPage_Entry, instance of ArrayObject(1), array(2), instance of craft\\elements\\Entry)" }, { "file": "/var/www/html/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php", "line": 973, "call": "GraphQL\\Executor\\ReferenceExecutor::completeObjectValue(GraphQLType: complexPage_Entry, instance of ArrayObject(1), instance of GraphQL\\Type\\Definition\\ResolveInfo, array(2), instance of craft\\elements\\Entry)" }, { "file": "/var/www/html/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php", "line": 789, "call": "GraphQL\\Executor\\ReferenceExecutor::completeAbstractValue(GraphQLType: pagesSectionEntryUnion, instance of ArrayObject(1), instance of GraphQL\\Type\\Definition\\ResolveInfo, array(2), instance of craft\\elements\\Entry)" }, { "file": "/var/www/html/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php", "line": 654, "call": "GraphQL\\Executor\\ReferenceExecutor::completeValue(GraphQLType: pagesSectionEntryUnion, instance of ArrayObject(1), instance of GraphQL\\Type\\Definition\\ResolveInfo, array(2), instance of craft\\elements\\Entry)" }, { "file": "/var/www/html/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php", "line": 887, "call": "GraphQL\\Executor\\ReferenceExecutor::completeValueCatchingError(GraphQLType: pagesSectionEntryUnion, instance of ArrayObject(1), instance of GraphQL\\Type\\Definition\\ResolveInfo, array(2), instance of craft\\elements\\Entry)" }, { "file": "/var/www/html/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php", "line": 761, "call": "GraphQL\\Executor\\ReferenceExecutor::completeListValue(GraphQLType: pagesSectionEntryUnion, instance of ArrayObject(1), instance of GraphQL\\Type\\Definition\\ResolveInfo, array(1), array(2))" }, { "file": "/var/www/html/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php", "line": 654, "call": "GraphQL\\Executor\\ReferenceExecutor::completeValue(GraphQLType: pagesSectionEntryUnion, instance of ArrayObject(1), instance of GraphQL\\Type\\Definition\\ResolveInfo, array(1), array(2))" }, { "file": "/var/www/html/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php", "line": 556, "call": "GraphQL\\Executor\\ReferenceExecutor::completeValueCatchingError(GraphQLType: pagesSectionEntryUnion, instance of ArrayObject(1), instance of GraphQL\\Type\\Definition\\ResolveInfo, array(1), array(2))" }, { "file": "/var/www/html/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php", "line": 1195, "call": "GraphQL\\Executor\\ReferenceExecutor::resolveField(GraphQLType: Query, null, instance of ArrayObject(1), array(1))" }, { "file": "/var/www/html/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php", "line": 264, "call": "GraphQL\\Executor\\ReferenceExecutor::executeFields(GraphQLType: Query, null, array(0), instance of ArrayObject(1))" }, { "file": "/var/www/html/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php", "line": 215, "call": "GraphQL\\Executor\\ReferenceExecutor::executeOperation(instance of GraphQL\\Language\\AST\\OperationDefinitionNode, null)" }, { "file": "/var/www/html/vendor/webonyx/graphql-php/src/Executor/Executor.php", "line": 156, "call": "GraphQL\\Executor\\ReferenceExecutor::doExecute()" }, { "file": "/var/www/html/vendor/webonyx/graphql-php/src/GraphQL.php", "line": 161, "call": "GraphQL\\Executor\\Executor::promiseToExecute(instance of GraphQL\\Executor\\Promise\\Adapter\\SyncPromiseAdapter, instance of GraphQL\\Type\\Schema, instance of GraphQL\\Language\\AST\\DocumentNode, null, array(2), null, null, null)" }, { "file": "/var/www/html/vendor/webonyx/graphql-php/src/GraphQL.php", "line": 93, "call": "GraphQL\\GraphQL::promiseToExecute(instance of GraphQL\\Executor\\Promise\\Adapter\\SyncPromiseAdapter, instance of GraphQL\\Type\\Schema, 'query {\n pagesEntries {\n \n ... on simplePage_Entry { \n bodyBlocks {\n __typename\n ... on textBlock_Entry {\n id\n typeHandle\n title\n }\n ... on imageBlock_Entry {\n id\n typeHandle\n title\n }\n }\n }\n ... on complexPage_Entry {\n bodyBlocks {\n __typename\n ... on textBlock_Entry {\n id\n typeHandle\n title\n }\n ... on imageBlock_Entry {\n id\n typeHandle\n title\n }\n }\n }\n }\n}\n\n', null, array(2), null, null, null, array(26))" }, { "file": "/var/www/html/vendor/craftcms/cms/src/services/Gql.php", "line": 526, "call": "GraphQL\\GraphQL::executeQuery(instance of GraphQL\\Type\\Schema, 'query {\n pagesEntries {\n \n ... on simplePage_Entry { \n bodyBlocks {\n __typename\n ... on textBlock_Entry {\n id\n typeHandle\n title\n }\n ... on imageBlock_Entry {\n id\n typeHandle\n title\n }\n }\n }\n ... on complexPage_Entry {\n bodyBlocks {\n __typename\n ... on textBlock_Entry {\n id\n typeHandle\n title\n }\n ... on imageBlock_Entry {\n id\n typeHandle\n title\n }\n }\n }\n }\n}\n\n', null, array(2), null, null, null, array(26))" }, { "file": "/var/www/html/vendor/craftcms/cms/src/controllers/GraphqlController.php", "line": 195, "call": "craft\\services\\Gql::executeQuery(instance of craft\\models\\GqlSchema, 'query {\n pagesEntries {\n \n ... on simplePage_Entry { \n bodyBlocks {\n __typename\n ... on textBlock_Entry {\n id\n typeHandle\n title\n }\n ... on imageBlock_Entry {\n id\n typeHandle\n title\n }\n }\n }\n ... on complexPage_Entry {\n bodyBlocks {\n __typename\n ... on textBlock_Entry {\n id\n typeHandle\n title\n }\n ... on imageBlock_Entry {\n id\n typeHandle\n title\n }\n }\n }\n }\n}\n\n', null, null, true)" }, { "call": "craft\\controllers\\GraphqlController::actionApi()" }, { "file": "/var/www/html/vendor/yiisoft/yii2/base/InlineAction.php", "line": 57, "function": "call_user_func_array(array(2), array(0))" }, { "file": "/var/www/html/vendor/yiisoft/yii2/base/Controller.php", "line": 178, "call": "yii\\base\\InlineAction::runWithParams(array(1))" }, { "file": "/var/www/html/vendor/yiisoft/yii2/base/Module.php", "line": 552, "call": "yii\\base\\Controller::runAction('api', array(1))" }, { "file": "/var/www/html/vendor/craftcms/cms/src/web/Application.php", "line": 350, "call": "yii\\base\\Module::runAction('graphql/api', array(1))" }, { "file": "/var/www/html/vendor/craftcms/cms/src/web/Application.php", "line": 649, "call": "craft\\web\\Application::runAction('graphql/api', array(1))" }, { "file": "/var/www/html/vendor/craftcms/cms/src/web/Application.php", "line": 312, "call": "craft\\web\\Application::_processActionRequest(instance of craft\\web\\Request)" }, { "file": "/var/www/html/vendor/yiisoft/yii2/base/Application.php", "line": 384, "call": "craft\\web\\Application::handleRequest(instance of craft\\web\\Request)" }, { "file": "/var/www/html/web/index.php", "line": 12, "call": "yii\\base\\Application::run()" } ] } ], "data": { "pagesEntries": [ { "bodyBlocks": [ { "__typename": "textBlock_Entry", "id": "21", "typeHandle": "textBlock", "title": "Test Text (Simple)" }, { "__typename": "imageBlock_Entry", "id": "22", "typeHandle": "imageBlock", "title": "Test Image (Simple)" } ] }, { "bodyBlocks": [ { "__typename": "imageBlock_Entry", "id": "27", "typeHandle": "imageBlock", "title": "Test Image (Complex)" }, { "__typename": "textBlock_Entry", "id": "28", "typeHandle": "textBlock", "title": "Test Text (Complex)" }, null ] } ] } } ```Suggested Solution
We suspect the problem is that the Matrix field generates a type name based on its handle in the current field layout (i.e.
bodyBlocks
in the example setup above). This creates a conflict, and as a result only one of the two Matrix types exist in the GraphQL schema. This could be solved by using the original handle (the handle defined in the CP > Settings > Fields section) in the field'sgetContentGqlType()
method to avoid such conflicts.We could not try out this solution because –at the time when the
getContentGqlType()
method is called– the Matrix Field'shandle
property is set to the overridden handle, and there is nooriginalHandle
property. We quickly tested including the field'sid
in the type name, and –although we suspect that would introduce new problems– it did solve the issue.Craft CMS version
5.4.9
PHP version
8.2.22
Operating system and version
Linux 6.10.12-orbstack-00282-gd1783374c25e
Database type and version
MySQL 8.0.36
Image driver and version
Imagick 3.7.0 (ImageMagick 6.9.11-60)
Installed plugins and versions
(None)
The text was updated successfully, but these errors were encountered: