Rather than using a HandlerFactory
with specific methods for creating each individual handler type, have you considered either just creating the handlers within the DynamoMethodListener
directly or maybe modifying the HandlerFactory
to return an array of handlers? Right now the HandlerFactory
doesn't provide a ton of value (aside from potentially mock-ability within tests) and is IMO too aware of all of the possible implementations of handlers.
Current Implementation
$handlers = [
$this->handlerFactory->baseUrl($methodModel, $methodBodyBuilder, $annotations),
$this->handlerFactory->serializationContext($methodModel, $methodBodyBuilder, $annotations),
$this->handlerFactory->requestUrl($methodModel, $methodBodyBuilder, $annotations),
$this->handlerFactory->requestHeader($methodModel, $methodBodyBuilder, $annotations),
$this->handlerFactory->requestBody($methodModel, $methodBodyBuilder, $annotations),
$this->handlerFactory->returns($methodModel, $methodBodyBuilder, $annotations),
$this->handlerFactory->asyncCallback($methodModel, $methodBodyBuilder, $annotations),
];
Option A
Create the handlers inline. This would remove the necessity of the factory entirely.
$handlers = [
new BaseUrlHandler($methodModel, $methodBodyBuilder, $annotations),
new SerializationContextHandler($methodModel, $methodBodyBuilder, $annotations),
new RequestUrlHandler($methodModel, $methodBodyBuilder, $annotations),
new RequestHeaderHandler($methodModel, $methodBodyBuilder, $annotations),
new RequestBodyHandler($methodModel, $methodBodyBuilder, $annotations),
new ReturnHandler($methodModel, $methodBodyBuilder, $annotations),
new AsyncHandler($methodModel, $methodBodyBuilder, $annotations),
];
Option B
Make the handler factory responsible for creating the handlers. With this approach, the listener doesn't know or care what type of handlers are handling the class.
$handlers = $this->handlerFactory->create($methodModel, $methodBodyBuilder, $annotations);
Option C
Allow for stateless handlers. This would be quite a bit more of a refactor, but you could change the abstract Handler
into a HandlerInterface
...
<?php
namespace Tebru\Retrofit\Generation\Handler;
interface HandlerInterface
{
/**
* @param MethodModel $methodModel
* @param MethodBodyBuilder $methodBodyBuilder
* @param AnnotationCollection $annotations
*/
public function handle(MethodModel $methodModel, MethodBodyBuilder $methodBodyBuilder, AnnotationCollection $annotations);
}
Then you could inject an array of HandlerInterface
's into your listener and delegate accordingly.
<?php
namespace Tebru\Retrofit\Generation\Listener;
use Tebru\Dynamo\Event\MethodEvent;
use Tebru\Retrofit\Generation\Builder\Factory\MethodBodyBuilderFactory;
use Tebru\Retrofit\Generation\Handler\HandlerInterface;
class DynamoMethodListener
{
/**
* @var HandlerInterface[]
*/
private $handlers;
/**
* Creates a new method body builder
*
* @var MethodBodyBuilderFactory
*/
private $methodBodyBuilderFactory;
/**
* Constructor
*
* @param HandlerInterface[] $handlers
* @param MethodBodyBuilderFactory $methodBodyBuilderFactory
*/
public function __construct(array $handlers, MethodBodyBuilderFactory $methodBodyBuilderFactory)
{
$this->handlers = $handlers;
$this->methodBodyBuilderFactory = $methodBodyBuilderFactory;
}
/**
* Handler the event
*
* @param MethodEvent $event
*/
public function __invoke(MethodEvent $event)
{
$methodModel = $event->getMethodModel();
$annotations = $event->getAnnotationCollection();
$methodBodyBuilder = $this->methodBodyBuilderFactory->make();
foreach ($this->handlers as $handler) {
$handler->handle($methodModel, $methodBodyBuilder, $annotations);
}
$body = $methodBodyBuilder->build();
$methodModel->setBody($body);
}
}
Option D
Create an aggregate method handler. This wouldn't require a major refactor, but could help keep the method listener simpler. The listener would create a single handler, which would be responsible for creating and calling the other handlers. I haven't fully thought this one through yet...
<?php
namespace Tebru\Retrofit\Generation\Handler;
class MethodHandler
{
/**
* @var Handler[]
*/
private $handlers;
/**
* @param MethodModel $methodModel
* @param MethodBodyBuilder $methodBodyBuilder
* @param AnnotationCollection $annotations
*/
public function __construct(MethodModel $methodModel, MethodBodyBuilder $methodBodyBuilder, AnnotationCollection $annotations);
{
$this->handlers = [
new BaseUrlHandler($methodModel, $methodBodyBuilder, $annotations),
new SerializationContextHandler($methodModel, $methodBodyBuilder, $annotations),
new RequestUrlHandler($methodModel, $methodBodyBuilder, $annotations),
new RequestHeaderHandler($methodModel, $methodBodyBuilder, $annotations),
new RequestBodyHandler($methodModel, $methodBodyBuilder, $annotations),
new ReturnHandler($methodModel, $methodBodyBuilder, $annotations),
new AsyncHandler($methodModel, $methodBodyBuilder, $annotations),
];
}
/**
* @inheritdoc
*/
public function handle()
{
foreach ($this->handlers as $handler) {
$handler->handle();
}
}
}
<?php
namespace Tebru\Retrofit\Generation\Listener;
use Tebru\Dynamo\Event\MethodEvent;
use Tebru\Retrofit\Generation\Builder\Factory\MethodBodyBuilderFactory;
class DynamoMethodListener
{
/**
* Creates a new method body builder
*
* @var MethodBodyBuilderFactory
*/
private $methodBodyBuilderFactory;
/**
* Constructor
*
* @param MethodBodyBuilderFactory $methodBodyBuilderFactory
*/
public function __construct(MethodBodyBuilderFactory $methodBodyBuilderFactory)
{
$this->methodBodyBuilderFactory = $methodBodyBuilderFactory;
}
/**
* Handler the event
*
* @param MethodEvent $event
*/
public function __invoke(MethodEvent $event)
{
$methodModel = $event->getMethodModel();
$annotations = $event->getAnnotationCollection();
$methodBodyBuilder = $this->methodBodyBuilderFactory->make();
$handler = new MethodHandler($methodModel, $methodBodyBuilder, $annotations);
$handler->handle();
$body = $methodBodyBuilder->build();
$methodModel->setBody($body);
}
}