diff --git a/Definition/Builder/SchemaBuilder.php b/Definition/Builder/SchemaBuilder.php index cbf4c7234..6ef069268 100644 --- a/Definition/Builder/SchemaBuilder.php +++ b/Definition/Builder/SchemaBuilder.php @@ -13,6 +13,7 @@ use GraphQL\Schema; use GraphQL\Type\Definition\Config; +use GraphQL\Type\LazyResolution; use Overblog\GraphQLBundle\Resolver\ResolverInterface; class SchemaBuilder @@ -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; } @@ -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']) ]); } } diff --git a/DependencyInjection/Compiler/TaggedServiceMappingPass.php b/DependencyInjection/Compiler/TaggedServiceMappingPass.php index f0db04fc0..c5c7dd3ef 100644 --- a/DependencyInjection/Compiler/TaggedServiceMappingPass.php +++ b/DependencyInjection/Compiler/TaggedServiceMappingPass.php @@ -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]); } } diff --git a/DependencyInjection/Compiler/TypesPass.php b/DependencyInjection/Compiler/TypesPass.php index c56d3eee7..81602b5a7 100644 --- a/DependencyInjection/Compiler/TypesPass.php +++ b/DependencyInjection/Compiler/TypesPass.php @@ -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) diff --git a/Generator/TypeGenerator.php b/Generator/TypeGenerator.php index 64d4be590..aa02e34ef 100644 --- a/Generator/TypeGenerator.php +++ b/Generator/TypeGenerator.php @@ -17,7 +17,7 @@ class TypeGenerator extends BaseTypeGenerator { - const USE_FOR_CLOSURES = '$container, $request, $user, $token'; + const USE_FOR_CLOSURES = '$container'; private $cacheDir; diff --git a/Resolver/ResolverResolver.php b/Resolver/ResolverResolver.php index 8e21d8275..0d0b969dc 100644 --- a/Resolver/ResolverResolver.php +++ b/Resolver/ResolverResolver.php @@ -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); diff --git a/Resolver/TypeResolver.php b/Resolver/TypeResolver.php index f2890251a..1b39ec120 100644 --- a/Resolver/TypeResolver.php +++ b/Resolver/TypeResolver.php @@ -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 { @@ -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; } /** @@ -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; } @@ -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) ); @@ -99,9 +125,4 @@ private function hasNeedListOfWrapper($alias) return false; } - - protected function supportedSolutionClass() - { - return 'GraphQL\\Type\\Definition\\Type'; - } } diff --git a/Resources/config/services.yml b/Resources/config/services.yml index ed11bd8f1..410aa4363 100644 --- a/Resources/config/services.yml +++ b/Resources/config/services.yml @@ -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 @@ -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: diff --git a/Resources/skeleton/TypeSystem.php.skeleton b/Resources/skeleton/TypeSystem.php.skeleton index 6e80f9dc3..844795581 100644 --- a/Resources/skeleton/TypeSystem.php.skeleton +++ b/Resources/skeleton/TypeSystem.php.skeleton @@ -6,18 +6,6 @@ { public function __construct(ContainerInterface $container) { -$request = null; -$token = null; -$user = null; -if ($container->has('request_stack')) { -$request = $container->get('request_stack')->getCurrentRequest(); -} -if ($container->has('security.token_storage')) { -$token = $container->get('security.token_storage')->getToken(); -if ($token instanceof TokenInterface) { -$user = $token->getUser(); -} -} parent::__construct(); }