[SoapBundle] Enhanced exception management with Symfony2
This commit is contained in:
parent
10705aa9e2
commit
6a6661012e
@ -25,6 +25,7 @@
|
||||
"ext-curl": "*",
|
||||
"ass/xmlsecurity": "~1.0",
|
||||
"symfony/framework-bundle": "~2.0",
|
||||
"symfony/twig-bundle": "~2.0",
|
||||
"zendframework/zend-mail": "2.1.*",
|
||||
"zendframework/zend-mime": "2.1.*",
|
||||
"zendframework/zend-soap": "2.1.*"
|
||||
|
@ -12,14 +12,18 @@
|
||||
|
||||
namespace BeSimple\SoapBundle\Controller;
|
||||
|
||||
use BeSimple\SoapBundle\Handler\ExceptionHandler;
|
||||
use BeSimple\SoapBundle\Soap\SoapRequest;
|
||||
use BeSimple\SoapBundle\Soap\SoapResponse;
|
||||
use BeSimple\SoapServer\Exception as SoapException;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerAware;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\FlattenException;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||
use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
|
||||
|
||||
/**
|
||||
* @author Christian Kerl <christian-kerl@web.de>
|
||||
@ -100,6 +104,46 @@ class SoapWebServiceController extends ContainerAware
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an Exception to a SoapFault Response.
|
||||
*
|
||||
* @param Request $request The request
|
||||
* @param FlattenException $exception A FlattenException instance
|
||||
* @param DebugLoggerInterface $logger A DebugLoggerInterface instance
|
||||
*
|
||||
* @return Response
|
||||
*
|
||||
* @throws \LogicException When the request query parameter "_besimple_soap_webservice" does not exist
|
||||
*/
|
||||
public function exceptionAction(Request $request, FlattenException $exception, DebugLoggerInterface $logger = null)
|
||||
{
|
||||
if (!$webservice = $request->query->get('_besimple_soap_webservice')) {
|
||||
throw new \LogicException(sprintf('The parameter "%s" is required in Request::$query parameter bag to generate the SoapFault.', '_besimple_soap_webservice'), null, $e);
|
||||
}
|
||||
|
||||
$view = 'TwigBundle:Exception:'.($this->container->get('kernel')->isDebug() ? 'exception' : 'error').'.txt.twig';
|
||||
$code = $exception->getStatusCode();
|
||||
$details = $this->container->get('templating')->render($view, array(
|
||||
'status_code' => $code,
|
||||
'status_text' => isset(Response::$statusTexts[$code]) ? Response::$statusTexts[$code] : '',
|
||||
'exception' => $exception,
|
||||
'logger' => $logger,
|
||||
));
|
||||
|
||||
$server = $this
|
||||
->container
|
||||
->get(sprintf('besimple.soap.context.%s', $webservice))
|
||||
->getServerBuilder()
|
||||
->withHandler(new ExceptionHandler($exception, $details))
|
||||
->build()
|
||||
;
|
||||
|
||||
ob_start();
|
||||
$server->handle($request->getContent());
|
||||
|
||||
return new Response(ob_get_clean());
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets called once for every SOAP header the \SoapServer received
|
||||
* and afterwards once for the called SOAP operation.
|
||||
@ -125,13 +169,7 @@ class SoapWebServiceController extends ContainerAware
|
||||
);
|
||||
|
||||
// forward to controller
|
||||
try {
|
||||
$response = $this->container->get('http_kernel')->handle($this->soapRequest, HttpKernelInterface::SUB_REQUEST, false);
|
||||
} catch (\Exception $e) {
|
||||
$this->soapResponse = new Response(null, 500);
|
||||
|
||||
throw $e instanceof \SoapFault || $this->container->getParameter('kernel.debug') ? $e : new SoapException\ReceiverSoapFault($e->getMessage());
|
||||
}
|
||||
$response = $this->container->get('http_kernel')->handle($this->soapRequest, HttpKernelInterface::SUB_REQUEST, false);
|
||||
|
||||
$this->setResponse($response);
|
||||
|
||||
|
@ -63,6 +63,8 @@ class BeSimpleSoapExtension extends Extension
|
||||
$serviceConfig['name'] = $name;
|
||||
$this->createWebServiceContext($serviceConfig, $container);
|
||||
}
|
||||
|
||||
$container->setParameter('besimple.soap.exception_listener.controller', $config['exception_controller']);
|
||||
}
|
||||
|
||||
private function registerCacheConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader)
|
||||
|
@ -40,6 +40,12 @@ class Configuration
|
||||
$this->addServicesSection($rootNode);
|
||||
$this->addWsdlDumperSection($rootNode);
|
||||
|
||||
$rootNode
|
||||
->children()
|
||||
->scalarNode('exception_controller')->defaultValue('BeSimpleSoapBundle:SoapWebService:exception')->end()
|
||||
->end()
|
||||
;
|
||||
|
||||
return $treeBuilder->buildTree();
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the BeSimpleSoapBundle.
|
||||
*
|
||||
* (c) Christian Kerl <christian-kerl@web.de>
|
||||
* (c) Francis Besset <francis.besset@gmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace BeSimple\SoapBundle\EventListener;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
|
||||
use Symfony\Component\HttpKernel\EventListener\ExceptionListener;
|
||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
|
||||
/**
|
||||
* @author Francis Besset <francis.besset@gmail.com>
|
||||
*/
|
||||
class SoapExceptionListener extends ExceptionListener
|
||||
{
|
||||
/**
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* To avoid conflict between , the logger param is not typed:
|
||||
* The parent class needs and instance of `Psr\Log\LoggerInterface` from Symfony 2.2,
|
||||
* before logger is an instance of `Symfony\Component\HttpKernel\Log\LoggerInterface`.
|
||||
*
|
||||
* @param ContainerInterface $container A ContainerInterface instance
|
||||
* @param string $controller The controller name to call
|
||||
* @param LoggerInterface $logger A logger instance
|
||||
*/
|
||||
public function __construct(ContainerInterface $container, $controller, $logger)
|
||||
{
|
||||
parent::__construct($controller, $logger);
|
||||
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
public function onKernelException(GetResponseForExceptionEvent $event)
|
||||
{
|
||||
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$request = $event->getRequest();
|
||||
if ('soap' !== $request->getRequestFormat()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$attributes = $request->attributes;
|
||||
if (!$webservice = $attributes->get('webservice')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$this->container->has(sprintf('besimple.soap.context.%s', $webservice))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// hack to retrieve the current WebService name in the controller
|
||||
$request->query->set('_besimple_soap_webservice', $webservice);
|
||||
|
||||
parent::onKernelException($event);
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
KernelEvents::EXCEPTION => array('onKernelException', -64),
|
||||
);
|
||||
}
|
||||
}
|
43
src/BeSimple/SoapBundle/Handler/ExceptionHandler.php
Normal file
43
src/BeSimple/SoapBundle/Handler/ExceptionHandler.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the BeSimpleSoapBundle.
|
||||
*
|
||||
* (c) Christian Kerl <christian-kerl@web.de>
|
||||
* (c) Francis Besset <francis.besset@gmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace BeSimple\SoapBundle\Handler;
|
||||
|
||||
use BeSimple\SoapServer\Exception\ReceiverSoapFault;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\FlattenException;
|
||||
|
||||
/**
|
||||
* @author Francis Besset <francis.besset@gmail.com>
|
||||
*/
|
||||
class ExceptionHandler
|
||||
{
|
||||
protected $exception;
|
||||
protected $details;
|
||||
|
||||
public function __construct(FlattenException $exception, $details = null)
|
||||
{
|
||||
$this->exception = $exception;
|
||||
$this->details = $details;
|
||||
}
|
||||
|
||||
public function __call($method, $arguments)
|
||||
{
|
||||
$code = $this->exception->getStatusCode();
|
||||
|
||||
throw new ReceiverSoapFault(
|
||||
isset(Response::$statusTexts[$code]) ? Response::$statusTexts[$code] : '',
|
||||
null,
|
||||
$this->details
|
||||
);
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@
|
||||
<parameters>
|
||||
<parameter key="besimple.soap.response.class">BeSimple\SoapBundle\Soap\SoapResponse</parameter>
|
||||
<parameter key="besimple.soap.response.listener.class">BeSimple\SoapBundle\EventListener\SoapResponseListener</parameter>
|
||||
<parameter key="besimple.soap.exception_listener.class">BeSimple\SoapBundle\EventListener\SoapExceptionListener</parameter>
|
||||
<parameter key="besimple.soap.context.class">BeSimple\SoapBundle\WebServiceContext</parameter>
|
||||
<parameter key="besimple.soap.binder.request_header.rpcliteral.class">BeSimple\SoapBundle\ServiceBinding\RpcLiteralRequestHeaderMessageBinder</parameter>
|
||||
<parameter key="besimple.soap.binder.request.rpcliteral.class">BeSimple\SoapBundle\ServiceBinding\RpcLiteralRequestMessageBinder</parameter>
|
||||
@ -25,6 +26,14 @@
|
||||
<argument type="service" id="besimple.soap.response" />
|
||||
</service>
|
||||
|
||||
<service id="besimple.soap.exception_listener" class="%besimple.soap.exception_listener.class%">
|
||||
<tag name="kernel.event_subscriber" />
|
||||
<tag name="monolog.logger" channel="request" />
|
||||
<argument type="service" id="service_container" />
|
||||
<argument>%besimple.soap.exception_listener.controller%</argument>
|
||||
<argument type="service" id="logger" on-invalid="null" />
|
||||
</service>
|
||||
|
||||
<service id="besimple.soap.context.rpcliteral" class="%besimple.soap.context.class%" abstract="true">
|
||||
<argument type="service" id="besimple.soap.definition.loader" />
|
||||
<argument type="service" id="besimple.soap.converter.collection" />
|
||||
|
@ -25,10 +25,11 @@
|
||||
"besimple/soap-common": "0.2.*",
|
||||
"besimple/soap-wsdl": "0.2.*",
|
||||
"ass/xmlsecurity": "~1.0",
|
||||
"symfony/framework-bundle": "~2.0",
|
||||
"symfony/twig-bundle": "~2.0",
|
||||
"zendframework/zend-mail": "2.1.*",
|
||||
"zendframework/zend-mime": "2.1.*",
|
||||
"zendframework/zend-soap": "2.1.*",
|
||||
"symfony/framework-bundle": "~2.0"
|
||||
"zendframework/zend-soap": "2.1.*"
|
||||
},
|
||||
"suggest": {
|
||||
"besimple/soap-client": "0.2.*",
|
||||
|
Loading…
Reference in New Issue
Block a user