Skip to content

Commit

Permalink
Merge pull request #22 from quadland/EventHandler
Browse files Browse the repository at this point in the history
Event handler
  • Loading branch information
Florian Preusner committed Sep 22, 2015
2 parents f25cd0b + a5e288c commit e3c9a1b
Show file tree
Hide file tree
Showing 10 changed files with 339 additions and 12 deletions.
43 changes: 43 additions & 0 deletions DependencyInjection/Compiler/EventHandlerCompilerPass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

namespace EightPoints\Bundle\GuzzleBundle\DependencyInjection\Compiler;
use \Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;

/**
* Class EventHandlerCompilerPass
*
* @package EightPoints\Bundle\GuzzleBundle\DependencyInjection\Compiler
*/
class EventHandlerCompilerPass implements CompilerPassInterface
{
/**
* We tag handlers with specific services to listen too.
*
* We get all event tagged services from the container.
* We then go through each event, and look for the value guzzle_bundle.
* For each one we find, we check if the service key is set, and then
* call setServiceName on each EventListener.
*
* @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
*
* @api
*/
public function process(ContainerBuilder $container)
{
$taggedServices = $container->findTaggedServiceIds('kernel.event_listener');

foreach($taggedServices as $id => $tags) {
foreach ($tags as $attributes) {
if(strstr($attributes['event'], 'guzzle_bundle') !== false) {
if(isset($attributes['service'])) {
$container->getDefinition($id)->addMethodCall(
'setServiceName', [$attributes['service']]
);
}
}
}
}
}

}
55 changes: 44 additions & 11 deletions DependencyInjection/GuzzleExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,32 +92,47 @@ protected function createHandler(ContainerBuilder $container, $name, array $conf
$requestHeader = $this->createRequestHeaderMiddleware($container, $config['headers']);
$container->setDefinition($headerServiceName, $requestHeader);

// Event Dispatching service
$eventServiceName = sprintf('guzzle_bundle.middleware.event_dispatch.%s', $name);
$eventService = $this->createEventMiddleware($container, $name);
$container->setDefinition($eventServiceName, $eventService);

$headerExpression = new Expression(sprintf("service('%s').attach()", $headerServiceName));
$logExpression = new Expression(sprintf("service('%s').log()", $logServiceName));
// Create the event Dispatch Middleware
$eventExpression = new Expression(sprintf("service('%s').dispatchEvent()", $eventServiceName));

$handler = new Definition('GuzzleHttp\HandlerStack');
$handler->setFactory(['GuzzleHttp\HandlerStack', 'create']);

// WSSE
if(isset($config['plugin']['wsse'])
&& $config['plugin']['wsse']['username']
&& $config['plugin']['wsse']['password']) {
// Plugins
if(isset($config['plugin'])){
// Wsse if required
if (isset($config['plugin']['wsse'])
&& $config['plugin']['wsse']['username']
&& $config['plugin']['wsse']['password']) {

$wsseConfig = $config['plugin']['wsse'];
unset($config['plugin']['wsse']);

$username = $config['plugin']['wsse']['username'];
$password = $config['plugin']['wsse']['password'];
$username = $wsseConfig['username'];
$password = $$wsseConfig['password'];

$wsse = $this->createWsseMiddleware($container, $username, $password);
$wsseServiceName = sprintf('guzzle_bundle.middleware.wsse.%s', $name);
$wsse = $this->createWsseMiddleware($container, $username, $password);
$wsseServiceName = sprintf('guzzle_bundle.middleware.wsse.%s', $name);

$container->setDefinition($wsseServiceName, $wsse);
$container->setDefinition($wsseServiceName, $wsse);

$wsseExpression = new Expression(sprintf('service("%s").attach()', $wsseServiceName));
$wsseExpression = new Expression(sprintf('service("%s").attach()', $wsseServiceName));

$handler->addMethodCall('push', [$wsseExpression]);
$handler->addMethodCall('push', [$wsseExpression]);
}
}

$handler->addMethodCall('push', [$headerExpression]);
$handler->addMethodCall('push', [$logExpression]);
// goes on the end of the stack.
$handler->addMethodCall('unshift', [$eventExpression]);

return $handler;
} // end: createHandler()
Expand Down Expand Up @@ -179,6 +194,24 @@ protected function createRequestHeaderMiddleware(ContainerBuilder $container, ar
return $requestHeader;
} // end: createRequestHeaderMiddleware()

/**
* Create Middleware For dispatching events
*
* @author Chris Warner
* @since 2015-09
*
* @param ContainerBuilder $container
*
* @return Definition
*/
protected function createEventMiddleware(ContainerBuilder $container, $name) {
$eventMiddleWare = new Definition($container->getParameter('guzzle_bundle.middleware.event_dispatcher.class'));
$eventMiddleWare->addArgument(new Reference('event_dispatcher'));
$eventMiddleWare->addArgument($name);

return $eventMiddleWare;
} // end: createEventMiddleware()

/**
* Create Middleware for WSSE
*
Expand Down
15 changes: 15 additions & 0 deletions Events/GuzzleEventListenerInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php
/**
* Created by IntelliJ IDEA.
* User: chris
* Date: 9/16/15
* Time: 2:40 PM
*/

namespace EightPoints\Bundle\GuzzleBundle\Events;


interface GuzzleEventListenerInterface
{
public function setServiceName($serviceName);
}
13 changes: 13 additions & 0 deletions Events/GuzzleEvents.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php
namespace EightPoints\Bundle\GuzzleBundle\Events;

/**
* Class GuzzleEvents
*
* @package EightPoints\Bundle\GuzzleBundle\Events
*/
final class GuzzleEvents
{
const PRE_TRANSACTION = 'guzzle_bundle.pre_transaction';
const POST_TRANSACTION = 'guzzle_bundle.post_transaction';
}
66 changes: 66 additions & 0 deletions Events/PostTransactionEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

namespace EightPoints\Bundle\GuzzleBundle\Events;

use Psr\Http\Message\ResponseInterface;
use Symfony\Component\EventDispatcher\Event;

/**
* Class PostTransactionEvent
*
* @package EightPoints\Bundle\GuzzleBundle\Events
*/
class PostTransactionEvent extends Event
{
/**
* @var ResponseInterface
*/
protected $response;

/**
* @var string
*/
protected $serviceName;

/**
* PostTransactionEvent constructor.
*
* @param ResponseInterface $response
*/
public function __construct(ResponseInterface $response, $serviceName)
{
$this->response = $response;
$this->serviceName = $serviceName;
}


/**
* Get the transaction from the event.
*
* This returns the transaction we are working with.
*
* @return ResponseInterface
*/
public function getTransaction()
{
return $this->response;
}

/**
* Sets the transaction inline with the event.
*
* @param ResponseInterface $response
*/
public function setTransaction(ResponseInterface $response)
{
$this->response = $response;
}

/**
* @return string
*/
public function getServiceName()
{
return $this->serviceName;
}
}
69 changes: 69 additions & 0 deletions Events/PreTransactionEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php
namespace EightPoints\Bundle\GuzzleBundle\Events;
use Psr\Http\Message\RequestInterface;
use Symfony\Component\EventDispatcher\Event;

/**
* Class PreTransactionEvent
*
* @package EightPoints\Bundle\GuzzleBundle\Events
*
* @author Chris Warner([email protected])
*/
class PreTransactionEvent extends Event
{
/**
* @var RequestInterface
*/
protected $requestTransaction;
/**
* @var string
*/
protected $serviceName;

/**
* PreTransactionEvent constructor.
*
* @param RequestInterface $requestTransaction
*/
public function __construct(RequestInterface $requestTransaction, $serviceName)
{
$this->requestTransaction = $requestTransaction;
$this->serviceName = $serviceName;
}

/**
* Access the transaction from the Guzzle HTTP request
*
* This returns the actual Request Object from the Guzzle HTTP
* Reqeust. This object will be modified by the event listener.
* @return RequestInterface
*/
public function getTransaction()
{
return $this->requestTransaction;
}

/**
* Replaces the transaction with the modified one.
*
* Guzzles transaction returns a modified request object,
* so once it has been modified, we need to put it back on the
* event so it can become part of the transaction.
*
* @param RequestInterface $requestTransaction
*/
public function setTransaction(RequestInterface $requestTransaction)
{
$this->requestTransaction = $requestTransaction;
}

/**
* @return string
*/
public function getServiceName()
{
return $this->serviceName;
}

}
6 changes: 5 additions & 1 deletion GuzzleBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@

use Symfony\Component\HttpKernel\Bundle\Bundle,
Symfony\Component\DependencyInjection\ContainerBuilder,
Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
Symfony\Component\DependencyInjection\Extension\ExtensionInterface,
EightPoints\Bundle\GuzzleBundle\DependencyInjection\Compiler\EventHandlerCompilerPass;

/**
* Class GuzzleBundle
Expand All @@ -32,6 +33,9 @@ class GuzzleBundle extends Bundle {
public function build(ContainerBuilder $container) {

parent::build($container);

$container->addCompilerPass(new EventHandlerCompilerPass());

} // end: build

/**
Expand Down
74 changes: 74 additions & 0 deletions Middleware/EventDispatchMiddleware.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?php
namespace EightPoints\Bundle\GuzzleBundle\Middleware;


use EightPoints\Bundle\GuzzleBundle\Events\PostTransactionEvent;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use EightPoints\Bundle\GuzzleBundle\Events\GuzzleEvents;
use EightPoints\Bundle\GuzzleBundle\Events\PreTransactionEvent;

/**
* Class EventDispatchMiddleware
*
* Dispatches an Event using the Symfony Event Dispatcher.
* Dispatches a PRE_TRANSACTION event, before the transaction is sent
* Dispatches a POST_TRANMSACTION event, when the remote hosts responds.
*
* @package EightPoints\Bundle\GuzzleBundle\Middleware
*/
class EventDispatchMiddleware
{
/**
* @var EventDispatcherInterface
*/
private $eventDispatcher;
private $serviceName;

/**
* EventDispatchMiddleware constructor.
*
* @param EventDispatcherInterface $eventDispatcher
*/
public function __construct(EventDispatcherInterface $eventDispatcher, $serviceName)
{
$this->eventDispatcher = $eventDispatcher;
$this->serviceName = $serviceName;
}

/**
* @return \Closure
*/
public function dispatchEvent()
{
return function (callable $handler) {
return function (
RequestInterface $request,
array $options
) use ( $handler ) {
// Create the Pre Transaction event.
$preTransactionEvent = new PreTransactionEvent($request, $this->serviceName);

// Dispatch it through the symfony Dispatcher.
$this->eventDispatcher->dispatch(GuzzleEvents::PRE_TRANSACTION, $preTransactionEvent);

// Continue the handler chain.
$promise = $handler($preTransactionEvent->getTransaction(), $options);
// Handle the response form teh server.
return $promise->then(
function (ResponseInterface $response) {
// Create hte Post Transaction event.
$postTransactionEvent = new PostTransactionEvent($response, $this->serviceName);

// Dispatch the event on the symfony event dispatcher.
$this->eventDispatcher->dispatch(GuzzleEvents::POST_TRANSACTION, $postTransactionEvent);

// Continue down the chain.
return $postTransactionEvent->getTransaction();
}
);
};
};
}
}
Loading

0 comments on commit e3c9a1b

Please sign in to comment.