Repository navigation
feat: support phpdocumentor/reflection-docblock 6 and type-resolver 2 - #840
timtheisinger wants to merge 2 commits into
Conversation
reflection-docblock 6 requires type-resolver 2, which replaces the `Types\Collection` list type with `PseudoTypes\Generic`, an `Object_`. Generic iterables such as `\ArrayObject<int, User>` therefore no longer mapped to GraphQL lists. Handle `Generic` next to `Collection` so both major versions work. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #840 +/- ##
============================================
- Coverage 95.72% 92.07% -3.66%
- Complexity 1773 2175 +402
============================================
Files 154 205 +51
Lines 4586 5777 +1191
============================================
+ Hits 4390 5319 +929
- Misses 196 458 +262 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
| // (an `Object_`) instead of `Collection` (an `AbstractList`). | ||
| if ($type instanceof Generic && $type->getTypes() !== []) { | ||
| $genericTypes = $type->getTypes(); | ||
| $innerType = $this->topRootTypeMapper->toGraphQLOutputType(end($genericTypes), $subType, $reflector, $docBlockObj); |
There was a problem hiding this comment.
Why do we only pass the last type of the $type->getTypes() for the OutputType? Does this mean support for union and intersection types aren't properly supported here?
There was a problem hiding this comment.
We're working with lists here and want to get the type of items in that list. For all common PHP list types like ArrayObject or Iterator (not true for Generator) this should be last the type parameter. This behavior is also exactly what getValueType did in type-resolver v1.
See: https://github.com/phpDocumentor/TypeResolver/blob/1.12.0/src/TypeResolver.php#L457-L466
https://github.com/phpDocumentor/TypeResolver/blob/1.12.0/src/Types/Collection.php#L40
It reverses the params and the last one lands in valueType.
I'm not sure exactly what you mean by missing support for unions/intersections. For example if we have a \ArrayObject<int, A&B>, the whole intersection A&B will be the value type, as before. The tests cover this already as far as I can see.
There was a problem hiding this comment.
@timtheisinger what does getTypes return for a phpdoc like:
@return \ArrayObject<int, A&B>|boolUnlike `Collection`, type-resolver 2's `Generic` is an `Object_`, so `IteratorTypeMapper` took `\ArrayObject<int, User>` for a raw iterator in the `\ArrayObject|User[]` pattern. Other union members were then dropped instead of failing: `\ArrayObject<int, User>|bool` mapped to `[User!]!`. Skip `Generic` wherever `Collection` used to fall through, so mapping results and errors match type-resolver 1.
Problem
GraphQLite requires
phpdocumentor/reflection-docblock ^5.4andphpdocumentor/type-resolver ^1.7. Current projects increasingly lockreflection-docblock6 (which requirestype-resolver2) through other dependencies, for example a fresh Shopware 6.7 project viamcp/sdk. In such a project, Composer cannot install GraphQLite or anything that depends on it without downgradingreflection-docblock(-W).Only widening the constraints is not enough.
type-resolver2 replacesTypes\Collection(anAbstractList) withPseudoTypes\Generic(anObject_), so generic iterables such as\ArrayObject<int, User>or\Iterator<string, int>stop mapping to GraphQL lists: 17 tests fail and PHPStan reports the missingCollectionclass.Fix
BaseTypeMappermaps aGenericoutput type to a list of its last type parameter, which is whatCollection(anAbstractListwith that value type) did withtype-resolver1.TypeHandlermatches a phpdoc generic against a non-generic return type (\ArrayObject/\ArrayObject<string, TestObject>) for bothCollectionandGeneric.composer.jsonallowsreflection-docblock ^5.4 || ^6.0andtype-resolver ^1.7 || ^2.0.phpstan.neonignoresclass.notFoundfor them in these two files.Nothing else in GraphQLite depends on the API that changed between the major versions.
Tests
The existing tests already cover generic iterables and fail on
type-resolver2 without this change. With it all tests pass.We also built our production schema (183 types) with
reflection-docblock5 and 6. The output is byte-identical.