Skip to content
22 changes: 20 additions & 2 deletions Definition/Builder/SchemaBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

use GraphQL\Schema;
use GraphQL\Type\Definition\Config;
use GraphQL\Type\LazyResolution;
use Overblog\GraphQLBundle\Resolver\ResolverInterface;

class SchemaBuilder
Expand All @@ -22,12 +23,29 @@ class SchemaBuilder
*/
private $typeResolver;

/**
* @var array
*/
private $schemaDescriptor;

/** @var bool */
private $enableValidation;

public function __construct(ResolverInterface $typeResolver, $enableValidation = false)
/**
* SchemaBuilder constructor.
*
* @param ResolverInterface $typeResolver
* @param array $schemaDescriptor
* @param bool $enableValidation
*/
public function __construct(
ResolverInterface $typeResolver,
array $schemaDescriptor,
$enableValidation = false
)
{
$this->typeResolver = $typeResolver;
$this->schemaDescriptor = $schemaDescriptor;
$this->enableValidation = $enableValidation;
}

Expand All @@ -50,7 +68,7 @@ public function create($queryAlias = null, $mutationAlias = null, $subscriptionA
'query' => $query,
'mutation' => $mutation,
'subscription' => $subscription,
'types' => $this->typeResolver->getSolutions(),
'typeResolution' => new LazyResolution($this->schemaDescriptor, [$this->typeResolver, 'resolve'])
]);
}
}
10 changes: 1 addition & 9 deletions DependencyInjection/Compiler/TaggedServiceMappingPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,7 @@ public function process(ContainerBuilder $container)
$resolverDefinition = $container->findDefinition($this->getResolverServiceID());

foreach ($mapping as $name => $options) {
$cleanOptions = $options;
$solutionID = $options['id'];

$definition = $container->findDefinition($solutionID);
if (is_subclass_of($definition->getClass(), 'Symfony\Component\DependencyInjection\ContainerAwareInterface')) {
$solutionDefinition = $container->findDefinition($options['id']);
$solutionDefinition->addMethodCall('setContainer', [new Reference('service_container')]);
}
$resolverDefinition->addMethodCall('addSolution', [$name, new Reference($solutionID), $cleanOptions]);
$resolverDefinition->addMethodCall('addSolution', [$name, null, $options]);
}
}

Expand Down
38 changes: 38 additions & 0 deletions DependencyInjection/Compiler/TypesPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,44 @@ public function process(ContainerBuilder $container)
->addTag('overblog_graphql.type', ['alias' => $name])
;
}

$types = [
'__Schema' => 1,
'__Type' => 1,
'__TypeKind' => 1,
'__Field' => 1,
'__InputValue' => 1,
'__EnumValue' => 1,
'__Directive' => 1,
'__DirectiveLocation' => 1
];
$possibleTypes = [];

foreach ($config as $typeConf) {
$typeName = $typeConf['config']['name'];
$types[$typeName] = 1;
if ($typeConf['type'] == 'object') {
$ifaces = $typeConf['config']['interfaces'] ?? [];
foreach ($ifaces as $iface) {
if (!array_key_exists($iface, $possibleTypes)) {
$possibleTypes[$iface] = [];
}
$possibleTypes[$iface][$typeName] = 1;
}
}
if ($typeConf['type'] == 'union') {
$possibleTypes[$typeName] = [];
foreach ($typeConf['config']['types'] as $unionMember) {
$possibleTypes[$typeName][$unionMember] = 1;
}
}
}

$container->getDefinition('overblog_graphql.schema_builder')->replaceArgument(1, [
'typeMap' => $types,
'possibleTypeMap' => $possibleTypes,
'version' => '1.0'
]);
}

private function processConfig(array $configs)
Expand Down
2 changes: 1 addition & 1 deletion Generator/TypeGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

