- Removed
use_experimental_executor
configuraton option. - Signature of TypeInterface changed from
string $name = null, string $resolveType
tostring $resolveType, ?string $name = null
- Removed deprecated
targetType
fromQuery
- Removed deprecated
fieldBuilder
fromField
- Removed deprecated
argsBuilder
fromField
- Removed deprecated
args
fromField
- Removed deprecated
builders
fromType
- Removed deprecated
values
fromEnum
- Removed deprecated
resolver_maps
configuration option - Removed
request_files
from context, userequest
object instead - Removed deprecated
builder
fromFieldsBuilder
, usename
attribute instead - Removed deprecated
builderConfig
fromFieldsBuilder
, useconfig
attribute instead - Removed deprecated autowire for type, resolver or mutation
implementing
Symfony\Component\DependencyInjection::setContainer
, use Symfony native autowire config instead - All classes are now final. If you need an extension point, try to use composition, implementing the interface or raise an issue.
- Customize the cursor encoder of the edges of a connection
- Change arguments of
TypeGenerator
- Add magic
__get
method toArgumentInterface
implementors - Annotations - Flattened annotations
- Annotations - Attributes changed
- Rename
GlobalVariables
toGraphQLServices
- Replace
overblog_graphql.global_variable
tag - Replace
resolver
expression function - Rename
ResolverInterface
toQueryInterface
- 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
versions
in your configuration- Remove it from
overblog_graphql
overblog_graphql: - versions: - graphiql: "0.11" - react: "15.6" - fetch: "2.0" - relay: "classic"
- Add it to
overblog_graphiql
overblog_graphiql: + javascript_libraries: + graphiql: "0.11" + react: "15.6" + fetch: "2.0"
- If you were using the
graphql:dump-schema
and depending on therelay
version 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_parent
andexceptions
configurations fromdefinitions
to new dedicatederror_handler
section.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:
setPromiseAdapter
method 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.
service
orserv
expression function should be used instead.
Upgrading your schema configuration:
-
Replace
user
bygetUser()
:- resolve: '@=user' + resolve: '@=getUser()'
or
- resolve: '@=resolver('foo', [user])' + resolve: '@=resolver('foo', [getUser()])'
-
Replace
token
byserv('security.token_storage')
- resolve: '@=token' + resolve: '@=serv('security.token_storage')'
or
- resolve: '@=resolver('foo', [token])' + resolve: '@=resolver('foo', [serv('security.token_storage')])'
-
Replace
request
byserv('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.0
We've dropped support for Symfony 2.8 and 3.0
Upgrading your Symfony version: