diff --git a/README.md b/README.md index 507092f32..fab92225f 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ Documentation - [Data fetching](docs/data-fetching/index.md) - [Query batching](docs/data-fetching/batching.md) - [Promise](docs/data-fetching/promise.md) -- [Annotations & PHP 8 Attributes](docs/annotations/index.md) +- [Attributes](docs/attributes/index.md) - [Validation](docs/validation/index.md) - [Security](docs/security/index.md) - [Handle CORS](docs/security/handle-cors.md) diff --git a/docs/annotations/arguments-transformer.md b/docs/attributes/arguments-transformer.md similarity index 100% rename from docs/annotations/arguments-transformer.md rename to docs/attributes/arguments-transformer.md diff --git a/docs/annotations/annotations-reference.md b/docs/attributes/attributes-reference.md similarity index 64% rename from docs/annotations/annotations-reference.md rename to docs/attributes/attributes-reference.md index 2a124e7e9..2df3fa2da 100644 --- a/docs/annotations/annotations-reference.md +++ b/docs/attributes/attributes-reference.md @@ -1,4 +1,4 @@ -# Annotations / Attributes reference +# Attributes reference In the following reference examples the line `use Overblog\GraphQLBundle\Annotation as GQL;` will be omitted. @@ -6,7 +6,7 @@ In the following reference examples the line `use Overblog\GraphQLBundle\Annotat - When an annotation requires an expression, the `@=` will be added automatically if it's not set. - - For example, `@GQL\Access("isAuthenticated()")` will be converted to `['access' => '@=isAuthenticated()']` during the compilation. + - 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. @@ -16,114 +16,100 @@ As fields on input types don't support resolvers, the field `elevation` will sim ```php "heroId"])] public $id; - /** - * @GQL\Field(type="[Hero]", resolve="resolver('hero_friends', [args['droidsOnly'], args['nameStartsWith']])") - * @GQL\Arg(name="droidsOnly", type="Boolean", description="Retrieve only droids heroes"), - * @GQL\Arg(name="nameStartsWith", type="String", description="Retrieve only heroes with name starting with") - */ + #[GQL\Field(type: "[Hero]", resolve: "resolver('hero_friends', [args['droidsOnly'], args['nameStartsWith']])")] + #[GQL\Arg(name: "droidsOnly", type: "Boolean", description: "Retrieve only droids heroes")] + #[GQL\Arg(name: "nameStartsWith", type: "String", description: "Retrieve only heroes with name starting with")] public $friends; } ``` -## @ArgsBuilder +## `#[ArgsBuilder]` -This annotation is used in conjunction with a `@Field`, a `@Query` or `@Mutation` to generate the field arguments. +This annotation is used in conjunction with a `#Field`, a `#Query` or `#Mutation` to generate the field arguments. It is used to set an arguments builder for a field (see [Args builders](../definitions/builders/args.md))) -Required attributes: +Required parameters: - **value** : The name of the args builder -Optional attributes: +Optional parameters: - **config** : The configuration to pass to the args builder @@ -169,79 +150,67 @@ Example: ```php getFriends(); } } ``` -## @Deprecated +## `#[Deprecated]` -This annotation is used in conjunction with `@Field` to mark it as deprecated with the specified reason. +This annotation is used in conjunction with `#Field` to mark it as deprecated with the specified reason. Example ```php ' - **type** : The GraphqL type of the field. This attribute can sometimes be guessed automatically from Doctrine ORM annotations @@ -306,7 +273,7 @@ Optional attributes: Deprecated attributes (use flat annotations instead): -- **args** : An array of `@Arg` +- **args** : An array of `#[Arg]` - **fieldBuilder** : A field builder to use. Either as string (will be the field builder name), or as an array, first index will the name of the builder and second one will be the config. - **argsBuilder** : An args builder to use. Either as string (will be the args builder name), or as an array, first index will the name of the builder and second one will be the config. @@ -315,23 +282,15 @@ Example on properties: ```php "heroId"])] public $id; - /** - * @GQL\Field( - * type="[Hero]", - * resolve="resolver('hero_friends', [value, args['page']])" - * ) - * @GQL\ArgsBuilder("Pager") - */ + #[GQL\Field(type: "[Hero]", resolve: "resolver('hero_friends', [value, args['page']])")] + #[GQL\ArgsBuilder("Pager")] public $friends; } ``` @@ -341,30 +300,27 @@ Example on methods: ```php friends, 0, $limit); } } ``` -## @FieldBuilder +## `#[FieldBuilder]` -This annotation is used with `@Field`, `@Query` or `@Mutation` to use a builder to generate the field. +This annotation is used with `#Field`, `#Query` or `#Mutation` to use a builder to generate the field. It is used to set a field builder for a field (see [Field builders](../definitions/builders/field.md))) -Required attributes: +Required parameters: - **value** : The name of the field builder -Optional attributes: +Optional parameters: - **config** : The configuration to pass to the field builder @@ -373,29 +329,26 @@ Example: ```php "heroId"])] protected $field1; } ``` -## @FieldsBuilder +## `#[FieldsBuilder]` -This annotation is used with `@GQL\Type` to use a builder to generate fields for the type. +This annotation is used with `#[GQL\Type]` to use a builder to generate fields for the type. It is used to add fields builder to types (see [Fields builders](../definitions/builders/fields.md))) -Required attributes: +Required parameters: - **value** : The name of the fields builder -Optional attributes: +Optional parameters: - **config** : The configuration to pass to the fields builder @@ -404,76 +357,70 @@ Example: ```php repository->find($id); $user->setEmail($newEmail); @@ -506,31 +449,31 @@ class MutationProvider { } ``` -## @Provider +## `#[Provider]` -This annotation applies on classes to indicate that it contains methods tagged with `@Query` or `@Mutation`. -Without it, the `@Query` and `@Mutation` are ignored. When used, **remember to have a corresponding service with the fully qualified name of the class as service id**. -You can use `@Access` and/or `@IsPublic` on a provider class to add default access or visibility on defined query or mutation. +This annotation applies on classes to indicate that it contains methods tagged with #Query` or #Mutation`. +Without it, the #Query` and #Mutation` are ignored. When used, **remember to have a corresponding service with the fully qualified name of the class as service id**. +You can use #Access` and/or #IsPublic` on a provider class to add default access or visibility on defined query or mutation. -Optional attributes: +Optional parameters: - **prefix**: A prefix to apply to all field names from this provider -- **targetQueryTypes**: The default GraphQL type(s) to attach the provider `@Query` to -- **targetMutationTypes**: The default GraphQL type(s) to attach the provider `@Mutation` to +- **targetQueryTypes**: The default GraphQL type(s) to attach the provider #Query` to +- **targetMutationTypes**: The default GraphQL type(s) to attach the provider #Mutation` to -## @Query +## `#[Query]` -This annotation applies on methods for classes tagged with the `@Provider` annotation. It indicates that on this class a method will resolve a Query field. +This annotation applies on methods for classes tagged with the #Provider` annotation. It indicates that on this class a method will resolve a Query field. The corresponding GraphQL field is added to the GraphQL type(s) following the logic: -- The type(s) specified in the `targetTypes` attribute of the `@Query` annotation if it's defined. +- The type(s) specified in the `targetTypes` attribute of the #Query` annotation if it's defined. or -- The type(s) specified in the `targetQueryTypes` attribute of the `@Provider` annotation if it's defined. +- The type(s) specified in the `targetQueryTypes` attribute of the #Provider` annotation if it's defined. or - The root Query type of the default schema (defined in configuration at key `overblog_graphql.definitions.schema.query` or `overblog_graphql.definitions.schema.default.query`). The class exposing the query(ies) must be declared as a [service](https://symfony.com/doc/current/service_container.html). -Optional attributes: +Optional parameters: - **targetTypes** : The GraphQL type(s) to attach the field to (by default, it'll be the root Query type of the default schema. see [Default Schema](../definitions/schema.md#default-schema)). You can specify one or multiple target types. @@ -543,55 +486,47 @@ This will add a `users` property on the main query object, with a resolver `@=se namespace App\Graphql\Query; -/** - * @GQL\Provider - */ +#[GQL\Provider] class UsersProviders { - /** - * @GQL\Query(type="[User]", name="users") - */ + #[GQL\Query(type: "[User]", name: "users")] public function getUsers() { return $this->repository->findAll(); } } ``` -## @Type +## `#[Type]` This annotation is used on _class_ to define a GraphQL Type. -Optional attributes: +Optional parameters: - **name** : The GraphQL name of the type (default to the class name without namespace) - **interfaces** : An array of GraphQL interface this type inherits from (can be auto-guessed. See interface documentation). - **isRelay** : Set to true to have a Relay compatible type (ie. A `clientMutationId` will be added). - **isTypeOf** : Is type of resolver for interface implementation -Deprecated attributes: +Deprecated parameters: -- **builders** : An array of `@FieldsBuilder` annotations +- **builders** : An array of `#[FieldsBuilder]` attributes ```php "MyConnectionEdge"])] class MyConnection {} ``` @@ -725,30 +651,24 @@ If the `node` attribute is used, a standard edge type will be automatically gene ```php "MyType"])] +#[GQL\Type] class MyConnectionEdge {} -/** - * @GQL\Type - * @GQL\FieldsBuilder("relay-connection", config={edgeType="MyConnectionEdge"}) - */ +#[GQL\FieldsBuilder("relay-connection", config: ["edgeType" => "MyConnectionEdge"])] +#[GQL\Type] class MyConnection {} ``` -## @Relay\Edge +## `#[Relay\Edge]` -This annotation extends the `@Type` annotation so it uses the same attributes. +This annotation extends the `#Type` annotation so it uses the same attributes. It prepends the `RelayEdgeFieldsBuilder` to the list of fields builders. The extra attribute is : @@ -758,16 +678,12 @@ The extra attribute is : ```php "MyType"])] +#[GQL\Type] class MyEdge {} ``` diff --git a/docs/annotations/index.md b/docs/attributes/index.md similarity index 87% rename from docs/annotations/index.md rename to docs/attributes/index.md index 122c27407..a1880bcec 100644 --- a/docs/annotations/index.md +++ b/docs/attributes/index.md @@ -28,11 +28,13 @@ overblog_graphql: suffix: ~ ``` +Note: The annotation are deprecated as of version `1.3` and will be removed in the next major version. + This will load all annotated classes in `%kernel.project_dir%/src/GraphQL` into the schema. The annotations & attributes are equivalent and are used in the same way. They share the same annotation namespaces, classes and API. -Example with annotations: +Example with attributes: ```php use Overblog\GraphQLBundle\Annotation as GQL; @@ -43,21 +45,25 @@ class MyType { } ``` -Example with attributes: +Example with annotations: ```php use Overblog\GraphQLBundle\Annotation as GQL; -#[GQL\Type] +/** + * @GQL\Type + */ class MyType { - #[GQL\Field(type: "Int")] + /** + * @GQL\Field(type="Int") + */ protected $myField; } ``` -## Using Annotations or Attributes as your only Mapping +## Using Attributes as your only Mapping -If you only use annotations as mappings you need to add an empty `RootQuery` type. +If you only use attributes as mappings you need to add an empty `RootQuery` type. Your config should look like this: ```yaml @@ -68,7 +74,7 @@ overblog_graphql: query: RootQuery mappings: types: - - type: annotation + - type: attribute dir: "%kernel.project_dir%/src/GraphQL" suffix: ~ ``` @@ -85,18 +91,18 @@ class RootQuery If you use mutations, you need a `RootMutation` type as well. -## Attributes/Annotations reference -- [Attributes/Annotations reference](annotations-reference.md) +## Attributes reference +- [Attributes reference](attributes-reference.md) ## Arguments transformation, populating & validation - [Arguments Transformer](arguments-transformer.md) -## Annotations & type inheritance +## Attributes & type inheritance -As PHP classes naturally support inheritance (and so is the annotation reader), it doesn't make sense to allow classes to use the "inherits" option (as on types declared using YAML). -The type will inherit annotations declared on parent class properties and methods. The annotation on the class itself will not be inherited. +As PHP classes naturally support inheritance (and so is the attribute reader), it doesn't make sense to allow classes to use the "inherits" option (as on types declared using YAML). +The type will inherit attributes declared on parent class properties and methods. The attribute on the class itself will not be inherited. -## Attributes/Annotations, value & default resolver +## Attributes, value & default resolver In GraphQL, when a type's field is resolved, GraphQL expects by default a property (for object) or a key (for array) on the corresponding value returned for the type. @@ -114,7 +120,7 @@ So, the `value` could be an object instance with a `name` property or an array w Except for the root Query and root Mutation types, the `value` variable is always returned by another resolver. For the root Query and the Root Mutation types, the `value` variable is the service with an id that equals to the fully qualified name of the query/mutation class. -The following rules apply for `#[GQL\Field]`, `#[GQL\Query]` and `#[GQL\Mutation]` annotations to guess a resolver when no `resolver` attribute is defined: +The following rules apply for `#[GQL\Field]`, `#[GQL\Query]` and `#[GQL\Mutation]` attributes to guess a resolver when no `resolver` attribute is defined: - If `#[GQL\Field]` is defined on a property : - If `#[GQL\Field]`'s attribute `name` is defined and is not equal to the property name @@ -130,9 +136,9 @@ The following rules apply for `#[GQL\Field]`, `#[GQL\Query]` and `#[GQL\Mutation - `@=call(service()., args)` for root query or mutation -## Attributes/Annotations, Root Query & Root Mutation +## Attributes, Root Query & Root Mutation -If you define your root Query or root Mutation type as a class with annotations, it will allow you to define methods directly on the class itself to be exposed as GraphQL fields. +If you define your root Query or root Mutation type as a class with attributes, it will allow you to define methods directly on the class itself to be exposed as GraphQL fields. For example: ```php @@ -244,7 +250,7 @@ In this example, the type `String!` will be auto-guessed from the return type hi ### `#[GQL\Field]` arguments auto-guessing when defined on a method with type hinted parameters -The arguments of the `#[GQL\Field]` attribute/annotation can be auto-guessed if it's defined on a method with type hinted arguments. Arguments without default value will be consided required. +The arguments of the `#[GQL\Field]` attribute can be auto-guessed if it's defined on a method with type hinted arguments. Arguments without default value will be consided required. For example: