Skip to content
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

Fix AnnotationReader returning Input classes as Type classes. #532

Merged

Conversation

mdoelker
Copy link
Contributor

This fixes the issue described in #531 that would result in error "Cached type in registry is not the type returned by type mapper" when using Input types in mutations via variables.

@codecov-commenter
Copy link

Codecov Report

Base: 95.67% // Head: 95.77% // Increases project coverage by +0.09% 🎉

Coverage data is based on head (8cfaa6a) compared to base (4fdca6e).
Patch coverage: 100.00% of modified lines in pull request are covered.

Additional details and impacted files
@@             Coverage Diff              @@
##             master     #532      +/-   ##
============================================
+ Coverage     95.67%   95.77%   +0.09%     
  Complexity     1773     1773              
============================================
  Files           154      154              
  Lines          4279     4564     +285     
============================================
+ Hits           4094     4371     +277     
- Misses          185      193       +8     
Impacted Files Coverage Δ
src/AnnotationReader.php 95.89% <100.00%> (+1.39%) ⬆️
src/Annotations/Input.php 71.42% <0.00%> (-23.81%) ⬇️
src/FieldsBuilder.php 95.13% <0.00%> (-0.10%) ⬇️
src/Schema.php 100.00% <0.00%> (ø)
src/QueryField.php 100.00% <0.00%> (ø)
src/TypeRegistry.php 100.00% <0.00%> (ø)
src/TypeGenerator.php 100.00% <0.00%> (ø)
src/FactoryContext.php 100.00% <0.00%> (ø)
src/Types/EnumType.php 0.00% <0.00%> (ø)
src/Types/InputType.php 100.00% <0.00%> (ø)
... and 57 more

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report at Codecov.
📢 Do you have feedback about the report comment? Let us know in this issue.

@oojacoboo
Copy link
Collaborator

Thanks for the PR @mdoelker.

So, I think this change is needed, at least according to how it should probably be written. However, I tested your branch on our repo and it's actually failing.

It seems this method is being called on some Input annotated (attribute in our case) types: https://github.com/thecodingmachine/graphqlite/blob/master/src/TypeGenerator.php#L47

Here is the call stack:

TheCodingMachine\GraphQLite\MissingAnnotationException: GraphQL type class "Foo\Input" must provide a @Type annotation.

/srv/www/vendor/thecodingmachine/graphqlite/src/MissingAnnotationException.php:18
/srv/www/vendor/thecodingmachine/graphqlite/src/TypeGenerator.php:50
/srv/www/vendor/thecodingmachine/graphqlite/src/Mappers/AbstractTypeMapper.php:264
/srv/www/vendor/thecodingmachine/graphqlite/src/Mappers/CompositeTypeMapper.php:65
/srv/www/vendor/thecodingmachine/graphqlite/src/Mappers/RecursiveTypeMapper.php:300
/srv/www/vendor/thecodingmachine/graphqlite/src/Mappers/RecursiveTypeMapper.php:359
/srv/www/vendor/thecodingmachine/graphqlite/src/Mappers/Root/BaseTypeMapper.php:71
/srv/www/vendor/thecodingmachine/graphqlite/src/Mappers/Root/EnumTypeMapper.php:60
/srv/www/src/Acme/GraphQL/Type/Mapper.php:128
/srv/www/vendor/thecodingmachine/graphqlite/src/Mappers/Root/CompoundTypeMapper.php:54
/srv/www/vendor/thecodingmachine/graphqlite/src/Mappers/Root/IteratorTypeMapper.php:45
/srv/www/vendor/thecodingmachine/graphqlite/src/Mappers/Root/NullableTypeMapperAdapter.php:55
/srv/www/vendor/thecodingmachine/graphqlite/src/Mappers/Parameters/TypeHandler.php:350
/srv/www/vendor/thecodingmachine/graphqlite/src/Mappers/Parameters/TypeHandler.php:88
/srv/www/vendor/thecodingmachine/graphqlite/src/FieldsBuilder.php:401
/srv/www/vendor/thecodingmachine/graphqlite/src/FieldsBuilder.php:302
/srv/www/vendor/thecodingmachine/graphqlite/src/FieldsBuilder.php:208
/srv/www/vendor/thecodingmachine/graphqlite/src/Types/TypeAnnotatedObjectType.php:44
/srv/www/vendor/webonyx/graphql-php/src/Type/Definition/FieldDefinition.php:97
/srv/www/vendor/webonyx/graphql-php/src/Type/Definition/TypeWithFields.php:26
/srv/www/vendor/webonyx/graphql-php/src/Type/Definition/TypeWithFields.php:77
/srv/www/vendor/thecodingmachine/graphqlite/src/Types/MutableTrait.php:124
/srv/www/vendor/thecodingmachine/graphqlite/src/Types/MutableTrait.php:83
/srv/www/vendor/webonyx/graphql-php/src/Utils/TypeInfo.php:202
/srv/www/vendor/webonyx/graphql-php/src/Utils/TypeInfo.php:222
/srv/www/vendor/webonyx/graphql-php/src/Type/Schema.php:234
/srv/www/vendor/webonyx/graphql-php/src/Type/Schema.php:208
/srv/www/vendor/webonyx/graphql-php/src/Type/Introspection.php:240
/srv/www/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php:623
/srv/www/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php:550
/srv/www/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php:1195
/srv/www/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php:1145
/srv/www/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php:1106
/srv/www/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php:793
/srv/www/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php:741
/srv/www/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php:654
/srv/www/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php:557
/srv/www/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php:1195
/srv/www/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php:264
/srv/www/vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php:215
/srv/www/vendor/webonyx/graphql-php/src/Executor/Executor.php:156
/srv/www/vendor/webonyx/graphql-php/src/GraphQL.php:169
/srv/www/vendor/webonyx/graphql-php/src/Server/Helper.php:311
/srv/www/vendor/webonyx/graphql-php/src/Server/Helper.php:211
/srv/www/vendor/webonyx/graphql-php/src/Server/StandardServer.php:136
/srv/www/vendor/webonyx/graphql-php/src/Server/StandardServer.php:171

