diff --git a/DependencyInjection/Compiler/EventHandlerCompilerPass.php b/DependencyInjection/Compiler/EventHandlerCompilerPass.php new file mode 100644 index 0000000..3f6bd37 --- /dev/null +++ b/DependencyInjection/Compiler/EventHandlerCompilerPass.php @@ -0,0 +1,43 @@ +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']] + ); + } + } + } + } + } + +} diff --git a/DependencyInjection/GuzzleExtension.php b/DependencyInjection/GuzzleExtension.php index b6bb9f4..7cc2ddd 100644 --- a/DependencyInjection/GuzzleExtension.php +++ b/DependencyInjection/GuzzleExtension.php @@ -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() @@ -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 * diff --git a/Events/GuzzleEventListenerInterface.php b/Events/GuzzleEventListenerInterface.php new file mode 100644 index 0000000..7e145d4 --- /dev/null +++ b/Events/GuzzleEventListenerInterface.php @@ -0,0 +1,15 @@ +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; + } +} diff --git a/Events/PreTransactionEvent.php b/Events/PreTransactionEvent.php new file mode 100644 index 0000000..e8c9c6c --- /dev/null +++ b/Events/PreTransactionEvent.php @@ -0,0 +1,69 @@ +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; + } + +} diff --git a/GuzzleBundle.php b/GuzzleBundle.php index 0c6f2ca..92d1428 100644 --- a/GuzzleBundle.php +++ b/GuzzleBundle.php @@ -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 @@ -32,6 +33,9 @@ class GuzzleBundle extends Bundle { public function build(ContainerBuilder $container) { parent::build($container); + + $container->addCompilerPass(new EventHandlerCompilerPass()); + } // end: build /** diff --git a/Middleware/EventDispatchMiddleware.php b/Middleware/EventDispatchMiddleware.php new file mode 100644 index 0000000..2488d8d --- /dev/null +++ b/Middleware/EventDispatchMiddleware.php @@ -0,0 +1,74 @@ +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(); + } + ); + }; + }; + } +} diff --git a/README.md b/README.md index 826b291..2f425a9 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,14 @@ $client = $this->get('guzzle.client.api_crm'); $response = $client->get('/users'); ``` +## Events +Handling events. Events are dispatched before and after the request to the remote host. +### Listening To Events +``` xml + + + +``` ## Features ### Symfony Debug Toolbar / Profiler diff --git a/Resources/config/services.xml b/Resources/config/services.xml index 72a2aa3..e86cad1 100644 --- a/Resources/config/services.xml +++ b/Resources/config/services.xml @@ -12,6 +12,8 @@ EightPoints\Bundle\GuzzleBundle\Log\Logger EightPoints\Bundle\GuzzleBundle\Middleware\LogMiddleware EightPoints\Bundle\GuzzleBundle\Middleware\RequestHeaderMiddleware + + EightPoints\Bundle\GuzzleBundle\Middleware\EventDispatchMiddleware