class TypeGenerator extends BaseTypeGenerator
{
const USE_FOR_CLOSURES = '$container, $request, $user, $token';
const USE_FOR_CLOSURES = '$container';

private $cacheDir;

Expand Down
31 changes: 31 additions & 0 deletions Resolver/ResolverResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,39 @@

namespace Overblog\GraphQLBundle\Resolver;

use Symfony\Component\DependencyInjection\ContainerInterface;

class ResolverResolver extends AbstractProxyResolver
{
/**
* @var ContainerInterface
*/
private $container;

/**
* ResolverResolver constructor.
*
* @param ContainerInterface $container
*/
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}

public function getSolution($name)
{
$solution = parent::getSolution($name);

if (! $solution) {
$typeOptions = $this->getSolutionOptions($name);
if ($typeOptions and $this->container->has($typeOptions['id'])) {
$solution = $this->container->get($typeOptions['id']);
}
}

return $solution;
}

protected function unresolvableMessage($alias)
{
return sprintf('Unknown resolver with alias "%s" (verified service tag)', $alias);
Expand Down
35 changes: 28 additions & 7 deletions Resolver/TypeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
namespace Overblog\GraphQLBundle\Resolver;

use GraphQL\Type\Definition\Type;
use GraphQL\Type\Introspection;
use Overblog\GraphQLBundle\Resolver\Cache\ArrayCache;
use Overblog\GraphQLBundle\Resolver\Cache\CacheInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

class TypeResolver extends AbstractResolver
{
Expand All @@ -22,9 +24,23 @@ class TypeResolver extends AbstractResolver
*/
private $cache;

public function __construct(CacheInterface $cache = null)
{
/**
* @var ContainerInterface
*/
private $container;

/**
* LazyTypeResolver constructor.
*
* @param CacheInterface|null $cache
* @param ContainerInterface $container
*/
public function __construct(
CacheInterface $cache = null,
ContainerInterface $container
) {
$this->cache = null !== $cache ? $cache : new ArrayCache();
$this->container = $container;
}

/**
Expand All @@ -34,6 +50,11 @@ public function __construct(CacheInterface $cache = null)
*/
public function resolve($alias)
{
if (strpos($alias, '__') === 0) {
$staticName = '_'.lcfirst(substr($alias, 2));
return Introspection::$staticName();
}

if (null === $alias) {
return;
}
Expand Down Expand Up @@ -65,6 +86,11 @@ private function baseType($alias)
return $type;
}

$typeOptions = $this->getSolutionOptions($alias);
if ($typeOptions and $this->container->has($typeOptions['id'])) {
return $this->container->get($typeOptions['id']);
}

throw new UnresolvableException(
sprintf('Unknown type with alias "%s" (verified service tag)', $alias)
);
Expand Down Expand Up @@ -99,9 +125,4 @@ private function hasNeedListOfWrapper($alias)

return false;
}

protected function supportedSolutionClass()
{
return 'GraphQL\\Type\\Definition\\Type';
}
}
5 changes: 4 additions & 1 deletion Resources/config/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,19 @@ services:
public: false
arguments:
- "@overblog_graphql.type_resolver"
- "%overblog_graphql.definition.lazy_types_descriptor%"
- false

overblog_graphql.type_resolver:
class: Overblog\GraphQLBundle\Resolver\TypeResolver
arguments:
-
- "@service_container"

overblog_graphql.resolver_resolver:
class: Overblog\GraphQLBundle\Resolver\ResolverResolver
arguments:
- "@service_container"

overblog_graphql.mutation_resolver:
class: Overblog\GraphQLBundle\Resolver\MutationResolver
Expand Down Expand Up @@ -79,7 +83,6 @@ services:
- "%overblog_graphql.default_resolver%"
calls:
- ["addUseStatement", ["Symfony\\Component\\DependencyInjection\\ContainerInterface"]]
- ["addUseStatement", ["Symfony\\Component\\Security\\Core\\Authentication\\Token\\TokenInterface"]]
- ["setExpressionLanguage", ["@overblog_graphql.expression_language"]]

overblog_graphql.event_listener.classloader_listener:
Expand Down
12 changes: 0 additions & 12 deletions Resources/skeleton/TypeSystem.php.skeleton
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,6 @@
{<traits>
<spaces>public function __construct(ContainerInterface $container)
<spaces>{
<spaces><spaces>$request = null;
<spaces><spaces>$token = null;
<spaces><spaces>$user = null;
<spaces><spaces>if ($container->has('request_stack')) {
<spaces><spaces><spaces>$request = $container->get('request_stack')->getCurrentRequest();
<spaces><spaces>}
<spaces><spaces>if ($container->has('security.token_storage')) {
<spaces><spaces><spaces>$token = $container->get('security.token_storage')->getToken();
<spaces><spaces><spaces>if ($token instanceof TokenInterface) {
<spaces><spaces><spaces><spaces>$user = $token->getUser();
<spaces><spaces><spaces>}
<spaces><spaces>}

<spaces><spaces>parent::__construct(<config>);
<spaces>}
Expand Down