Skip to content

Commit 1501383

Browse files
authored
feat: allow executor plugin to work with older webonyx graphql versions (#2)
1 parent ac11011 commit 1501383

File tree

3 files changed

+101
-40
lines changed

3 files changed

+101
-40
lines changed

Executor/ReferenceExecutor.php

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
3+
namespace Graycore\GraphQlIntrospectionCache\Executor;
4+
5+
use GraphQL\Executor\ExecutionContext;
6+
use GraphQL\Executor\ExecutionResult;
7+
use GraphQL\Executor\ExecutorImplementation;
8+
use GraphQL\Executor\Promise\Promise;
9+
use GraphQL\Executor\Promise\PromiseAdapter;
10+
use GraphQL\Language\AST\DocumentNode;
11+
use GraphQL\Type\Schema;
12+
use GraphQL\Utils\Utils;
13+
use Magento\Framework\App\ObjectManager;
14+
use ReflectionMethod;
15+
use ReflectionProperty;
16+
use SplObjectStorage;
17+
18+
class ReferenceExecutor extends \GraphQL\Executor\ReferenceExecutor
19+
{
20+
private static ?self $executorInstance = null;
21+
22+
protected function __construct(ExecutionContext $context)
23+
{
24+
if (is_callable('parent::__construct')) {
25+
parent::__construct($context);
26+
} else {
27+
$this->setExecutorPrivateProp('UNDEFINED', Utils::undefined(), true);
28+
$this->setExecutorPrivateProp('exeContext', $context);
29+
$this->setExecutorPrivateProp('subFieldCache', new SplObjectStorage());
30+
}
31+
}
32+
33+
private function setExecutorPrivateProp(string $property, $value, bool $static = false): void
34+
{
35+
try {
36+
$reflectionProperty = new ReflectionProperty(\GraphQL\Executor\ReferenceExecutor::class, $property);
37+
$reflectionProperty->setAccessible(true);
38+
$reflectionProperty->setValue($static ? null : $this, $value);
39+
} catch (\ReflectionException $e) {}
40+
}
41+
42+
public static function create(
43+
PromiseAdapter $promiseAdapter,
44+
Schema $schema,
45+
DocumentNode $documentNode,
46+
$rootValue,
47+
$contextValue,
48+
$variableValues,
49+
?string $operationName,
50+
callable $fieldResolver
51+
) : ExecutorImplementation {
52+
if (self::$executorInstance !== null) {
53+
return self::$executorInstance;
54+
}
55+
56+
$reflectionMethod = new ReflectionMethod(\GraphQL\Executor\ReferenceExecutor::class, 'buildExecutionContext');
57+
if ($reflectionMethod->isPrivate()) {
58+
$reflectionMethod->setAccessible(true);
59+
}
60+
61+
$exeContext = $reflectionMethod->invoke(
62+
null,
63+
$schema,
64+
$documentNode,
65+
$rootValue,
66+
$contextValue,
67+
$variableValues,
68+
$operationName,
69+
$fieldResolver,
70+
$promiseAdapter
71+
);
72+
73+
if (is_array($exeContext)) {
74+
$promise = $promiseAdapter->createFulfilled(new ExecutionResult(null, $exeContext));
75+
return new class($promise) implements ExecutorImplementation
76+
{
77+
private Promise $result;
78+
79+
public function __construct(Promise $result)
80+
{
81+
$this->result = $result;
82+
}
83+
84+
public function doExecute() : Promise
85+
{
86+
return $this->result;
87+
}
88+
};
89+
}
90+
91+
return self::$executorInstance = ObjectManager::getInstance()->create(
92+
ReferenceExecutor::class,
93+
['context' => $exeContext]
94+
);
95+
}
96+
}

Plugin/ExecutorPlugin.php

+2-40
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,12 @@
22

33
namespace Graycore\GraphQlIntrospectionCache\Plugin;
44

5-
use Closure;
65
use GraphQL\Executor\Executor;
7-
use GraphQL\Executor\ReferenceExecutor;
6+
use Graycore\GraphQlIntrospectionCache\Executor\ReferenceExecutor;
87
use Magento\Framework\GraphQl\Query\QueryProcessor;
9-
use Magento\Framework\ObjectManagerInterface;
108

119
class ExecutorPlugin
1210
{
13-
private ObjectManagerInterface $objectManager;
14-
15-
public function __construct(ObjectManagerInterface $objectManager)
16-
{
17-
$this->objectManager = $objectManager;
18-
}
19-
2011
/**
2112
* Before processing a GraphQL query, replace the factory with a wrapper that uses the object manager.
2213
* This allows us to create plugins on the ReferenceExecutor.
@@ -25,36 +16,7 @@ public function beforeProcess(
2516
QueryProcessor $subject,
2617
...$args
2718
): array {
28-
Executor::setImplementationFactory(
29-
fn(
30-
$promiseAdapter,
31-
$schema,
32-
$documentNode,
33-
$rootValue,
34-
$contextValue,
35-
$variableValues,
36-
$operationName,
37-
$fieldResolver
38-
) => $this->objectManager->create(
39-
ReferenceExecutor::class,
40-
[
41-
'context' => Closure::bind(
42-
fn() => ReferenceExecutor::buildExecutionContext(
43-
$schema,
44-
$documentNode,
45-
$rootValue,
46-
$contextValue,
47-
$variableValues,
48-
$operationName,
49-
$fieldResolver,
50-
$promiseAdapter
51-
),
52-
null,
53-
ReferenceExecutor::class
54-
)()
55-
]
56-
)
57-
);
19+
Executor::setImplementationFactory([ReferenceExecutor::class, 'create']);
5820
return $args;
5921
}
6022
}

Test/Integration/CachedQueryTest.php

+3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
use PHPUnit\Framework\TestCase;
1010
use Magento\TestFramework\ObjectManager;
1111

12+
/**
13+
* @magentoAppArea graphql
14+
*/
1215
class CachedQueryTest extends TestCase
1316
{
1417
private $om;

0 commit comments

Comments
 (0)