diff --git a/src/Mappers/RecursiveTypeMapper.php b/src/Mappers/RecursiveTypeMapper.php index 3a227a5..b62c3ba 100644 --- a/src/Mappers/RecursiveTypeMapper.php +++ b/src/Mappers/RecursiveTypeMapper.php @@ -107,8 +107,12 @@ public function canMapClassToType(string $className): bool */ public function mapClassToType(string $className, ?OutputType $subType): MutableObjectType { - if (isset($this->classToTypeCache[$className])) { - return $this->classToTypeCache[$className]; + $cacheKey = $className; + if ($subType !== null) { + $cacheKey .= '__`__'.$subType->name; + } + if (isset($this->classToTypeCache[$cacheKey])) { + return $this->classToTypeCache[$cacheKey]; } $closestClassName = $this->findClosestMatchingParent($className); @@ -129,7 +133,7 @@ public function mapClassToType(string $className, ?OutputType $subType): Mutable } $this->typeRegistry->registerType($type); - $this->classToTypeCache[$className] = $type; + $this->classToTypeCache[$cacheKey] = $type; $this->extendType($className, $type); @@ -192,19 +196,23 @@ public function mapClassToInterfaceOrType(string $className, ?OutputType $subTyp if ($closestClassName === null) { throw CannotMapTypeException::createForType($className); } - if (!isset($this->interfaces[$closestClassName])) { + $cacheKey = $closestClassName; + if ($subType !== null) { + $cacheKey .= '__`__'.$subType->name; + } + if (!isset($this->interfaces[$cacheKey])) { $objectType = $this->mapClassToType($className, $subType); $supportedClasses = $this->getClassTree(); if (isset($supportedClasses[$closestClassName]) && !empty($supportedClasses[$closestClassName]->getChildren())) { // Cast as an interface - $this->interfaces[$closestClassName] = new InterfaceFromObjectType($this->namingStrategy->getInterfaceNameFromConcreteName($objectType->name), $objectType, $subType, $this); - $this->typeRegistry->registerType($this->interfaces[$closestClassName]); + $this->interfaces[$cacheKey] = new InterfaceFromObjectType($this->namingStrategy->getInterfaceNameFromConcreteName($objectType->name), $objectType, $subType, $this); + $this->typeRegistry->registerType($this->interfaces[$cacheKey]); } else { - $this->interfaces[$closestClassName] = $objectType; + $this->interfaces[$cacheKey] = $objectType; } } - return $this->interfaces[$closestClassName]; + return $this->interfaces[$cacheKey]; } /** diff --git a/tests/Fixtures/Integration/Controllers/ProductController.php b/tests/Fixtures/Integration/Controllers/ProductController.php new file mode 100644 index 0000000..bfae734 --- /dev/null +++ b/tests/Fixtures/Integration/Controllers/ProductController.php @@ -0,0 +1,27 @@ +name = $name; + $this->price = $price; + } + + /** + * @Field(name="name") + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * @Field(name="price") + * @return float + */ + public function getPrice(): float + { + return $this->price; + } +} diff --git a/tests/Integration/EndToEndTest.php b/tests/Integration/EndToEndTest.php index e14cf81..d7bcf0c 100644 --- a/tests/Integration/EndToEndTest.php +++ b/tests/Integration/EndToEndTest.php @@ -44,6 +44,7 @@ use TheCodingMachine\GraphQL\Controllers\TypeGenerator; use TheCodingMachine\GraphQL\Controllers\TypeRegistry; use TheCodingMachine\GraphQL\Controllers\Types\TypeResolver; +use function var_dump; use function var_export; class EndToEndTest extends TestCase @@ -394,5 +395,68 @@ public function testEndToEndPorpaginas() ], 'count' => 2 ] - ], $result->toArray(Debug::RETHROW_INTERNAL_EXCEPTIONS)['data']); } + ], $result->toArray(Debug::RETHROW_INTERNAL_EXCEPTIONS)['data']); + } + + /** + * This tests is used to be sure that the PorpaginasIterator types are not mixed up when cached (because it has a subtype) + */ + public function testEndToEnd2Iterators() + { + /** + * @var Schema $schema + */ + $schema = $this->mainContainer->get(Schema::class); + + $queryString = ' + query { + getContactsIterator { + items(limit: 1, offset: 1) { + name + uppercaseName + ... on User { + email + } + } + count + } + + getProducts { + items { + name + price + } + count + } + } + '; + + $result = GraphQL::executeQuery( + $schema, + $queryString + ); + + $this->assertSame([ + 'getContactsIterator' => [ + 'items' => [ + [ + 'name' => 'Bill', + 'uppercaseName' => 'BILL', + 'email' => 'bill@example.com' + ] + ], + 'count' => 2 + ], + 'getProducts' => [ + 'items' => [ + [ + 'name' => 'Foo', + 'price' => 42.0, + ] + ], + 'count' => 1 + ] + ], $result->toArray(Debug::RETHROW_INTERNAL_EXCEPTIONS)['data']); + + } }