diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index ba93624b5b..3afd167284 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -18,6 +18,7 @@ New features: - Unauthorized access to fields can now generate GraphQL errors (rather that schema errors in GraphQLite v3) - Added fine-grained security using the `@Security` annotation. A field can now be [marked accessible or not depending on the context](fine-grained-security.md). For instance, you can restrict access to the field "viewsCount" of the type `BlogPost` only for post that the current user wrote. + - You can now inject the current logged user in any query / mutation / field using the `@InjectUser` annotation - Performance: - You can inject the [Webonyx query plan in a parameter from a resolver](query_plan.md) - You can use the [dataloader pattern to improve performance drastically via the "prefetchMethod" attribute](prefetch_method.md) diff --git a/src/Mappers/CannotMapTypeException.php b/src/Mappers/CannotMapTypeException.php index 5dd92097ac..680eb476e7 100644 --- a/src/Mappers/CannotMapTypeException.php +++ b/src/Mappers/CannotMapTypeException.php @@ -83,7 +83,7 @@ public static function mustBeOutputType(string $subTypeName): self public static function mustBeInputType(string $subTypeName): self { - return new self('type "' . $subTypeName . '" must be an input type.'); + return new self('type "' . $subTypeName . '" must be an input type (if you declared an input type with the name "' . $subTypeName . '", make sure that there are no output type with the same name as this is forbidden by the GraphQL spec).'); } /** diff --git a/src/TypeRegistry.php b/src/TypeRegistry.php index f9ce17fe91..21da7734b2 100644 --- a/src/TypeRegistry.php +++ b/src/TypeRegistry.php @@ -22,7 +22,7 @@ class TypeRegistry { /** @var array */ - private $outputTypes = []; + private $types = []; /** * Registers a type. @@ -33,10 +33,10 @@ class TypeRegistry */ public function registerType(NamedType $type): void { - if (isset($this->outputTypes[$type->name])) { + if (isset($this->types[$type->name])) { throw new GraphQLRuntimeException('Type "' . $type->name . '" is already registered'); } - $this->outputTypes[$type->name] = $type; + $this->types[$type->name] = $type; } /** @@ -50,17 +50,17 @@ public function registerType(NamedType $type): void */ public function getOrRegisterType(NamedType $type): NamedType { - if (isset($this->outputTypes[$type->name])) { - return $this->outputTypes[$type->name]; + if (isset($this->types[$type->name])) { + return $this->types[$type->name]; } - $this->outputTypes[$type->name] = $type; + $this->types[$type->name] = $type; return $type; } public function hasType(string $typeName): bool { - return isset($this->outputTypes[$typeName]); + return isset($this->types[$typeName]); } /** @@ -68,11 +68,11 @@ public function hasType(string $typeName): bool */ public function getType(string $typeName): NamedType { - if (! isset($this->outputTypes[$typeName])) { + if (! isset($this->types[$typeName])) { throw new GraphQLRuntimeException('Could not find type "' . $typeName . '" in registry'); } - return $this->outputTypes[$typeName]; + return $this->types[$typeName]; } public function getMutableObjectType(string $typeName): MutableObjectType diff --git a/tests/Fixtures/InputOutputNameConflict/Controllers/InAndOutController.php b/tests/Fixtures/InputOutputNameConflict/Controllers/InAndOutController.php new file mode 100644 index 0000000000..77740b61e9 --- /dev/null +++ b/tests/Fixtures/InputOutputNameConflict/Controllers/InAndOutController.php @@ -0,0 +1,21 @@ +value = $value; + } + + /** + * @Field() + */ + public function getValue(): string + { + return $this->value; + } + + /** + * @Factory(name="InAndOut") + */ + public static function create(string $value): self + { + return new self($value); + } +} diff --git a/tests/Fixtures/Integration/Types/ContactFactory.php b/tests/Fixtures/Integration/Types/ContactFactory.php index 9e1398d678..5f81fc602a 100644 --- a/tests/Fixtures/Integration/Types/ContactFactory.php +++ b/tests/Fixtures/Integration/Types/ContactFactory.php @@ -15,7 +15,7 @@ class ContactFactory { /** * @Factory() - * @UseInputType(for="$relations", inputType="[ContactRefInput!]!") + * @UseInputType(for="$relations", inputType="[ContactRef!]!") * @param string $name * @param Contact|null $manager * @param Contact[] $relations @@ -34,7 +34,7 @@ public function createContact(string $name, DateTimeInterface $birthDate, ?Uploa } /** - * @Factory(name="ContactRefInput", default=false) + * @Factory(name="ContactRef", default=false) * @return Contact */ public function getContact(string $name): Contact diff --git a/tests/Integration/EndToEndTest.php b/tests/Integration/EndToEndTest.php index 94654f7cc2..5976801098 100644 --- a/tests/Integration/EndToEndTest.php +++ b/tests/Integration/EndToEndTest.php @@ -21,6 +21,7 @@ use TheCodingMachine\GraphQLite\GraphQLRuntimeException; use TheCodingMachine\GraphQLite\InputTypeGenerator; use TheCodingMachine\GraphQLite\InputTypeUtils; +use TheCodingMachine\GraphQLite\Mappers\CannotMapTypeException; use TheCodingMachine\GraphQLite\Mappers\CompositeTypeMapper; use TheCodingMachine\GraphQLite\Mappers\GlobTypeMapper; use TheCodingMachine\GraphQLite\Mappers\Parameters\ContainerParameterHandler; @@ -52,6 +53,7 @@ use TheCodingMachine\GraphQLite\Containers\EmptyContainer; use TheCodingMachine\GraphQLite\Reflection\CachedDocBlockFactory; use TheCodingMachine\GraphQLite\Schema; +use TheCodingMachine\GraphQLite\SchemaFactory; use TheCodingMachine\GraphQLite\Security\AuthenticationServiceInterface; use TheCodingMachine\GraphQLite\Security\AuthorizationServiceInterface; use TheCodingMachine\GraphQLite\Security\SecurityExpressionLanguageProvider; @@ -451,7 +453,7 @@ public function testEndToEndInputType() { name: "bar" } - ] + ] } ) { name, @@ -1364,4 +1366,18 @@ public function getUser(): ?object $this->assertSame(42, $result->toArray(Debug::RETHROW_UNSAFE_EXCEPTIONS)['data']['injectedUser']); } + + public function testInputOutputNameConflict(): void + { + $schemaFactory = new SchemaFactory(new Psr16Cache(new ArrayAdapter()), new BasicAutoWiringContainer(new EmptyContainer())); + $schemaFactory->addControllerNamespace('TheCodingMachine\\GraphQLite\\Fixtures\\InputOutputNameConflict\\Controllers'); + $schemaFactory->addTypeNamespace('TheCodingMachine\\GraphQLite\\Fixtures\\InputOutputNameConflict\\Types'); + + $schema = $schemaFactory->createSchema(); + + $this->expectException(CannotMapTypeException::class); + $this->expectExceptionMessage('For parameter $inAndOut, in TheCodingMachine\\GraphQLite\\Fixtures\\InputOutputNameConflict\\Controllers\\InAndOutController::testInAndOut, type "InAndOut" must be an input type (if you declared an input type with the name "InAndOut", make sure that there are no output type with the same name as this is forbidden by the GraphQL spec).'); + + $schema->validate(); + } }