Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Definition/Builder/SchemaBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ public function create($queryAlias = null, $mutationAlias = null, $subscriptionA
'query' => $query,
'mutation' => $mutation,
'subscription' => $subscription,
'types' => $this->typeResolver->getSolutions(),
'typeLoader' => [$this->typeResolver, 'resolve'],
'types' => [$this->typeResolver, 'getSolutions'],
]);
if ($this->enableValidation) {
$schema->assertValid();
Expand Down
9 changes: 7 additions & 2 deletions DependencyInjection/Compiler/TaggedServiceMappingPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ public function process(ContainerBuilder $container)
$cleanOptions = $options;
$solutionID = $options['id'];

$solutionDefinition = $container->findDefinition($options['id']);
$solutionDefinition = $container->findDefinition($solutionID);
// make solution service public to improve lazy loading
$solutionDefinition->setPublic(true);

$methods = array_map(
function ($methodCall) {
Expand All @@ -80,7 +82,10 @@ function ($methodCall) {
$solutionDefinition->addMethodCall('setContainer', [new Reference('service_container')]);
}

$resolverDefinition->addMethodCall('addSolution', [$name, new Reference($solutionID), $cleanOptions]);
$resolverDefinition->addMethodCall(
'addSolution',
[$name, [new Reference('service_container'), 'get'], [$solutionID], $cleanOptions]
);
}
}

Expand Down
70 changes: 61 additions & 9 deletions Resolver/AbstractResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,20 @@ abstract class AbstractResolver implements ResolverInterface
*/
private $solutionOptions = [];

public function addSolution($name, $solution, $options = [])
/**
* @var array
*/
private $fullyLoadedSolutions = [];

public function addSolution($name, callable $solutionFunc, array $solutionFuncArgs = [], array $options = [])
{
if (!$this->supportsSolution($solution)) {
throw new UnsupportedResolverException(
sprintf('Resolver "%s" must be "%s" "%s" given.', $name, $this->supportedSolutionClass(), get_class($solution))
);
}
$this->fullyLoadedSolutions[$name] = false;
$this->solutions[$name] = function () use ($name, $solutionFunc, $solutionFuncArgs) {
$solution = call_user_func_array($solutionFunc, $solutionFuncArgs);
$this->checkSolution($name, $solution);

$this->solutions[$name] = $solution;
return $solution;
};
$this->solutionOptions[$name] = $options;

return $this;
Expand All @@ -44,15 +49,15 @@ public function addSolution($name, $solution, $options = [])
*/
public function getSolution($name)
{
return isset($this->solutions[$name]) ? $this->solutions[$name] : null;
return isset($this->solutions[$name]) ? $this->loadSolution($name) : null;
}

/**
* @return array
*/
public function getSolutions()
{
return $this->solutions;
return $this->loadSolutions();
}

/**
Expand All @@ -65,6 +70,44 @@ public function getSolutionOptions($name)
return isset($this->solutionOptions[$name]) ? $this->solutionOptions[$name] : [];
}

/**
* @param string $name
*
* @return mixed
*/
private function loadSolution($name)
{
if ($this->fullyLoadedSolutions[$name]) {
return $this->solutions[$name];
} else {
$loader = $this->solutions[$name];
$this->solutions[$name] = $loader();
$this->fullyLoadedSolutions[$name] = true;
$this->postLoadSolution($this->solutions[$name]);

return $this->solutions[$name];
}
}

/**
* @return mixed[]
*/
private function loadSolutions()
{
foreach ($this->solutions as $name => &$solution) {
$solution = $this->loadSolution($name);
}

return $this->solutions;
}

/**
* @param mixed $solution
*/
protected function postLoadSolution($solution)
{
}

/**
* @param mixed $solution
*
Expand All @@ -77,6 +120,15 @@ protected function supportsSolution($solution)
return null === $supportedClass || $solution instanceof $supportedClass;
}

protected function checkSolution($name, $solution)
{
if (!$this->supportsSolution($solution)) {
throw new UnsupportedResolverException(
sprintf('Resolver "%s" must be "%s" "%s" given.', $name, $this->supportedSolutionClass(), get_class($solution))
);
}
}

/**
* default return null to accept mixed type.
*
Expand Down
2 changes: 1 addition & 1 deletion Resolver/ResolverInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ interface ResolverInterface
{
public function resolve($input);

public function addSolution($name, $solution, $extraOptions = []);
public function addSolution($name, callable $solutionFunc, array $solutionFuncArgs = [], array $options = []);

public function getSolution($name);

Expand Down
13 changes: 12 additions & 1 deletion Resolver/TypeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ public function resolve($alias)
$item = $this->cacheAdapter->getItem(md5($alias));

if (!$item->isHit()) {
$item->set($this->string2Type($alias));
$type = $this->string2Type($alias);
$item->set($type);
$this->cacheAdapter->save($item);
}

Expand Down Expand Up @@ -98,6 +99,16 @@ private function hasNeedListOfWrapper($alias)
return false;
}

protected function postLoadSolution($solution)
{
// also add solution with real type name if needed for typeLoader when using autoMapping
if ($solution && !isset($this->getSolutions()[$solution->name])) {
$this->addSolution($solution->name, function () use ($solution) {
return $solution;
});
}
}

protected function supportedSolutionClass()
{
return Type::class;
Expand Down
1 change: 1 addition & 0 deletions Tests/Functional/App/config/global/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ services:

overblog_graphql:
definitions:
config_validation: false
schema:
query: Query
mutation: ~
Expand Down
7 changes: 6 additions & 1 deletion Tests/Resolver/AbstractProxyResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,15 @@ abstract class AbstractProxyResolverTest extends AbstractResolverTest
protected function getResolverSolutionsMapping()
{
return [
'Toto' => ['solution' => new Toto(), 'method' => 'resolve'],
'Toto' => ['solutionFunc' => [$this, 'createToto'], 'solutionFuncArgs' => [], 'method' => 'resolve'],
];
}

public function createToto()
{
return new Toto();
}

public function testResolveKnownMutation()
{
$result = $this->resolver->resolve(['Toto', ['my', 'resolve', 'test']]);
Expand Down
2 changes: 1 addition & 1 deletion Tests/Resolver/AbstractResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public function setUp()
$this->resolver = $this->createResolver();

foreach ($this->getResolverSolutionsMapping() as $name => $options) {
$this->resolver->addSolution($name, $options['solution'], $options);
$this->resolver->addSolution($name, $options['solutionFunc'], $options['solutionFuncArgs'], $options);
}
}
}
14 changes: 11 additions & 3 deletions Tests/Resolver/TypeResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,26 @@ protected function createResolver()
protected function getResolverSolutionsMapping()
{
return [
'Toto' => ['solution' => new ObjectType(['name' => 'Toto'])],
'Tata' => ['solution' => new ObjectType(['name' => 'Tata'])],
'Toto' => ['solutionFunc' => [$this, 'createObjectType'], 'solutionFuncArgs' => [['name' => 'Toto']]],
'Tata' => ['solutionFunc' => [$this, 'createObjectType'], 'solutionFuncArgs' => [['name' => 'Tata']]],
];
}

public function createObjectType(array $config)
{
return new ObjectType($config);
}

/**
* @expectedException \Overblog\GraphQLBundle\Resolver\UnsupportedResolverException
* @expectedExceptionMessage Resolver "not-supported" must be "GraphQL\Type\Definition\Type" "stdClass" given.
*/
public function testAddNotSupportedSolution()
{
$this->resolver->addSolution('not-supported', new \stdClass());
$this->resolver->addSolution('not-supported', function () {
return new \stdClass();
});
$this->resolver->getSolution('not-supported');
}

public function testResolveKnownType()
Expand Down