Skip to content

Commit 4cc697b

Browse files
committed
Merge pull request #816 from crystalservice/exceptional-wrapper-serialize
ExceptionWrapper serialize handler
2 parents e3a28eb + 497b895 commit 4cc697b

File tree

4 files changed

+226
-0
lines changed

4 files changed

+226
-0
lines changed

Resources/config/view.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
<parameter key="fos_rest.view.exception_wrapper_handler" />
1212
<parameter key="fos_rest.view_handler.default.class">FOS\RestBundle\View\ViewHandler</parameter>
1313
<parameter key="fos_rest.view_handler.jsonp.class">FOS\RestBundle\View\JsonpHandler</parameter>
14+
<parameter key="fos_rest.serializer.exception_wrapper_serialize_handler.class">FOS\RestBundle\Serializer\ExceptionWrapperSerializeHandler</parameter>
1415
</parameters>
1516

1617
<services>
@@ -42,5 +43,9 @@
4243

4344
<service id="fos_rest.view.exception_wrapper_handler" class="%fos_rest.view.exception_wrapper_handler%" />
4445

46+
<service id="fos_rest.serializer.exception_wrapper_serialize_handler" class="%fos_rest.serializer.exception_wrapper_serialize_handler.class%">
47+
<tag name="jms_serializer.subscribing_handler" />
48+
</service>
49+
4550
</services>
4651
</container>
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
3+
namespace FOS\RestBundle\Serializer;
4+
5+
use FOS\RestBundle\Util\ExceptionWrapper;
6+
use JMS\Serializer\Context;
7+
use JMS\Serializer\GraphNavigator;
8+
use JMS\Serializer\Handler\SubscribingHandlerInterface;
9+
use JMS\Serializer\JsonSerializationVisitor;
10+
use JMS\Serializer\XmlSerializationVisitor;
11+
12+
class ExceptionWrapperSerializeHandler implements SubscribingHandlerInterface
13+
{
14+
/**
15+
* @return array
16+
*/
17+
public static function getSubscribingMethods()
18+
{
19+
return array(
20+
array(
21+
'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
22+
'format' => 'json',
23+
'type' => 'FOS\\RestBundle\\Util\\ExceptionWrapper',
24+
'method' => 'serializeToJson'
25+
),
26+
array(
27+
'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
28+
'format' => 'xml',
29+
'type' => 'FOS\\RestBundle\\Util\\ExceptionWrapper',
30+
'method' => 'serializeToXml'
31+
)
32+
);
33+
}
34+
35+
/**
36+
* @param JsonSerializationVisitor $visitor
37+
* @param ExceptionWrapper $wrapper
38+
* @param array $type
39+
* @param Context $context
40+
* @return array
41+
*/
42+
public function serializeToJson(
43+
JsonSerializationVisitor $visitor,
44+
ExceptionWrapper $wrapper,
45+
array $type,
46+
Context $context
47+
) {
48+
$data = $this->convertToArray($wrapper);
49+
return $visitor->visitArray($data, $type, $context);
50+
}
51+
52+
/**
53+
* @param XmlSerializationVisitor $visitor
54+
* @param ExceptionWrapper $wrapper
55+
* @param array $type
56+
* @param Context $context
57+
*/
58+
public function serializeToXml(
59+
XmlSerializationVisitor $visitor,
60+
ExceptionWrapper $wrapper,
61+
array $type,
62+
Context $context
63+
) {
64+
$data = $this->convertToArray($wrapper);
65+
66+
if (null === $visitor->document) {
67+
$visitor->document = $visitor->createDocument(null, null, true);
68+
}
69+
70+
foreach ($data as $key => $value) {
71+
$entryNode = $visitor->document->createElement($key);
72+
$visitor->getCurrentNode()->appendChild($entryNode);
73+
$visitor->setCurrentNode($entryNode);
74+
75+
$node = $context->getNavigator()->accept($value, null, $context);
76+
if (null !== $node) {
77+
$visitor->getCurrentNode()->appendChild($node);
78+
}
79+
80+
$visitor->revertCurrentNode();
81+
}
82+
}
83+
84+
/**
85+
* @param ExceptionWrapper $exceptionWrapper
86+
* @return array
87+
*/
88+
protected function convertToArray(ExceptionWrapper $exceptionWrapper)
89+
{
90+
return array(
91+
'code' => $exceptionWrapper->getCode(),
92+
'message' => $exceptionWrapper->getMessage(),
93+
'errors' => $exceptionWrapper->getErrors(),
94+
);
95+
}
96+
}

Tests/View/ViewHandlerTest.php

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,23 @@
1111

1212
namespace FOS\RestBundle\Tests\View;
1313

