- Removed
use_experimental_executorconfiguraton option. - Signature of TypeInterface changed
- Customize the cursor encoder of the edges of a connection
- Change arguments of
TypeGenerator - Add magic
__getmethod toArgumentInterfaceimplementors - Annotations - Flattened annotations
- Annotations - Attributes changed
- Rename
GlobalVariablestoGraphQLServices - Replace
overblog_graphql.global_variabletag - Replace
resolverexpression function - Rename
ResolverInterfacetoQueryInterface - Remove Argument deprecated method
- Remove ConnectionBuilder deprecated class
- Remove XML type configuration
The connection builder now accepts an optional custom cursor encoder as first argument of the constructor.
$connectionBuilder = new ConnectionBuilder(
+ new class implements CursorEncoderInterface {
+ public function encode($value): string
+ {
+ ...
+ }
+
+ public function decode(string $cursor)
+ {
+ ...
+ }
+ }
static function (iterable $edges, PageInfoInterface $pageInfo) {
...
},
static function (string $cursor, $value, int $index) {
...
}
);The Overblog\GraphQLBundle\Generator\TypeGenerator service is used internally for compilation of GraphQL types. If you
overrode the service definition, please take into account the new constructor signature:
public function __construct(
array $typeConfigs,
TypeBuilder $typeBuilder,
EventDispatcherInterface $eventDispatcher,
TypeGeneratorOptions $options
)TypeBuilder here is a new service Overblog\GraphQLBundle\Generator\TypeBuilder, which is also used internally.
The rest of the arguments were moved into the separate class Overblog\GraphQLBundle\Generator\TypeGeneratorOptions
with the following constructor signature:
public function __construct(
string $namespace,
?string $cacheDir,
bool $useClassMap = true,
?string $cacheBaseDir = null,
?int $cacheDirMask = null
)The interface Overblog\GraphQLBundle\Definition\ArgumentInterface as well as implementing it class
Overblog\GraphQLBundle\Definition\Argument now have the magic __get method:
interface ArgumentInterface extends ArrayAccess, Countable
{
/**
* @return array the old array
*/
public function exchangeArray(array $array): array;
public function getArrayCopy(): array;
+ /**
+ * @return mixed
+ */
+ public function __get(string $name);
}
class Argument implements ArgumentInterface
{
// ...
+ public function __get(string $name)
+ {
+ return $this->rawArguments[$name] ?? null;
+ }
}If you use your own class for resolver arguments, then it should have a __get method as well.
In order to prepare to PHP 8 attributes (they don't support nested attributes at the moment. @see symfony/symfony#38503), the following annotations have been flattened: @FieldsBuilder, @FieldBuilder, @ArgsBuilder, @Arg and @EnumValue.
Before:
/**
* @GQL\Type
*/
class MyType {
/**
* @GQL\Field(args={
* @GQL\Arg(name="arg1", type="String"),
* @GQL\Arg(name="arg2", type="Int")
* })
*/
public function myFields(?string $arg1, ?int $arg2) {..}
}After:
/**
* @GQL\Type
*/
class MyType {
/**
* @GQL\Field
* @GQL\Arg(name="arg1", type="String"),
* @GQL\Arg(name="arg2", type="Int")
*/
public function myFields(?string $arg1, ?int $arg2) {..}
}Change the attributes name of @FieldsBuilder annotation from builder and builderConfig to value and config.
Before:
/**
* @GQL\Type(name="MyType", builders={@GQL\FieldsBuilder(builder="Timestamped", builderConfig={opt1: "val1"})})
*/
class MyType {
}After:
/**
* @GQL\Type("MyType")
* @GQL\FieldsBuilder(value="Timestamped", config={opt1: "val1"})
*/
class MyType {
}The GlobalVariables class was renamed into GraphQLServices to better reflect its purpose - holding services,
passed to all generated GraphQL types.
If you have any services tagged with overblog_graphql.global_variable, they should now be tagged with
overblog_graphql.service instead.
The signature of the resolver expression function has been changed.
Old signature (deprecated): resolver(string $alias, array $args = []): mixed
New signature: query(string $alias, ...$args): mixed
Example:
- resolver('get_posts', [args, info, value])
+ query('get_posts', args, info, value)The Overblog\GraphQLBundle\Definition\Resolver\ResolverInterface interface is deprecated. Use
Overblog\GraphQLBundle\Definition\Resolver\QueryInterface instead.
Example:
- use Overblog\GraphQLBundle\Definition\Resolver\ResolverInterface;
+ use Overblog\GraphQLBundle\Definition\Resolver\QueryInterface;
- class UserResolver implements ResolverInterface
+ class UserQuery implements QueryInterface
{
// ...
}Method Overblog\GraphQLBundle\Definition\Argument::getRawArguments is replaced by
Overblog\GraphQLBundle\Definition\Argument::getArrayCopy.
Class Overblog\GraphQLBundle\Relay\Connection\Output\ConnectionBuilder is replaced by
Overblog\GraphQLBundle\Relay\Connection\ConnectionBuilder.
XML type configuration is no longer supported.
- Rename default_field config
- Improve default field resolver
- Use service tags to register resolver maps
overblog_graphql:
definitions:
- default_resolver: ~
+ default_field_resolver: ~The new default_field_resolver config entry accepts callable service id.
Stop using internally symfony/property-access package
since it was a bottleneck to performance for large schema.
Array access and camelize getter/isser are supported but hasser,
jQuery style (e.g. last()) and "can" property accessors
are no more supported out-of-the-box,
please implement a custom resolver if these accessors are needed.
Globally:
overblog_graphql:
definitions:
default_field_resolver: 'App\GraphQL\CustomResolver'see default field resolver for more details
Per Type:
MyType:
type: object
config:
resolveField: 'App\GraphQL\MyTypeResolver::defaultFieldResolver'
fields:
name: {type: String}
email: {type: String}see default Field Resolver per type for more details
The resolver maps used to be configured using the overblog_graphql.definitions.schema.resolver_maps
option. This has been deprecated in favour of using service tags to register them.
# config/graphql.yaml
overblog_graphql:
definitions:
schema:
# ...
- resolver_maps:
- - 'App\GraphQL\MyResolverMap'# services/graphql.yaml
services:
- App\GraphQL\MyResolverMap: ~
+ App\GraphQL\MyResolverMap:
+ tags:
+ - { name: overblog_graphql.resolver_map, schema: default }- Remove auto mapping configuration
- Relay Paginator, Connections & Edges
- Remove obsoletes deprecations
- Simplify executor interface
- The AutoMapping configuration entry has been removed in favor of Symfony 4+ service configuration.
Upgrading:
- Delete old configuration.
overblog_graphql: definitions: - auto_mapping: ~ - use Symfony 4+ service configuration to tag your types, resolvers or mutation.
# config/services.yaml services: _defaults: autoconfigure: true App\GraphQL\: resource: ../src/GraphQL
- Following the paginator update and the use of interfaces for Relay Connection & Edge, getters & setters must be use to manipulate Connection, Edge and PageInfo Properties
Before :
$connection->edges = $edges;
$connection->totalCount = 10;
...
$edge->cursor = $cursor;
$edge->node = $node;After :
$connection->setEdges($edges);
$connection->setTotalCount(10);
...
$edge->setCursor($cursor);
$edge->setNode($node);Connection builder has been moved and it methods are no more accessible statically:
Before:
use Overblog\GraphQLBundle\Relay\Connection\Output\ConnectionBuilder;
ConnectionBuilder::connectionFromArray([]);After:
use Overblog\GraphQLBundle\Relay\Connection\ConnectionBuilder;
$connectionBuilder = new ConnectionBuilder();
$connectionBuilder->connectionFromArray([]);The builder short syntax (Field: Builder => Field: {builder: Builder}) is obsolete:
Foo:
type: object
config:
fields:
- bar: MyBuilder
+ bar: {builder: MyBuilder}
Relay builder without 'Relay::' prefix is obsolete:
Foo:
type: object
config:
fields:
bar:
- argsBuilder: ConnectionArgs
+ argsBuilder: "Relay::Connection"This section is only for users using custom executor.
The interface move to be look a little be more to GraphQL\GraphQL
promiseToExecute method.
In Overblog\GraphQLBundle\Executor\ExecutorInterface
setPromiseAdapter and setDefaultFieldResolver has been removed.
Promise adapter is now the first argument ($promiseAdapter)
and default field resolver the 7th argument ($fieldResolver) of
Overblog\GraphQLBundle\Executor\ExecutorInterface::execute method.
- GraphiQL
- Errors handler
- Promise adapter interface
- Expression language
- Type autoMapping and Symfony DI autoconfigure
- Events
- Explicitly declare non detected types
- Change fluent resolvers id
- The GraphiQL interface has been removed in favor of a new bundle.
Upgrading:
- Remove the graphiql route from your application
- For standard Symfony installation:
/app/config/routing_dev.yml - For Symfony Flex:
/config/routes/dev/graphql_graphiql.yaml
- For standard Symfony installation:
- Installing OverblogGraphiQLBundle
composer require --dev overblog/graphiql-bundle- Follow instructions at https://github.com/overblog/GraphiQLBundle
- In case you have defined the
versionsin your configuration- Remove it from
overblog_graphqloverblog_graphql: - versions: - graphiql: "0.11" - react: "15.6" - fetch: "2.0" - relay: "classic"
- Add it to
overblog_graphiqloverblog_graphiql: + javascript_libraries: + graphiql: "0.11" + react: "15.6" + fetch: "2.0"
- If you were using the
graphql:dump-schemaand depending on therelayversion as in the previous configuration, now you have to explicitly choose for a format during the command:bin/console graphql:dump-schema --modern
- Remove it from
- Made errors handler more customizable
Upgrading:
- Delete configuration to override base user exception classes.
overblog_graphql: definitions: exceptions: - types: - warnings: ~ - errors: ~ - Move
internal_error_message,map_exceptions_to_parentandexceptionsconfigurations fromdefinitionsto new dedicatederror_handlersection.overblog_graphql: definitions: - internal_error_message: ~ - map_exceptions_to_parent: ~ - exceptions: ~ + errors_handler: + internal_error_message: ~ + map_exceptions_to_parent: ~ + exceptions: ~
- Changed the promise adapter interface (
Overblog\GraphQLBundle\Executor\ExecutorInterface) as the promiseAdapter is not nullable in the bundle context.
Upgrading:
setPromiseAdaptermethod no more nullable.- public function setPromiseAdapter(PromiseAdapter $promiseAdapter = null); + public function setPromiseAdapter(PromiseAdapter $promiseAdapter);
- user expression variable has been replaced by getUser expression function
- container, request and token expression variables has been removed.
serviceorservexpression function should be used instead.
Upgrading your schema configuration:
-
Replace
userbygetUser():- resolve: '@=user' + resolve: '@=getUser()'
or
- resolve: '@=resolver('foo', [user])' + resolve: '@=resolver('foo', [getUser()])'
-
Replace
tokenbyserv('security.token_storage')- resolve: '@=token' + resolve: '@=serv('security.token_storage')'
or
- resolve: '@=resolver('foo', [token])' + resolve: '@=resolver('foo', [serv('security.token_storage')])'
-
Replace
requestbyserv('request_stack')- resolve: '@=request' + resolve: '@=serv('request_stack')'
or
- resolve: '@=resolver('foo', [request])' + resolve: '@=resolver('foo', [serv('request_stack')])'
When using these functionalities, type will be accessible only by FQCN in schema definition
(if class doesn't implement Overblog\GraphQLBundle\Definition\Resolver\AliasedInterface).
So if you want to use the true type name don't forget to declare it as an alias using interface.
This change is to increase performance, types are lazy-loaded.
Here's an example:
<?php
namespace App\GraphQL\Type;
use GraphQL\Type\Definition\ScalarType;
class DateTimeType extends ScalarType
{
public $name = 'DateTime';
// ...
}Before 0.11: DateTimeType could be accessed by FQCN App\GraphQL\Type\DateTimeType and the real DateTimeType.
Since 0.11: Only FQCN App\GraphQL\Type\DateTimeType is accessible
Here is how this can be done in 0.11:
<?php
namespace App\GraphQL\Type;
use GraphQL\Type\Definition\ScalarType;
use Overblog\GraphQLBundle\Definition\Resolver\AliasedInterface;
class DateTimeType extends ScalarType implements AliasedInterface
{
public $name = 'DateTime';
/**
* {@inheritdoc}
*/
public static function getAliases()
{
return ['DateTime'];
}
// ...
}Before 0.11 all types was declare as non detected types, this was not the correct way of declaring types. This could lead to some performances issues or/and wrong types public exposition (in introspection query). See webonyx/graphql-php documentations for more details
Since 0.11 Non detect types should be explicitly declared
Here is a concrete example:
Query:
type: object
config:
fields:
foo: {type: FooInterface!}
FooInterface:
type: interface
config:
fields:
id: {type: ID!}
resolveType: '@=resolver("foo", [value])'
Bar:
type: object
config:
fields:
id: {type: ID!}
# ...
interfaces: [FooInterface]
Baz:
type: object
config:
fields:
id: {type: ID!}
# ...
interfaces: [FooInterface]In above example Baz and Bar can not be detected by graphql-php during static schema analysis,
an GraphQL\Error\InvariantViolation exception will be thrown with the following message:
Could not find possible implementing types for FooInterface in schema.
Check that schema.types is defined and is an array of all possible types in the schema.
Here is how this can be fixed:
overblog_graphql:
definitions:
schema:
query: Query
types: [Bar, Baz]Overblog\GraphQLBundle\Event\ExecutorContextEvent::setExecutorContext method has been removed as context
is now an ArrayObject. When using graphql.executor.context listener the value will now be accessible only
in context variables and not in rootValue. context and rootValue have been separated, if you need to
use rootValue see event documentation for more details.
Before 0.11
context and rootValue were of type array with same value so $context === $info->rootValue and
$context === $value in root query resolver. Because of this, uploaded files was accessible in
$context['request_files'] and $info->rootValue['request_files'].
Since 0.11
context is of type ArrayObject and rootValue has no typeHint (default: null) so
$context !== $info->rootValue and $context !== $value in root query resolver.
Uploaded files is no longer accessible under $info->rootValue['request_files'] out of the box.
The use of class name as prefix of fluent resolver id removes the possibility to use same class as 2 different services. See issue #296 for more detail Because of this, in v0.11 we are using service id as prefix (like in Symfony 4.1)...
Example:
services:
app.resolver.greetings:
class: App\GraphQL\Resolver\Greetings
tags:
- { name: overblog_graphql.resolver, method: __invoke, alias: say_hello }
- { name: overblog_graphql.resolver }Before 0.11: '@=resolver("App\\GraphQL\\Resolver\\Greetings", [args['name']])'
Since 0.11: '@=resolver("app.resolver.greetings", [args['name']])'
-
Minimal supported Symfony version is now
^3.1 || ^4.0We've dropped support for Symfony 2.8 and 3.0
Upgrading your Symfony version: