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

Cleanup Input default value and Fix #1171 #1172

Merged
merged 7 commits into from
Mar 30, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 20 additions & 5 deletions docs/annotations/annotations-reference.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Annotations reference
# Annotations / Attributes reference

In the following reference examples the line `use Overblog\GraphQLBundle\Annotation as GQL;` will be omitted.

Expand All @@ -8,7 +8,7 @@ In the following reference examples the line `use Overblog\GraphQLBundle\Annotat

- For example, `@GQL\Access("isAuthenticated()")` will be converted to `['access' => '@=isAuthenticated()']` during the compilation.

- You can use multiple type annotations on the same class. For example, if you need your class to be a GraphQL Type AND a Graphql Input, you just need to add the two annotations. Incompatible annotations or properties for a specified Type will simply be ignored.
- You can use multiple type annotations on the same class. For example, if you need your class to be a GraphQL Type AND a GraphQL Input, you just need to add the two annotations. Incompatible annotations or properties for a specified Type will simply be ignored.

In the following example, both the type `Coordinates` and the input type `CoordinatesInput` will be generated during the compilation process.
As fields on input types don't support resolvers, the field `elevation` will simply be ignored to generate the input type (it will only have two fields: `latitude` and `longitude`).
Expand Down Expand Up @@ -62,6 +62,8 @@ class Coordinates {

[@Input](#input)

[@InputField](#inputfield)

[@IsPublic](#ispublic)

[@Mutation](#mutation)
Expand Down Expand Up @@ -425,6 +427,17 @@ Optional attributes:

The corresponding class will also be used by the `Arguments Transformer` service. An instance of the corresponding class will be use as the `input` value if it is an argument of a query or mutation. (see [The Arguments Transformer documentation](arguments-transformer.md)).

## @InputField

This annotation is used in conjunction with the `@Input` annotation to define an input field.
It is the same as a regular `@Field` annotation, but it can hold a `defaultValue` and can't have a `resolver`.

Optional attributes:

- **name** : The GraphQL name of the field (default to the property name)
- **type** : The GraphqL type of the field. This attribute can sometimes be guessed automatically from Doctrine ORM annotations
- **defaultValue** : The default value of the field

## @IsPublic

Added on a _class_ in conjunction with `@Type` or `@TypeInterface`, this annotation will define the default to set if fields are public or not.
Expand Down Expand Up @@ -578,13 +591,15 @@ class Hero {

This annotation is used on _class_ to define a GraphQL interface.

Required attributes:
Optional attributes:

- **resolveType** : An expression to resolve the types
- **name** : The GraphQL name of the interface (default to the class name without namespace)

Optional attributes:
If the `resolveType` attribute is not set, the service `overblog_graphql.interface_type_resolver` will be used to try to resolve the type automatically based on types implementing the interface and their associated class.
The system will register a map of interfaces with the list of types and their associated class name implementing the interface (the parameter is named `overblog_graphql_types.interfaces_map` in the container) and use it to resolve the type from the value (the first type where the class `instanceof` operator returns true will be used).

- **name** : The GraphQL name of the interface (default to the class name without namespace)
```php

Vincz marked this conversation as resolved.
Show resolved Hide resolved
## @Scalar

Expand Down
68 changes: 21 additions & 47 deletions docs/annotations/arguments-transformer.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# The Arguments Transformer service

When using annotation, as we use classes to describe our GraphQL objects, it is also possible to create and populate classes instances using GraphQL data.
When using attributes or annotations, as we use classes to describe our GraphQL objects, it is also possible to create and populate classes instances using GraphQL data.
If a class is used to describe a GraphQL Input, this same class can be instantiated to hold the corresponding GraphQL Input data.
This is where the `Arguments Transformer` comes into play. Knowing the matching between GraphQL types and PHP classes, the service is able to instantiate a PHP classes and populate it with data based on the corresponding GraphQL type.
This is where the `Arguments Transformer` comes into play. Knowing the matching between GraphQL types and PHP classes, the service is able to instantiate a PHP classes and populate it with data based on the corresponding GraphQL type.
To invoke the Arguments Transformer, we use the `input` expression function in our resolvers.

## the `arguments` function in expression language

The `arguments` function take two parameters, a mapping of arguments name and their type, like `name => type`. The type is in GraphQL notation, eventually with the "[]" and "!". The data are indexed by argument name.
This function will use the `Arguments Transformer` service to transform the list of arguments into their corresponding PHP class if it has one and using a property accessor, it will populate the instance, and will use the `validator` service to validate it.
The transformation is done recursively. If an Input include another Input as field, it will also be populated the same way.
The transformation is done recursively. If an Input include another Input as field, it will also be populated the same way.

For example:

Expand All @@ -19,51 +19,34 @@ namespace App\GraphQL\Input;
use Overblog\GraphQLBundle\Annotation as GQL;
use Symfony\Component\Validator\Constraints as Assert;

/**
* @GQL\Input
*/
#[GQL\Input]
class UserRegisterInput {
/**
* @GQL\Field(type="String!")
* @Assert\NotBlank
* @Assert\Length(min = 2, max = 50)
*/
#[Assert\NotBlank]
#[Assert\Length(min: 2, max: 50)]
#[GQL\Field(type: "String!")]
public $username;

/**
* @GQL\Field(type="String!")
* @Assert\NotBlank
* @Assert\Email
*/
#[Assert\NotBlank]
#[Assert\Email]
#[GQL\Field(type: "String!")]
public $email;

/**
* @GQL\Field(type="String!")
* @Assert\NotBlank
* @Assert\Length(
* min = 5,
* minMessage="The password must be at least 5 characters long."
* )
*/
#[Assert\NotBlank]
#[Assert\Length(min: 5, minMessage: "The password must be at least 5 characters long.")]
#[GQL\Field(type: "String!")]
public $password;

/**
* @GQL\Field(type="Int!")
* @Assert\NotBlank
* @Assert\GreaterThan(18)
*/
#[Assert\NotBlank]
#[Assert\GreaterThan(18)]
#[GQL\Field(type: "Int!")]
public $age;
}

....

/**
* @GQL\Provider
*/
#[GQL\Provider]
class UserRepository {
/**
* @GQL\Mutation
*/
#[GQL\Mutation]
public function createUser(UserRegisterInput $input) : User {
// Use the validated $input here
$user = new User();
Expand All @@ -81,19 +64,10 @@ The mutation received the valid instance.
In the above example, everything is auto-guessed and a Provider is used. But this would be the same as :

```php
/**
* @GQL\Type
*/
#[GQL\Type]
class RootMutation {
/**
* @GQL\Field(
* type="User",
* args={
* @GQL\Arg(name="input", type="UserRegisterInput")
* },
* resolve="@=call(service('UserRepository').createUser, arguments({input: 'UserRegisterInput'}, arg))"
* )
*/
#[GQL\Field(type: "User", resolve: "@=call(service('UserRepository').createUser, arguments({input: 'UserRegisterInput'}, arg))")]
#[GQL\Arg(name: "input", type: "UserRegisterInput")]
public $createUser;
}
```
Expand Down
Loading
Loading