14+
use FOS\RestBundle\Serializer\ExceptionWrapperSerializeHandler;
15+
use FOS\RestBundle\Util\ExceptionWrapper;
1416
use FOS\RestBundle\View\ExceptionWrapperHandler;
1517
use FOS\RestBundle\View\View;
1618
use FOS\RestBundle\View\ViewHandler;
19+
use JMS\Serializer\EventDispatcher\EventDispatcher;
20+
use JMS\Serializer\Exclusion\GroupsExclusionStrategy;
21+
use JMS\Serializer\Handler\FormErrorHandler;
22+
use JMS\Serializer\Handler\HandlerRegistry;
23+
use JMS\Serializer\SerializerBuilder;
1724
use Symfony\Bundle\FrameworkBundle\Templating\TemplateReference;
1825
use FOS\RestBundle\Util\Codes;
1926
use Symfony\Component\DependencyInjection\Container;
27+
use Symfony\Component\Form\Form;
28+
use Symfony\Component\Form\FormBuilder;
29+
use Symfony\Component\Form\FormError;
30+
use Symfony\Component\Form\Forms;
2031
use Symfony\Component\HttpFoundation\Request;
2132
use Symfony\Component\HttpFoundation\Response;
2233
use Symfony\Component\Form\FormView;
@@ -546,4 +557,92 @@ public function testConfigurableViewHandlerInterface()
546557
$this->assertEquals('1.1', $context->attributes->get('version')->getOrThrow(new \Exception('Serialization version not set as expected')));
547558
$this->assertTrue($context->shouldSerializeNull());
548559
}
560+
561+
/**
562+
* @dataProvider exceptionWrapperSerializeResponseContentProvider
563+
* @param string $format
564+
*/
565+
public function testCreateResponseWithFormErrorsAndSerializationGroups($format)
566+
{
567+
$form = Forms::createFormFactory()->createBuilder()
568+
->add('name', 'text')
569+
->add('description', 'text')
570+
->getForm();
571+
572+
$form->get('name')->addError(new FormError('Invalid name'));
573+
574+
$exceptionWrapper = new ExceptionWrapper(
575+
array(
576+
'status_code' => 400,
577+
'message' => 'Validation Failed',
578+
'errors' => $form
579+
)
580+
);
581+
582+
$view = new View($exceptionWrapper);
583+
$view->getSerializationContext()->setGroups(array('Custom'));
584+
585+
$wrapperHandler = new ExceptionWrapperSerializeHandler();
586+
$translatorMock = $this->getMock(
587+
'Symfony\\Component\\Translation\\TranslatorInterface',
588+
array('trans', 'transChoice', 'setLocale', 'getLocale')
589+
);
590+
$translatorMock
591+
->expects($this->any())
592+
->method('trans')
593+
->will($this->returnArgument(0));
594+
595+
$formErrorHandler = new FormErrorHandler($translatorMock);
596+
597+
$serializer = SerializerBuilder::create()
598+
->configureHandlers(function (HandlerRegistry $handlerRegistry) use ($wrapperHandler, $formErrorHandler) {
599+
$handlerRegistry->registerSubscribingHandler($wrapperHandler);
600+
$handlerRegistry->registerSubscribingHandler($formErrorHandler);
601+
})
602+
->build();
603+
604+
$container = $this->getMock('Symfony\Component\DependencyInjection\Container', array('get'));
605+
$container
606+
->expects($this->once())
607+
->method('get')
608+
->with('fos_rest.serializer')
609+
->will($this->returnValue($serializer));
610+
611+
$viewHandler = new ViewHandler(array());
612+
$viewHandler->setContainer($container);
613+
614+
$response = $viewHandler->createResponse($view, new Request(), $format);
615+
616+
$serializer2 = SerializerBuilder::create()
617+
->configureHandlers(function (HandlerRegistry $handlerRegistry) use ($wrapperHandler, $formErrorHandler) {
618+
$handlerRegistry->registerSubscribingHandler($formErrorHandler);
619+
})
620+
->build();
621+
622+
$container2 = $this->getMock('Symfony\Component\DependencyInjection\Container', array('get'));
623+
$container2
624+
->expects($this->once())
625+
->method('get')
626+
->with('fos_rest.serializer')
627+
->will($this->returnValue($serializer2));
628+
629+
$viewHandler = new ViewHandler(array());
630+
$viewHandler->setContainer($container2);
631+
632+
$view2 = new View($exceptionWrapper);
633+
$response2 = $viewHandler->createResponse($view2, new Request(), $format);
634+
635+
$this->assertEquals($response->getContent(), $response2->getContent());
636+
}
637+
638+
/**
639+
* @return array
640+
*/
641+
public function exceptionWrapperSerializeResponseContentProvider()
642+
{
643+
return array(
644+
'json' => array('json'),
645+
'xml' => array('xml')
646+
);
647+
}
549648
}

Util/ExceptionWrapper.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
namespace FOS\RestBundle\Util;
1313

14+
use Symfony\Component\Form\FormInterface;
15+
1416
/**
1517
* Wraps an exception into the FOSRest exception format.
1618
*/
@@ -32,4 +34,28 @@ public function __construct($data)
3234
$this->errors = $data['errors'];
3335
}
3436
}
37+
38+
/**
39+
* @return int
40+
*/
41+
public function getCode()
42+
{
43+
return $this->code;
44+
}
45+
46+
/**
47+
* @return FormInterface
48+
*/
49+
public function getErrors()
50+
{
51+
return $this->errors;
52+
}
53+
54+
/**
55+
* @return string
56+
*/
57+
public function getMessage()
58+
{
59+
return $this->message;
60+
}
3561
}

0 commit comments

Comments
 (0)