diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..89314a047 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,11 @@ +| Q | A +| ---------------- | ----- +| Bug report? | yes/no +| Feature request? | yes/no +| BC Break report? | yes/no +| RFC? | yes/no +| Version/Branch | x.y.z + + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..e697fee2b --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,15 @@ +| Q | A +| ------------- | --- +| Bug fix? | yes/no +| New feature? | yes/no +| BC breaks? | yes/no +| Deprecations? | yes/no +| Tests pass? | yes/no +| Documented? | yes/no +| Fixed tickets | #... +| License | MIT + + diff --git a/Config/EnumTypeDefinition.php b/Config/EnumTypeDefinition.php index d0f7c7182..a86888d03 100644 --- a/Config/EnumTypeDefinition.php +++ b/Config/EnumTypeDefinition.php @@ -25,7 +25,6 @@ public function getDefinition() ->append($this->nameSection()) ->arrayNode('values') ->useAttributeAsKey('name') - // if value not define we use name as value ->beforeNormalization() ->ifTrue(function ($v) { return is_array($v); diff --git a/Config/ObjectTypeDefinition.php b/Config/ObjectTypeDefinition.php index 9c638a539..1aa112c04 100644 --- a/Config/ObjectTypeDefinition.php +++ b/Config/ObjectTypeDefinition.php @@ -23,7 +23,7 @@ public function getDefinition() $node ->children() ->append($this->nameSection()) - ->append($this->outputFieldsSelection('fields', true)) + ->append($this->outputFieldsSelection('fields')) ->append($this->descriptionSection()) ->arrayNode('interfaces') ->prototype('scalar')->info('One of internal or custom interface types.')->end() diff --git a/Config/TypeWithOutputFieldsDefinition.php b/Config/TypeWithOutputFieldsDefinition.php index 83c5b63fa..8618255f0 100644 --- a/Config/TypeWithOutputFieldsDefinition.php +++ b/Config/TypeWithOutputFieldsDefinition.php @@ -18,23 +18,26 @@ abstract class TypeWithOutputFieldsDefinition extends TypeDefinition { + const BUILDER_FIELD_TYPE = 'field'; + const BUILDER_ARGS_TYPE = 'args'; + /** * @var MappingInterface[] */ private static $argsBuilderClassMap = [ - 'ForwardConnectionArgs' => 'Overblog\GraphQLBundle\Relay\Connection\ForwardConnectionArgsDefinition', - 'BackwardConnectionArgs' => 'Overblog\GraphQLBundle\Relay\Connection\BackwardConnectionArgsDefinition', - 'ConnectionArgs' => 'Overblog\GraphQLBundle\Relay\Connection\ConnectionArgsDefinition', + 'Relay::ForwardConnection' => 'Overblog\GraphQLBundle\Relay\Connection\ForwardConnectionArgsDefinition', + 'Relay::BackwardConnection' => 'Overblog\GraphQLBundle\Relay\Connection\BackwardConnectionArgsDefinition', + 'Relay::Connection' => 'Overblog\GraphQLBundle\Relay\Connection\ConnectionArgsDefinition', ]; /** * @var MappingInterface[] */ private static $fieldBuilderClassMap = [ - 'Mutation' => 'Overblog\GraphQLBundle\Relay\Mutation\MutationFieldDefinition', - 'GlobalId' => 'Overblog\GraphQLBundle\Relay\Node\GlobalIdFieldDefinition', - 'Node' => 'Overblog\GraphQLBundle\Relay\Node\NodeFieldDefinition', - 'PluralIdentifyingRoot' => 'Overblog\GraphQLBundle\Relay\Node\PluralIdentifyingRootFieldDefinition', + 'Relay::Mutation' => 'Overblog\GraphQLBundle\Relay\Mutation\MutationFieldDefinition', + 'Relay::GlobalId' => 'Overblog\GraphQLBundle\Relay\Node\GlobalIdFieldDefinition', + 'Relay::Node' => 'Overblog\GraphQLBundle\Relay\Node\NodeFieldDefinition', + 'Relay::PluralIdentifyingRoot' => 'Overblog\GraphQLBundle\Relay\Node\PluralIdentifyingRootFieldDefinition', ]; public static function addArgsBuilderClass($name, $argBuilderClass) @@ -80,40 +83,40 @@ protected static function checkBuilderClass($builderClass, $type) } /** - * @param $name + * @param string $name + * @param string $type + * + * @return MappingInterface * - * @return MappingInterface|null + * @throws InvalidConfigurationException if builder class not define */ - protected function getArgsBuilder($name) + protected function getBuilder($name, $type) { static $builders = []; - if (isset($builders[$name])) { - return $builders[$name]; + if (isset($builders[$type][$name])) { + return $builders[$type][$name]; } - if (isset(self::$argsBuilderClassMap[$name])) { - return $builders[$name] = new self::$argsBuilderClassMap[$name](); - } - } + $builderClassMap = self::${$type.'BuilderClassMap'}; - /** - * @param $name - * - * @return MappingInterface|null - */ - protected function getFieldBuilder($name) - { - static $builders = []; - if (isset($builders[$name])) { - return $builders[$name]; + if (isset($builderClassMap[$name])) { + return $builders[$type][$name] = new $builderClassMap[$name](); } + // deprecated relay builder name ? + $newName = 'Relay::'.rtrim($name, 'Args'); + if (isset($builderClassMap[$newName])) { + @trigger_error( + sprintf('The "%s" %s builder is deprecated as of 0.7 and will be removed in 0.8. Use "%s" instead.', $name, $type, $newName), + E_USER_DEPRECATED + ); - if (isset(self::$fieldBuilderClassMap[$name])) { - return $builders[$name] = new self::$fieldBuilderClassMap[$name](); + return $builders[$type][$newName] = new $builderClassMap[$newName](); } + + throw new InvalidConfigurationException(sprintf('%s builder "%s" not found.', ucfirst($type), $name)); } - protected function outputFieldsSelection($name, $withAccess = false) + protected function outputFieldsSelection($name) { $builder = new TreeBuilder(); $node = $builder->root($name); @@ -140,12 +143,7 @@ protected function outputFieldsSelection($name, $withAccess = false) } if ($argsBuilderName) { - if (!($argsBuilder = $this->getArgsBuilder($argsBuilderName))) { - throw new InvalidConfigurationException(sprintf('Args builder "%s" not found.', $argsBuilder)); - } - - $args = $argsBuilder->toMappingDefinition([]); - + $args = $this->getBuilder($argsBuilderName, static::BUILDER_ARGS_TYPE)->toMappingDefinition([]); $field['args'] = isset($field['args']) && is_array($field['args']) ? array_merge($args, $field['args']) : $args; } @@ -163,6 +161,11 @@ protected function outputFieldsSelection($name, $withAccess = false) $fieldBuilderName = $field['builder']; unset($field['builder']); } elseif (is_string($field)) { + @trigger_error( + 'The builder short syntax (Field: Builder => Field: {builder: Builder}) is deprecated as of 0.7 and will be removed in 0.8. '. + 'It will be replaced by the field type short syntax (Field: Type => Field: {type: Type})', + E_USER_DEPRECATED + ); $fieldBuilderName = $field; } @@ -175,10 +178,7 @@ protected function outputFieldsSelection($name, $withAccess = false) } if ($fieldBuilderName) { - if (!($fieldBuilder = $this->getFieldBuilder($fieldBuilderName))) { - throw new InvalidConfigurationException(sprintf('Field builder "%s" not found.', $fieldBuilderName)); - } - $buildField = $fieldBuilder->toMappingDefinition($builderConfig); + $buildField = $this->getBuilder($fieldBuilderName, static::BUILDER_FIELD_TYPE)->toMappingDefinition($builderConfig); $field = is_array($field) ? array_merge($buildField, $field) : $buildField; } @@ -193,9 +193,18 @@ protected function outputFieldsSelection($name, $withAccess = false) ->info('Array of possible type arguments. Each entry is expected to be an array with following keys: name (string), type') ->useAttributeAsKey('name', false) ->prototype('array') + // Allow arg type short syntax (Arg: Type => Arg: {type: Type}) + ->beforeNormalization() + ->ifTrue(function ($options) { + return is_string($options); + }) + ->then(function ($options) { + return ['type' => $options]; + }) + ->end() ->children() ->append($this->typeSelection(true)) - ->scalarNode('description')->end() + ->append($this->descriptionSection()) ->append($this->defaultValueSection()) ->end() ->end() @@ -211,18 +220,8 @@ protected function outputFieldsSelection($name, $withAccess = false) ->variableNode('complexity') ->info('Custom complexity calculator.') ->end() - ->variableNode('map')->end() ->end(); - if ($withAccess) { - $prototype - ->children() - ->variableNode('access') - ->info('Access control to field (expression language can be use here)') - ->end() - ->end(); - } - return $node; } } diff --git a/Resources/config/graphql_types.yml b/Resources/config/graphql_types.yml index ac8fceba5..f9b9c5625 100644 --- a/Resources/config/graphql_types.yml +++ b/Resources/config/graphql_types.yml @@ -1,5 +1,5 @@ services: - # GraphQL ccalar types + # GraphQL build-in Scalars types overblog_graphql.definition.string_type: class: GraphQL\Type\Definition\StringType factory: ["GraphQL\\Type\\Definition\\Type", string] diff --git a/Resources/doc/definitions/index.md b/Resources/doc/definitions/index.md index c7c3e1b06..073bc2246 100644 --- a/Resources/doc/definitions/index.md +++ b/Resources/doc/definitions/index.md @@ -1,13 +1,12 @@ Definitions =========== -* [System types](system-types/index.md) +* [Type System](type-system/index.md) * [Schema](schema.md) Go further ---------- -* [Custom scalar](custom-scalar.md) * [Mutation](mutation.md) * [Relay](relay/index.md) * [Builders](builders/index.md) diff --git a/Resources/doc/definitions/relay/connection.md b/Resources/doc/definitions/relay/connection.md index a60e45a38..4a93236ea 100644 --- a/Resources/doc/definitions/relay/connection.md +++ b/Resources/doc/definitions/relay/connection.md @@ -18,15 +18,15 @@ User: type: String friends: type: friendConnection - argsBuilder: ConnectionArgs + argsBuilder: "Relay::Connection" resolve: '@=resolver("friends", [value, args])' friendsForward: type: userConnection - argsBuilder: ForwardConnectionArgs + argsBuilder: "Relay::ForwardConnection resolve: '@=resolver("friends", [value, args])' friendsBackward: type: userConnection - argsBuilder: BackwardConnectionArgs + argsBuilder: "Relay::BackwardConnection" resolve: '@=resolver("friends", [value, args])' friendConnection: diff --git a/Resources/doc/definitions/relay/mutation.md b/Resources/doc/definitions/relay/mutation.md index e4075d06f..b540ea3c5 100644 --- a/Resources/doc/definitions/relay/mutation.md +++ b/Resources/doc/definitions/relay/mutation.md @@ -7,7 +7,7 @@ Mutation: config: fields: introduceShip: - builder: Mutation + builder: "Relay::Mutation" builderConfig: inputType: IntroduceShipInput payloadType: IntroduceShipPayload diff --git a/Resources/doc/definitions/relay/node/global-id.md b/Resources/doc/definitions/relay/node/global-id.md index f6cc9b41e..23a02a05a 100644 --- a/Resources/doc/definitions/relay/node/global-id.md +++ b/Resources/doc/definitions/relay/node/global-id.md @@ -7,7 +7,7 @@ Query: config: fields: node: - builder: Node + builder: "Relay::Node" builderConfig: nodeInterfaceType: NodeInterface idFetcher: '@=service("overblog_graphql.test.resolver.global").idFetcher(value)' @@ -25,7 +25,7 @@ User: config: fields: id: - builder: GlobalId + builder: "Relay::GlobalId" builderConfig: typeName: User name: @@ -37,7 +37,7 @@ Photo: config: fields: id: - builder: GlobalId + builder: "Relay::GlobalId" builderConfig: typeName: Photo idFetcher: '@=value["photoId"]' @@ -50,7 +50,7 @@ Post: config: fields: id: - builder: GlobalId + builder: "Relay::GlobalId" builderConfig: typeName: Post text: diff --git a/Resources/doc/definitions/relay/node/node.md b/Resources/doc/definitions/relay/node/node.md index 78bb230d8..67e82671e 100644 --- a/Resources/doc/definitions/relay/node/node.md +++ b/Resources/doc/definitions/relay/node/node.md @@ -7,7 +7,7 @@ Query: config: fields: node: - builder: Node + builder: "Relay::Node" builderConfig: nodeInterfaceType: Node idFetcher: '@=resolver("node_id_fetcher", [value])' diff --git a/Resources/doc/definitions/relay/node/plural.md b/Resources/doc/definitions/relay/node/plural.md index e143f07ea..4fb4219b6 100644 --- a/Resources/doc/definitions/relay/node/plural.md +++ b/Resources/doc/definitions/relay/node/plural.md @@ -7,7 +7,7 @@ Query: config: fields: usernames: - builder: PluralIdentifyingRoot + builder: "Relay::PluralIdentifyingRoot" builderConfig: argName: 'usernames' description: 'Map from a username to the user' diff --git a/Resources/doc/definitions/system-types/index.md b/Resources/doc/definitions/system-types/index.md deleted file mode 100644 index dc8d29e63..000000000 --- a/Resources/doc/definitions/system-types/index.md +++ /dev/null @@ -1,11 +0,0 @@ -System types -============= - -Types can be defined in bundle Resources/config/graphql using -this file extension **.types.yml** or **.types.xml**. - -* [enum](enum.md) -* [interface](interface.md) -* [object](object.md) -* [union](union.md) -* [input object](input-object.md) diff --git a/Resources/doc/definitions/system-types/enum.md b/Resources/doc/definitions/type-system/enum.md similarity index 100% rename from Resources/doc/definitions/system-types/enum.md rename to Resources/doc/definitions/type-system/enum.md diff --git a/Resources/doc/definitions/type-system/index.md b/Resources/doc/definitions/type-system/index.md new file mode 100644 index 000000000..4466f5d1c --- /dev/null +++ b/Resources/doc/definitions/type-system/index.md @@ -0,0 +1,17 @@ +Type System +============ + +Types +----- + +Types can be defined in bundle Resources/config/graphql using +this file extension **.types.yml** or **.types.xml**. + +* [Scalars](scalars.md) +* [Object](object.md) +* [Interface](interface.md) +* [Union](union.md) +* [Enum](enum.md) +* [Input Object](input-object.md) +* [Lists](lists.md) +* [Non-Null](non-null.md) diff --git a/Resources/doc/definitions/system-types/input-object.md b/Resources/doc/definitions/type-system/input-object.md similarity index 100% rename from Resources/doc/definitions/system-types/input-object.md rename to Resources/doc/definitions/type-system/input-object.md diff --git a/Resources/doc/definitions/system-types/interface.md b/Resources/doc/definitions/type-system/interface.md similarity index 100% rename from Resources/doc/definitions/system-types/interface.md rename to Resources/doc/definitions/type-system/interface.md diff --git a/Resources/doc/definitions/type-system/lists.md b/Resources/doc/definitions/type-system/lists.md new file mode 100644 index 000000000..d6fe93113 --- /dev/null +++ b/Resources/doc/definitions/type-system/lists.md @@ -0,0 +1,5 @@ +Lists +====== + +To denote that a field uses a List type the item type is wrapped in square brackets like this: **[Pet]**. +If using yaml like config file, the double quote is required like this: **"[Pet]"**. diff --git a/Resources/doc/definitions/type-system/non-null.md b/Resources/doc/definitions/type-system/non-null.md new file mode 100644 index 000000000..1cce120d8 --- /dev/null +++ b/Resources/doc/definitions/type-system/non-null.md @@ -0,0 +1,4 @@ +Non-Null +======== + +A trailing exclamation mark is used to denote a field that uses a Non‐Null type like this: **String!**. diff --git a/Resources/doc/definitions/system-types/object.md b/Resources/doc/definitions/type-system/object.md similarity index 100% rename from Resources/doc/definitions/system-types/object.md rename to Resources/doc/definitions/type-system/object.md diff --git a/Resources/doc/definitions/custom-scalar.md b/Resources/doc/definitions/type-system/scalars.md similarity index 81% rename from Resources/doc/definitions/custom-scalar.md rename to Resources/doc/definitions/type-system/scalars.md index 4bda799e0..b9964dc06 100644 --- a/Resources/doc/definitions/custom-scalar.md +++ b/Resources/doc/definitions/type-system/scalars.md @@ -1,6 +1,18 @@ -# Custom scalar +Scalars +======= -Here a simple example to add a custom scalar: +Here all supported built‐in Scalars: + +* **Int** +* **Float** +* **String** +* **Boolean** +* **ID** + +Custom Scalar +------------- + +Here a simple example of how to add a custom Scalar: ```yaml DateTime: diff --git a/Resources/doc/definitions/system-types/union.md b/Resources/doc/definitions/type-system/union.md similarity index 100% rename from Resources/doc/definitions/system-types/union.md rename to Resources/doc/definitions/type-system/union.md diff --git a/Tests/Functional/app/config/connection/mapping/connection.types.yml b/Tests/Functional/app/config/connection/mapping/connection.types.yml index e0753a3ce..41743ba17 100644 --- a/Tests/Functional/app/config/connection/mapping/connection.types.yml +++ b/Tests/Functional/app/config/connection/mapping/connection.types.yml @@ -15,15 +15,15 @@ User: description: "the user name" friends: type: friendConnection - argsBuilder: ConnectionArgs + argsBuilder: "Relay::Connection" resolve: '@=resolver("friends", [value, args])' friendsForward: type: userConnection - argsBuilder: ForwardConnectionArgs + argsBuilder: "Relay::ForwardConnection" resolve: '@=resolver("friends", [value, args])' friendsBackward: type: userConnection - argsBuilder: BackwardConnectionArgs + argsBuilder: "Relay::BackwardConnection" resolve: '@=resolver("friends", [value, args])' friendConnection: diff --git a/Tests/Functional/app/config/customScalar/mapping/Query.types.yml b/Tests/Functional/app/config/customScalar/mapping/Query.types.yml index 00947adb3..f28d9db20 100644 --- a/Tests/Functional/app/config/customScalar/mapping/Query.types.yml +++ b/Tests/Functional/app/config/customScalar/mapping/Query.types.yml @@ -10,8 +10,7 @@ Query: config: fields: dateTime: - type: "DateTime!" + type: DateTime! args: - dateTime: - type: "DateTime" + dateTime: DateTime resolve: ["Overblog\\GraphQLGenerator\\Tests\\Resolver", "getDateTime"] diff --git a/Tests/Functional/app/config/global/mapping/global.types.yml b/Tests/Functional/app/config/global/mapping/global.types.yml index 9eb000221..c37e882cb 100644 --- a/Tests/Functional/app/config/global/mapping/global.types.yml +++ b/Tests/Functional/app/config/global/mapping/global.types.yml @@ -8,7 +8,7 @@ Query: config: fields: node: - builder: Node + builder: "Relay::Node" builderConfig: nodeInterfaceType: NodeInterface idFetcher: '@=service("overblog_graphql.test.resolver.global").idFetcher(value)' @@ -20,10 +20,7 @@ User: type: object config: fields: - id: - builder: GlobalId - builderConfig: - typeName: User + id: "Relay::GlobalId" name: type: String interfaces: [NodeInterface] @@ -33,7 +30,7 @@ Photo: config: fields: id: - builder: GlobalId + builder: "Relay::GlobalId" builderConfig: typeName: Photo idFetcher: '@=value["photoId"]' @@ -46,9 +43,7 @@ Post: config: fields: id: - builder: GlobalId - builderConfig: - typeName: Post + builder: "Relay::GlobalId" text: type: String status: diff --git a/Tests/Functional/app/config/mutation/mapping/RootMutation.types.yml b/Tests/Functional/app/config/mutation/mapping/RootMutation.types.yml index 776052610..230055886 100644 --- a/Tests/Functional/app/config/mutation/mapping/RootMutation.types.yml +++ b/Tests/Functional/app/config/mutation/mapping/RootMutation.types.yml @@ -3,13 +3,13 @@ RootMutation: config: fields: simpleMutation: - builder: Mutation + builder: "Relay::Mutation" builderConfig: inputType: simpleMutationInput payloadType: simpleMutationPayload mutateAndGetPayload: {result: 1} simpleMutationWithThunkFields: - builder: Mutation + builder: "Relay::Mutation" builderConfig: inputType: simpleMutationWithThunkFieldsInput payloadType: simpleMutationWithThunkFieldsPayload diff --git a/Tests/Functional/app/config/node/mapping/Query.types.yml b/Tests/Functional/app/config/node/mapping/Query.types.yml index 6db1035e0..a8c6d778c 100644 --- a/Tests/Functional/app/config/node/mapping/Query.types.yml +++ b/Tests/Functional/app/config/node/mapping/Query.types.yml @@ -3,7 +3,7 @@ Query: config: fields: node: - builder: Node + builder: "Relay::Node" builderConfig: nodeInterfaceType: Node idFetcher: '@=resolver("node_id_fetcher", [value])' diff --git a/Tests/Functional/app/config/plural/mapping/Query.types.xml b/Tests/Functional/app/config/plural/mapping/Query.types.xml index 4d67b9336..a3fc9798a 100644 --- a/Tests/Functional/app/config/plural/mapping/Query.types.xml +++ b/Tests/Functional/app/config/plural/mapping/Query.types.xml @@ -9,7 +9,7 @@ - PluralIdentifyingRoot + Relay::PluralIdentifyingRoot usernames Map from a username to the user diff --git a/Tests/Functional/app/config/queryComplexity/mapping/connectionWithComplexity.types.yml b/Tests/Functional/app/config/queryComplexity/mapping/connectionWithComplexity.types.yml index 1b15ca2ac..33e551c24 100644 --- a/Tests/Functional/app/config/queryComplexity/mapping/connectionWithComplexity.types.yml +++ b/Tests/Functional/app/config/queryComplexity/mapping/connectionWithComplexity.types.yml @@ -15,7 +15,7 @@ User: friends: complexity: "@=(!args['first'] ? 50 : 1) + childrenComplexity" type: friendConnection - argsBuilder: ConnectionArgs + argsBuilder: "Relay::Connection" resolve: '@=resolver("friends", [value, args])' friendConnection: