Skip to content

Commit a20e8d8

Browse files
committed
Migrating ParameterHandler to a middleware system
Currently the ParmeterHandlerInterface only allows for a handler to handle or not handle a parameter. There is no way a ParameterHandler can "wrap" othe parameter handlers. So there is no easy way to write a ParameterHandler that does validation upon the result of other parameter handlers. This commit moves ParameterMapperInterface to a system of ParameterMiddlewareInterface where parameter middlewares are chained. We therefore get all the benefits of middlewares when handling parameters.
1 parent 48c50e5 commit a20e8d8

19 files changed

+195
-158
lines changed

src/FieldsBuilder.php

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
use TheCodingMachine\GraphQLite\Annotations\SourceFieldInterface;
1818
use TheCodingMachine\GraphQLite\Mappers\CannotMapTypeException;
1919
use TheCodingMachine\GraphQLite\Mappers\CannotMapTypeExceptionInterface;
20-
use TheCodingMachine\GraphQLite\Mappers\Parameters\ParameterMapperInterface;
21-
use TheCodingMachine\GraphQLite\Mappers\Parameters\TypeMapper;
20+
use TheCodingMachine\GraphQLite\Mappers\Parameters\ParameterMiddlewareInterface;
21+
use TheCodingMachine\GraphQLite\Mappers\Parameters\TypeHandler;
2222
use TheCodingMachine\GraphQLite\Mappers\RecursiveTypeMapperInterface;
2323
use TheCodingMachine\GraphQLite\Mappers\Root\RootTypeMapperInterface;
2424
use TheCodingMachine\GraphQLite\Middlewares\FieldHandlerInterface;
@@ -49,9 +49,9 @@ class FieldsBuilder
4949
private $typeResolver;
5050
/** @var NamingStrategyInterface */
5151
private $namingStrategy;
52-
/** @var TypeMapper */
52+
/** @var TypeHandler */
5353
private $typeMapper;
54-
/** @var ParameterMapperInterface */
54+
/** @var ParameterMiddlewareInterface */
5555
private $parameterMapper;
5656
/** @var FieldMiddlewareInterface */
5757
private $fieldMiddleware;
@@ -64,15 +64,15 @@ public function __construct(
6464
CachedDocBlockFactory $cachedDocBlockFactory,
6565
NamingStrategyInterface $namingStrategy,
6666
RootTypeMapperInterface $rootTypeMapper,
67-
ParameterMapperInterface $parameterMapper,
67+
ParameterMiddlewareInterface $parameterMapper,
6868
FieldMiddlewareInterface $fieldMiddleware
6969
) {
7070
$this->annotationReader = $annotationReader;
7171
$this->recursiveTypeMapper = $typeMapper;
7272
$this->typeResolver = $typeResolver;
7373
$this->cachedDocBlockFactory = $cachedDocBlockFactory;
7474
$this->namingStrategy = $namingStrategy;
75-
$this->typeMapper = new TypeMapper($typeMapper, $argumentResolver, $rootTypeMapper, $typeResolver);
75+
$this->typeMapper = new TypeHandler($typeMapper, $argumentResolver, $rootTypeMapper, $typeResolver);
7676
$this->parameterMapper = $parameterMapper;
7777
$this->fieldMiddleware = $fieldMiddleware;
7878
}
@@ -480,11 +480,8 @@ private function mapParameters(array $refParameters, DocBlock $docBlock): array
480480
foreach ($refParameters as $parameter) {
481481
$parameterAnnotations = $this->annotationReader->getParameterAnnotations($parameter);
482482

483-
$parameterObj = $this->parameterMapper->mapParameter($parameter, $docBlock, $docBlockTypes[$parameter->getName()] ?? null, $parameterAnnotations);
483+
$parameterObj = $this->parameterMapper->mapParameter($parameter, $docBlock, $docBlockTypes[$parameter->getName()] ?? null, $parameterAnnotations, $this->typeMapper);
484484

485-
if ($parameterObj === null) {
486-
$parameterObj = $this->typeMapper->mapParameter($parameter, $docBlock, $docBlockTypes[$parameter->getName()] ?? null, $parameterAnnotations);
487-
}
488485
$args[$parameter->getName()] = $parameterObj;
489486
}
490487

src/Mappers/Parameters/CompositeParameterMapper.php

Lines changed: 0 additions & 39 deletions
This file was deleted.

src/Mappers/Parameters/ContainerParameterMapper.php renamed to src/Mappers/Parameters/ContainerParameterHandler.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
/**
1717
* Maps parameters with the \@Autowire annotation to container entry based on the FQCN or the passed identifier.
1818
*/
19-
class ContainerParameterMapper implements ParameterMapperInterface
19+
class ContainerParameterHandler implements ParameterMiddlewareInterface
2020
{
2121
/** @var ContainerInterface */
2222
private $container;
@@ -26,15 +26,15 @@ public function __construct(ContainerInterface $container)
2626
$this->container = $container;
2727
}
2828

29-
public function mapParameter(ReflectionParameter $parameter, DocBlock $docBlock, ?Type $paramTagType, ParameterAnnotations $parameterAnnotations): ?ParameterInterface
29+
public function mapParameter(ReflectionParameter $parameter, DocBlock $docBlock, ?Type $paramTagType, ParameterAnnotations $parameterAnnotations, ParameterHandlerInterface $next): ParameterInterface
3030
{
3131
/**
3232
* @var Autowire|null $autowire
3333
*/
3434
$autowire = $parameterAnnotations->getAnnotationByType(Autowire::class);
3535

3636
if ($autowire === null) {
37-
return null;
37+
return $next->mapParameter($parameter, $docBlock, $paramTagType, $parameterAnnotations);
3838
}
3939

4040
$id = $autowire->getIdentifier();

src/Mappers/Parameters/Next.php

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TheCodingMachine\GraphQLite\Mappers\Parameters;
6+
7+
use phpDocumentor\Reflection\DocBlock;
8+
use phpDocumentor\Reflection\Type;
9+
use ReflectionParameter;
10+
use SplQueue;
11+
use TheCodingMachine\GraphQLite\Annotations\ParameterAnnotations;
12+
use TheCodingMachine\GraphQLite\Parameters\ParameterInterface;
13+
14+
/**
15+
* Iterate a queue of middlewares and execute them.
16+
*/
17+
final class Next implements ParameterHandlerInterface
18+
{
19+
/** @var ParameterHandlerInterface */
20+
private $fallbackHandler;
21+
22+
/** @var SplQueue */
23+
private $queue;
24+
25+
/**
26+
* Clones the queue provided to allow re-use.
27+
*
28+
* @param ParameterHandlerInterface $fallbackHandler Fallback handler to
29+
* invoke when the queue is exhausted.
30+
*/
31+
public function __construct(SplQueue $queue, ParameterHandlerInterface $fallbackHandler)
32+
{
33+
$this->queue = clone $queue;
34+
$this->fallbackHandler = $fallbackHandler;
35+
}
36+
37+
public function mapParameter(ReflectionParameter $parameter, DocBlock $docBlock, ?Type $paramTagType, ParameterAnnotations $parameterAnnotations): ParameterInterface
38+
{
39+
if ($this->queue->isEmpty()) {
40+
return $this->fallbackHandler->mapParameter($parameter, $docBlock, $paramTagType, $parameterAnnotations);
41+
}
42+
43+
/**
44+
* @var ParameterMiddlewareInterface $middleware
45+
*/
46+
$middleware = $this->queue->dequeue();
47+
48+
return $middleware->mapParameter($parameter, $docBlock, $paramTagType, $parameterAnnotations, $this);
49+
}
50+
}

src/Mappers/Parameters/ParameterMapperInterface.php renamed to src/Mappers/Parameters/ParameterHandlerInterface.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
use TheCodingMachine\GraphQLite\Annotations\ParameterAnnotations;
1111
use TheCodingMachine\GraphQLite\Parameters\ParameterInterface;
1212

13-
interface ParameterMapperInterface
13+
interface ParameterHandlerInterface
1414
{
15-
public function mapParameter(ReflectionParameter $parameter, DocBlock $docBlock, ?Type $paramTagType, ParameterAnnotations $parameterAnnotations): ?ParameterInterface;
15+
public function mapParameter(ReflectionParameter $parameter, DocBlock $docBlock, ?Type $paramTagType, ParameterAnnotations $parameterAnnotations): ParameterInterface;
1616
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TheCodingMachine\GraphQLite\Mappers\Parameters;
6+
7+
use phpDocumentor\Reflection\DocBlock;
8+
use phpDocumentor\Reflection\Type;
9+
use ReflectionParameter;
10+
use TheCodingMachine\GraphQLite\Annotations\ParameterAnnotations;
11+
use TheCodingMachine\GraphQLite\Parameters\ParameterInterface;
12+
13+
/**
14+
* Processes a parameter for a given query/mutation/field/factory.
15+
*/
16+
interface ParameterMiddlewareInterface
17+
{
18+
public function mapParameter(ReflectionParameter $parameter, DocBlock $docBlock, ?Type $paramTagType, ParameterAnnotations $parameterAnnotations, ParameterHandlerInterface $next): ParameterInterface;
19+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TheCodingMachine\GraphQLite\Mappers\Parameters;
6+
7+
use phpDocumentor\Reflection\DocBlock;
8+
use phpDocumentor\Reflection\Type;
9+
use ReflectionParameter;
10+
use SplQueue;
11+
use TheCodingMachine\GraphQLite\Annotations\ParameterAnnotations;
12+
use TheCodingMachine\GraphQLite\Parameters\ParameterInterface;
13+
14+
final class ParameterMiddlewarePipe implements ParameterMiddlewareInterface
15+
{
16+
/** @var SplQueue<ParameterMiddlewareInterface> */
17+
private $pipeline;
18+
19+
/**
20+
* Initializes the queue.
21+
*/
22+
public function __construct()
23+
{
24+
$this->pipeline = new SplQueue();
25+
}
26+
27+
/**
28+
* PSR-15 middleware invocation.
29+
*
30+
* Executes the internal pipeline, passing $handler as the "final
31+
* handler" in cases when the pipeline exhausts itself.
32+
*/
33+
public function mapParameter(ReflectionParameter $parameter, DocBlock $docBlock, ?Type $paramTagType, ParameterAnnotations $parameterAnnotations, ParameterHandlerInterface $parameterMapper): ParameterInterface
34+
{
35+
return (new Next($this->pipeline, $parameterMapper))->mapParameter($parameter, $docBlock, $paramTagType, $parameterAnnotations);
36+
}
37+
38+
/**
39+
* Attach middleware to the pipeline.
40+
*/
41+
public function pipe(ParameterMiddlewareInterface $middleware): void
42+
{
43+
$this->pipeline->enqueue($middleware);
44+
}
45+
}

src/Mappers/Parameters/ResolveInfoParameterMapper.php renamed to src/Mappers/Parameters/ResolveInfoParameterHandler.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@
1212
use TheCodingMachine\GraphQLite\Parameters\ParameterInterface;
1313
use TheCodingMachine\GraphQLite\Parameters\ResolveInfoParameter;
1414

15-
class ResolveInfoParameterMapper implements ParameterMapperInterface
15+
class ResolveInfoParameterHandler implements ParameterMiddlewareInterface
1616
{
17-
public function mapParameter(ReflectionParameter $parameter, DocBlock $docBlock, ?Type $paramTagType, ParameterAnnotations $parameterAnnotations): ?ParameterInterface
17+
public function mapParameter(ReflectionParameter $parameter, DocBlock $docBlock, ?Type $paramTagType, ParameterAnnotations $parameterAnnotations, ParameterHandlerInterface $parameterMapper): ParameterInterface
1818
{
1919
$type = $parameter->getType();
2020
if ($type!== null && $type->getName() === ResolveInfo::class) {
2121
return new ResolveInfoParameter();
2222
}
2323

24-
return null;
24+
return $parameterMapper->mapParameter($parameter, $docBlock, $paramTagType, $parameterAnnotations);
2525
}
2626
}

src/Mappers/Parameters/TypeMapper.php renamed to src/Mappers/Parameters/TypeHandler.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
use function count;
4949
use function iterator_to_array;
5050

51-
class TypeMapper implements ParameterMapperInterface
51+
class TypeHandler implements ParameterHandlerInterface
5252
{
5353
/** @var PhpDocumentorTypeResolver */
5454
private $phpDocumentorTypeResolver;

src/Parameters/ParameterInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use GraphQL\Type\Definition\ResolveInfo;
88

99
/**
10-
* Instances of ParameterInterface represent a single PHP parameter in a Query/Mutation/Field.
10+
* Instances of ParameterInterface represent a single PHP parameter in a Query/Mutation/Field/Factory.
1111
*/
1212
interface ParameterInterface
1313
{

src/SchemaFactory.php

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@
1818
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
1919
use TheCodingMachine\GraphQLite\Mappers\CompositeTypeMapper;
2020
use TheCodingMachine\GraphQLite\Mappers\GlobTypeMapper;
21-
use TheCodingMachine\GraphQLite\Mappers\Parameters\CompositeParameterMapper;
22-
use TheCodingMachine\GraphQLite\Mappers\Parameters\ContainerParameterMapper;
23-
use TheCodingMachine\GraphQLite\Mappers\Parameters\ParameterMapperInterface;
24-
use TheCodingMachine\GraphQLite\Mappers\Parameters\ResolveInfoParameterMapper;
21+
use TheCodingMachine\GraphQLite\Mappers\Parameters\ContainerParameterHandler;
22+
use TheCodingMachine\GraphQLite\Mappers\Parameters\ParameterMiddlewareInterface;
23+
use TheCodingMachine\GraphQLite\Mappers\Parameters\ParameterMiddlewarePipe;
24+
use TheCodingMachine\GraphQLite\Mappers\Parameters\ResolveInfoParameterHandler;
2525
use TheCodingMachine\GraphQLite\Mappers\PorpaginasTypeMapper;
2626
use TheCodingMachine\GraphQLite\Mappers\RecursiveTypeMapper;
2727
use TheCodingMachine\GraphQLite\Mappers\Root\BaseTypeMapper;
@@ -69,7 +69,7 @@ class SchemaFactory
6969
private $typeMappers = [];
7070
/** @var TypeMapperFactoryInterface[] */
7171
private $typeMapperFactories = [];
72-
/** @var ParameterMapperInterface[] */
72+
/** @var ParameterMiddlewareInterface[] */
7373
private $parameterMappers = [];
7474
/** @var Reader */
7575
private $doctrineAnnotationReader;
@@ -171,7 +171,7 @@ public function addTypeMapperFactory(TypeMapperFactoryInterface $typeMapperFacto
171171
/**
172172
* Registers a parameter mapper.
173173
*/
174-
public function addParameterMapper(ParameterMapperInterface $parameterMapper): self
174+
public function addParameterMapper(ParameterMiddlewareInterface $parameterMapper): self
175175
{
176176
$this->parameterMappers[] = $parameterMapper;
177177

@@ -322,10 +322,12 @@ public function createSchema(): Schema
322322

323323
$argumentResolver = new ArgumentResolver();
324324

325-
$parameterMappers = $this->parameterMappers;
326-
$parameterMappers[] = new ResolveInfoParameterMapper();
327-
$parameterMappers[] = new ContainerParameterMapper($this->container);
328-
$compositeParameterMapper = new CompositeParameterMapper($parameterMappers);
325+
$parameterMiddlewarePipe = new ParameterMiddlewarePipe();
326+
foreach ($this->parameterMappers as $parameterMapper) {
327+
$parameterMiddlewarePipe->pipe($parameterMapper);
328+
}
329+
$parameterMiddlewarePipe->pipe(new ResolveInfoParameterHandler());
330+
$parameterMiddlewarePipe->pipe(new ContainerParameterHandler($this->container));
329331

330332
$fieldsBuilder = new FieldsBuilder(
331333
$annotationReader,
@@ -335,7 +337,7 @@ public function createSchema(): Schema
335337
$cachedDocBlockFactory,
336338
$namingStrategy,
337339
$compositeRootTypeMapper,
338-
$compositeParameterMapper,
340+
$parameterMiddlewarePipe,
339341
$fieldMiddlewarePipe
340342
);
341343

0 commit comments

Comments
 (0)