Skip to content

Commit 8c44ae3

Browse files
authored
Merge pull request #27 from moufmouf/inject_request
Adding the ability to type-hint on a Symfony request
2 parents ef21afb + e0191cc commit 8c44ae3

File tree

10 files changed

+170
-16
lines changed

10 files changed

+170
-16
lines changed

Context/SymfonyGraphQLContext.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
4+
namespace TheCodingMachine\Graphqlite\Bundle\Context;
5+
6+
7+
use Symfony\Component\HttpFoundation\Request;
8+
9+
class SymfonyGraphQLContext implements SymfonyRequestContextInterface
10+
{
11+
/**
12+
* @var Request
13+
*/
14+
private $request;
15+
16+
public function __construct(Request $request)
17+
{
18+
$this->request = $request;
19+
}
20+
21+
/**
22+
* @return Request
23+
*/
24+
public function getRequest(): Request
25+
{
26+
return $this->request;
27+
}
28+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace TheCodingMachine\Graphqlite\Bundle\Context;
4+
5+
use Symfony\Component\HttpFoundation\Request;
6+
7+
interface SymfonyRequestContextInterface
8+
{
9+
/**
10+
* @return Request
11+
*/
12+
public function getRequest(): Request;
13+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
4+
namespace TheCodingMachine\Graphqlite\Bundle\Controller\GraphQL;
5+
6+
7+
class InvalidUserPasswordException
8+
{
9+
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
4+
namespace TheCodingMachine\Graphqlite\Bundle\Controller\GraphQL;
5+
6+
7+
class LoginController
8+
{
9+
10+
}

Controller/GraphqliteController.php

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use GraphQL\Error\Error;
1111
use GraphQL\Executor\ExecutionResult;
1212
use GraphQL\Executor\Promise\Promise;
13+
use GraphQL\Server\ServerConfig;
1314
use GraphQL\Server\StandardServer;
1415
use GraphQL\Upload\UploadMiddleware;
1516
use function in_array;
@@ -27,6 +28,7 @@
2728
use Symfony\Component\HttpKernel\KernelEvents;
2829
use Symfony\Component\Routing\Route;
2930
use Symfony\Component\Routing\RouteCollection;
31+
use TheCodingMachine\Graphqlite\Bundle\Context\SymfonyGraphQLContext;
3032

3133
/**
3234
* Listens to every single request and forward Graphql requests to Graphql Webonix standardServer.
@@ -37,14 +39,16 @@ class GraphqliteController
3739
* @var HttpMessageFactoryInterface
3840
*/
3941
private $httpMessageFactory;
40-
/** @var StandardServer */
41-
private $standardServer;
4242
/** @var bool|int */
4343
private $debug;
44+
/**
45+
* @var ServerConfig
46+
*/
47+
private $serverConfig;
4448

45-
public function __construct(StandardServer $standardServer, HttpMessageFactoryInterface $httpMessageFactory = null, ?int $debug = Debug::RETHROW_UNSAFE_EXCEPTIONS)
49+
public function __construct(ServerConfig $serverConfig, HttpMessageFactoryInterface $httpMessageFactory = null, ?int $debug = Debug::RETHROW_UNSAFE_EXCEPTIONS)
4650
{
47-
$this->standardServer = $standardServer;
51+
$this->serverConfig = $serverConfig;
4852
$this->httpMessageFactory = $httpMessageFactory ?: new DiactorosFactory();
4953
$this->debug = $debug ?? false;
5054
}
@@ -84,12 +88,17 @@ public function handleRequest(Request $request): Response
8488
$uploadMiddleware = new UploadMiddleware();
8589
$psr7Request = $uploadMiddleware->processRequest($psr7Request);
8690

87-
return $this->handlePsr7Request($psr7Request);
91+
return $this->handlePsr7Request($psr7Request, $request);
8892
}
8993

90-
private function handlePsr7Request(ServerRequestInterface $request): JsonResponse
94+
private function handlePsr7Request(ServerRequestInterface $request, Request $symfonyRequest): JsonResponse
9195
{
92-
$result = $this->standardServer->executePsrRequest($request);
96+
// Let's put the request in the context.
97+
$serverConfig = clone $this->serverConfig;
98+
$serverConfig->setContext(new SymfonyGraphQLContext($symfonyRequest));
99+
100+
$standardService = new StandardServer($serverConfig);
101+
$result = $standardService->executePsrRequest($request);
93102

94103
if ($result instanceof ExecutionResult) {
95104
return new JsonResponse($result->toArray($this->debug), $this->decideHttpStatusCode($result));

Mappers/RequestParameter.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
4+
namespace TheCodingMachine\Graphqlite\Bundle\Mappers;
5+
6+
7+
use GraphQL\Type\Definition\ResolveInfo;
8+
use TheCodingMachine\Graphqlite\Bundle\Context\SymfonyRequestContextInterface;
9+
use TheCodingMachine\GraphQLite\GraphQLException;
10+
use TheCodingMachine\GraphQLite\Parameters\ParameterInterface;
11+
12+
class RequestParameter implements ParameterInterface
13+
{
14+
15+
/**
16+
* @param array<string, mixed> $args
17+
* @param mixed $context
18+
*
19+
* @return mixed
20+
*/
21+
public function resolve(?object $source, array $args, $context, ResolveInfo $info)
22+
{
23+
if (!$context instanceof SymfonyRequestContextInterface) {
24+
throw new GraphQLException('Cannot type-hint on a Symfony Request object in your query/mutation/field. The request context must implement SymfonyRequestContextInterface.');
25+
}
26+
return $context->getRequest();
27+
}
28+
}

Mappers/RequestParameterMapper.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
4+
namespace TheCodingMachine\Graphqlite\Bundle\Mappers;
5+
6+
7+
use phpDocumentor\Reflection\DocBlock;
8+
use phpDocumentor\Reflection\Type;
9+
use ReflectionParameter;
10+
use Symfony\Component\HttpFoundation\Request;
11+
use TheCodingMachine\GraphQLite\Annotations\ParameterAnnotations;
12+
use TheCodingMachine\GraphQLite\Mappers\Parameters\ParameterMapperInterface;
13+
use TheCodingMachine\GraphQLite\Parameters\ParameterInterface;
14+
15+
class RequestParameterMapper implements ParameterMapperInterface
16+
{
17+
18+
public function mapParameter(ReflectionParameter $parameter, DocBlock $docBlock, ?Type $paramTagType, ParameterAnnotations $parameterAnnotations): ?ParameterInterface
19+
{
20+
if ($parameter->getType()->getName() === Request::class) {
21+
return new RequestParameter();
22+
}
23+
return null;
24+
}
25+
}

Resources/config/container/graphqlite.xml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,6 @@
4747

4848
<service id="TheCodingMachine\GraphQLite\Security\AuthorizationServiceInterface" alias="TheCodingMachine\Graphqlite\Bundle\Security\AuthorizationService" />
4949

50-
<service id="GraphQL\Server\StandardServer">
51-
<argument type="service" id="GraphQL\Server\ServerConfig" />
52-
</service>
53-
5450
<service id="GraphQL\Server\ServerConfig">
5551
<call method="setSchema">
5652
<argument type="service" id="TheCodingMachine\GraphQLite\Schema"/>
@@ -62,6 +58,10 @@
6258
</service>
6359

6460
<service id="TheCodingMachine\Graphqlite\Bundle\Controller\GraphqliteController" public="true" />
61+
62+
<service id="TheCodingMachine\Graphqlite\Bundle\Mappers\RequestParameterMapper">
63+
<tag name="graphql.parameter_mapper"/>
64+
</service>
6565
</services>
6666

6767
</container>

Tests/Fixtures/Controller/TestGraphqlController.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use GraphQL\Error\Error;
88
use Porpaginas\Arrays\ArrayResult;
9+
use Symfony\Component\HttpFoundation\Request;
910
use TheCodingMachine\GraphQLite\Annotations\FailWith;
1011
use TheCodingMachine\GraphQLite\Annotations\Logged;
1112
use TheCodingMachine\GraphQLite\Annotations\Right;
@@ -102,4 +103,13 @@ public function withUserRight(): string
102103
{
103104
return 'foo';
104105
}
106+
107+
/**
108+
* @Query()
109+
* @return string
110+
*/
111+
public function getUri(Request $request): string
112+
{
113+
return $request->getPathInfo();
114+
}
105115
}

Tests/FunctionalTest.php

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
class FunctionalTest extends TestCase
1919
{
20-
public function testServiceWiring()
20+
public function testServiceWiring(): void
2121
{
2222
$kernel = new GraphqliteTestingKernel('test', true);
2323
$kernel->boot();
@@ -68,7 +68,7 @@ public function testServiceWiring()
6868
], $result);
6969
}
7070

71-
public function testServiceAutowiring()
71+
public function testServiceAutowiring(): void
7272
{
7373
$kernel = new GraphqliteTestingKernel('test', true);
7474
$kernel->boot();
@@ -98,7 +98,7 @@ public function testServiceAutowiring()
9898
], $result);
9999
}
100100

101-
public function testErrors()
101+
public function testErrors(): void
102102
{
103103
$kernel = new GraphqliteTestingKernel('test', true);
104104
$kernel->boot();
@@ -134,7 +134,7 @@ public function testErrors()
134134
$this->assertSame(404, $response->getStatusCode(), $response->getContent());
135135
}
136136

137-
public function testLoggedMiddleware()
137+
public function testLoggedMiddleware(): void
138138
{
139139
$kernel = new GraphqliteTestingKernel('test', true);
140140
$kernel->boot();
@@ -155,7 +155,7 @@ public function testLoggedMiddleware()
155155
], $result);
156156
}
157157

158-
public function testLoggedMiddleware2()
158+
public function testLoggedMiddleware2(): void
159159
{
160160
$kernel = new GraphqliteTestingKernel('test', true);
161161
$kernel->boot();
@@ -185,6 +185,27 @@ public function testLoggedMiddleware2()
185185

186186
}
187187

188+
public function testInjectQuery(): void
189+
{
190+
$kernel = new GraphqliteTestingKernel('test', true);
191+
$kernel->boot();
192+
193+
$request = Request::create('/graphql', 'GET', ['query' => '
194+
{
195+
uri
196+
}']);
197+
198+
$response = $kernel->handle($request);
199+
200+
$result = json_decode($response->getContent(), true);
201+
202+
$this->assertSame([
203+
'data' => [
204+
'uri' => '/graphql'
205+
]
206+
], $result);
207+
}
208+
188209
private function logIn(ContainerInterface $container)
189210
{
190211
// put a token into the storage so the final calls can function

0 commit comments

Comments
 (0)