I'm not sure why it's calling the TypeGenerator here instead of the InputTypeGenerator, or even if the InputTypeGenerator should be called. I'd expect the RecursiveTypeMapper to be detecting the Input, but for some reason it's not.

In any case, it seems this is the reason this was put in place, which clearly looks like WIP code. I'll try to find some time to dig deeper into it.

@oojacoboo
Copy link
Collaborator

oojacoboo commented Dec 17, 2022

So, I've been digging into this and the issue is that TypeHandler::mapReturnType receives both input and output types. However, there isn't currently a way to determine if it's an input or output and that's needed to map it accordingly.

Creating a testcase for this is difficult because it seems very dependent on the order in which the schema builder processes types. I believe it's using lexical ordering from the registered type namespaces. However, I'm not 100% on this. I am aware of another issue where there are ordering issues with Input type defined classes and inputs built with a factory.

Working on a fix for this and hopefully I can get something reasonable put together.

I don't really like how convoluted it is right now to determine what types you're working with. In reality, these type mappers shouldn't be dealing with these reflection classes and docblocks, and should instead, be using a proxy class we manage with methods that return reliable details about the the type (input, output, nullable, etc.).

This would require that we change the RootTypeMapperInterface. Right now it's a collection of garbage, redundant objects that seems to be used in various type mappers. It's all an effort to just pass around whatever was needed downstream. The interface desperately needs cleaning up.

@l-you
Copy link
Contributor

l-you commented Dec 17, 2022

I am aware of another issue where there are ordering issues with Input type defined classes and inputs built with a factory.

Can the same reason cause issue #536?

@oojacoboo
Copy link
Collaborator

@bladl could absolutely be related. As it's currently written, the order in which types are processed matters. It obviously does a pretty good job, but there are clearly some holes. Making sense of all these type mappers, IMO, is complicated and frustrating. And I blame that on the interface design, coupled with a lack of documentation and sub-optimal parameter names.

@mdoelker
Copy link
Contributor Author

@oojacoboo Sounds to me like you are using an input type as a return value somewhere, thus using it as an output type. It makes sense to me that it is then trying to map it over and complains about the missing #[Type] annotation, because that's how we declare output types.

The solution would be to either strictly use input types for inputs and output types for outputs OR declaring the class as both an #[Input] AND a #[Type] to make it work. Not sure if that really makes sense, but that's a matter of choice I guess.

@oojacoboo
Copy link
Collaborator

@mdoelker Yep, that's basically it. So, it appears the issue is with the factories requiring a Type annotation. When a field, of what's actually an input type, returns another input type - there in lies the issue. Using factories and Input annotated classes together just doesn't work well. I don't know why factories are requiring a Type annotation, except for legacy reasons, since they were the initial way of creating input types before the Input annotation was added.

I guess it's possible that could be changed to require an Input annotation instead and maybe they'll work well together.

@oojacoboo
Copy link
Collaborator

I've created #537 for discussion on factory updates. I see no reason this PR shouldn't be merged, even if it's a breaking change for some.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants