Skip to content

Commit 22032e9

Browse files
authored
Merge pull request #185 from mcg-web/use-type-loader
Add support for schema typeLoader
2 parents 52ba548 + 64abad3 commit 22032e9

File tree

9 files changed

+102
-19
lines changed

9 files changed

+102
-19
lines changed

Definition/Builder/SchemaBuilder.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ public function create($queryAlias = null, $mutationAlias = null, $subscriptionA
4747
'query' => $query,
4848
'mutation' => $mutation,
4949
'subscription' => $subscription,
50-
'types' => $this->typeResolver->getSolutions(),
50+
'typeLoader' => [$this->typeResolver, 'resolve'],
51+
'types' => [$this->typeResolver, 'getSolutions'],
5152
]);
5253
if ($this->enableValidation) {
5354
$schema->assertValid();

DependencyInjection/Compiler/TaggedServiceMappingPass.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,9 @@ public function process(ContainerBuilder $container)
6161
$cleanOptions = $options;
6262
$solutionID = $options['id'];
6363

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

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

83-
$resolverDefinition->addMethodCall('addSolution', [$name, new Reference($solutionID), $cleanOptions]);
85+
$resolverDefinition->addMethodCall(
86+
'addSolution',
87+
[$name, [new Reference('service_container'), 'get'], [$solutionID], $cleanOptions]
88+
);
8489
}
8590
}
8691

Resolver/AbstractResolver.php

Lines changed: 61 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,20 @@ abstract class AbstractResolver implements ResolverInterface
2323
*/
2424
private $solutionOptions = [];
2525

26-
public function addSolution($name, $solution, $options = [])
26+
/**
27+
* @var array
28+
*/
29+
private $fullyLoadedSolutions = [];
30+
31+
public function addSolution($name, callable $solutionFunc, array $solutionFuncArgs = [], array $options = [])
2732
{
28-
if (!$this->supportsSolution($solution)) {
29-
throw new UnsupportedResolverException(
30-
sprintf('Resolver "%s" must be "%s" "%s" given.', $name, $this->supportedSolutionClass(), get_class($solution))
31-
);
32-
}
33+
$this->fullyLoadedSolutions[$name] = false;
34+
$this->solutions[$name] = function () use ($name, $solutionFunc, $solutionFuncArgs) {
35+
$solution = call_user_func_array($solutionFunc, $solutionFuncArgs);
36+
$this->checkSolution($name, $solution);
3337

34-
$this->solutions[$name] = $solution;
38+
return $solution;
39+
};
3540
$this->solutionOptions[$name] = $options;
3641

3742
return $this;
@@ -44,15 +49,15 @@ public function addSolution($name, $solution, $options = [])
4449
*/
4550
public function getSolution($name)
4651
{
47-
return isset($this->solutions[$name]) ? $this->solutions[$name] : null;
52+
return isset($this->solutions[$name]) ? $this->loadSolution($name) : null;
4853
}
4954

5055
/**
5156
* @return array
5257
*/
5358
public function getSolutions()
5459
{
55-
return $this->solutions;
60+
return $this->loadSolutions();
5661
}
5762

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

73+
/**
74+
* @param string $name
75+
*
76+
* @return mixed
77+
*/
78+
private function loadSolution($name)
79+
{
80+
if ($this->fullyLoadedSolutions[$name]) {
81+
return $this->solutions[$name];
82+
} else {
83+
$loader = $this->solutions[$name];
84+
$this->solutions[$name] = $loader();
85+
$this->fullyLoadedSolutions[$name] = true;
86+
$this->postLoadSolution($this->solutions[$name]);
87+
88+
return $this->solutions[$name];
89+
}
90+
}
91+
92+
/**
93+
* @return mixed[]
94+
*/
95+
private function loadSolutions()
96+
{
97+
foreach ($this->solutions as $name => &$solution) {
98+
$solution = $this->loadSolution($name);
99+
}
100+
101+
return $this->solutions;
102+
}
103+
104+
/**
105+
* @param mixed $solution
106+
*/
107+
protected function postLoadSolution($solution)
108+
{
109+
}
110+
68111
/**
69112
* @param mixed $solution
70113
*
@@ -77,6 +120,15 @@ protected function supportsSolution($solution)
77120
return null === $supportedClass || $solution instanceof $supportedClass;
78121
}
79122

123+
protected function checkSolution($name, $solution)
124+
{
125+
if (!$this->supportsSolution($solution)) {
126+
throw new UnsupportedResolverException(
127+
sprintf('Resolver "%s" must be "%s" "%s" given.', $name, $this->supportedSolutionClass(), get_class($solution))
128+
);
129+
}
130+
}
131+
80132
/**
81133
* default return null to accept mixed type.
82134
*

Resolver/ResolverInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ interface ResolverInterface
1515
{
1616
public function resolve($input);
1717

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

2020
public function getSolution($name);
2121

Resolver/TypeResolver.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ public function resolve($alias)
4040
$item = $this->cacheAdapter->getItem(md5($alias));
4141

4242
if (!$item->isHit()) {
43-
$item->set($this->string2Type($alias));
43+
$type = $this->string2Type($alias);
44+
$item->set($type);
4445
$this->cacheAdapter->save($item);
4546
}
4647

@@ -98,6 +99,16 @@ private function hasNeedListOfWrapper($alias)
9899
return false;
99100
}
100101

102+
protected function postLoadSolution($solution)
103+
{
104+
// also add solution with real type name if needed for typeLoader when using autoMapping
105+
if ($solution && !isset($this->getSolutions()[$solution->name])) {
106+
$this->addSolution($solution->name, function () use ($solution) {
107+
return $solution;
108+
});
109+
}
110+
}
111+
101112
protected function supportedSolutionClass()
102113
{
103114
return Type::class;

Tests/Functional/App/config/global/config.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ services:
1212

1313
overblog_graphql:
1414
definitions:
15+
config_validation: false
1516
schema:
1617
query: Query
1718
mutation: ~

Tests/Resolver/AbstractProxyResolverTest.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,15 @@ abstract class AbstractProxyResolverTest extends AbstractResolverTest
1616
protected function getResolverSolutionsMapping()
1717
{
1818
return [
19-
'Toto' => ['solution' => new Toto(), 'method' => 'resolve'],
19+
'Toto' => ['solutionFunc' => [$this, 'createToto'], 'solutionFuncArgs' => [], 'method' => 'resolve'],
2020
];
2121
}
2222

23+
public function createToto()
24+
{
25+
return new Toto();
26+
}
27+
2328
public function testResolveKnownMutation()
2429
{
2530
$result = $this->resolver->resolve(['Toto', ['my', 'resolve', 'test']]);

Tests/Resolver/AbstractResolverTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public function setUp()
2727
$this->resolver = $this->createResolver();
2828

2929
foreach ($this->getResolverSolutionsMapping() as $name => $options) {
30-
$this->resolver->addSolution($name, $options['solution'], $options);
30+
$this->resolver->addSolution($name, $options['solutionFunc'], $options['solutionFuncArgs'], $options);
3131
}
3232
}
3333
}

Tests/Resolver/TypeResolverTest.php

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,26 @@ protected function createResolver()
2626
protected function getResolverSolutionsMapping()
2727
{
2828
return [
29-
'Toto' => ['solution' => new ObjectType(['name' => 'Toto'])],
30-
'Tata' => ['solution' => new ObjectType(['name' => 'Tata'])],
29+
'Toto' => ['solutionFunc' => [$this, 'createObjectType'], 'solutionFuncArgs' => [['name' => 'Toto']]],
30+
'Tata' => ['solutionFunc' => [$this, 'createObjectType'], 'solutionFuncArgs' => [['name' => 'Tata']]],
3131
];
3232
}
3333

34+
public function createObjectType(array $config)
35+
{
36+
return new ObjectType($config);
37+
}
38+
3439
/**
3540
* @expectedException \Overblog\GraphQLBundle\Resolver\UnsupportedResolverException
3641
* @expectedExceptionMessage Resolver "not-supported" must be "GraphQL\Type\Definition\Type" "stdClass" given.
3742
*/
3843
public function testAddNotSupportedSolution()
3944
{
40-
$this->resolver->addSolution('not-supported', new \stdClass());
45+
$this->resolver->addSolution('not-supported', function () {
46+
return new \stdClass();
47+
});
48+
$this->resolver->getSolution('not-supported');
4149
}
4250

4351
public function testResolveKnownType()

0 commit comments

Comments
 (0)