Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 273a896

Browse files
committed
Add a Controller function to make it easy to return json
If the serializer component is enabled it is used to generate the json data, if not the standard `json_encode` function is used
1 parent 83b53f4 commit 273a896

File tree

4 files changed

+152
-24
lines changed

4 files changed

+152
-24
lines changed

src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
1515
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
16+
use Symfony\Component\HttpFoundation\JsonResponse;
1617
use Symfony\Component\HttpFoundation\Response;
1718
use Symfony\Component\HttpFoundation\RedirectResponse;
1819
use Symfony\Component\HttpFoundation\StreamedResponse;
@@ -97,6 +98,29 @@ protected function redirectToRoute($route, array $parameters = array(), $status
9798
return $this->redirect($this->generateUrl($route, $parameters), $status);
9899
}
99100

101+
/**
102+
* Returns a JsonResponse that uses the serializer component if enabled, or json_encode.
103+
*
104+
* @param mixed $data The response data
105+
* @param int $status The status code to use for the Response
106+
* @param array $headers Array of extra headers to add
107+
* @param array $context Context to pass to serializer when using serializer component
108+
*
109+
* @return JsonResponse
110+
*/
111+
protected function json($data, $status = 200, $headers = array(), $context = array())
112+
{
113+
if ($this->container->has('serializer')) {
114+
$json = $this->container->get('serializer')->serialize($data, 'json', array_merge(array(
115+
'json_encode_options' => JsonResponse::DEFAULT_ENCODING_OPTIONS,
116+
), $context));
117+
118+
return new JsonResponse($json, $status, $headers, true);
119+
}
120+
121+
return new JsonResponse($data, $status, $headers);
122+
}
123+
100124
/**
101125
* Adds a flash message to the current session for type.
102126
*

src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTest.php

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@
1414
use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
1515
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
1616
use Symfony\Component\DependencyInjection\ContainerInterface;
17+
use Symfony\Component\HttpFoundation\JsonResponse;
1718
use Symfony\Component\HttpFoundation\Request;
1819
use Symfony\Component\HttpFoundation\RequestStack;
1920
use Symfony\Component\HttpFoundation\Response;
2021
use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
2122
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
2223
use Symfony\Component\Security\Core\User\User;
24+
use Symfony\Component\Serializer\SerializerInterface;
2325

2426
class ControllerTest extends TestCase
2527
{
@@ -124,6 +126,85 @@ private function getContainerWithTokenStorage($token = null)
124126

125127
return $container;
126128
}
129+
130+
public function testJson()
131+
{
132+
$container = $this->getMock(ContainerInterface::class);
133+
$container
134+
->expects($this->once())
135+
->method('has')
136+
->with('serializer')
137+
->will($this->returnValue(false));
138+
139+
$controller = new TestController();
140+
$controller->setContainer($container);
141+
142+
$response = $controller->json(array());
143+
$this->assertInstanceOf(JsonResponse::class, $response);
144+
$this->assertEquals('[]', $response->getContent());
145+
}
146+
147+
public function testJsonWithSerializer()
148+
{
149+
$container = $this->getMock(ContainerInterface::class);
150+
$container
151+
->expects($this->once())
152+
->method('has')
153+
->with('serializer')
154+
->will($this->returnValue(true));
155+
156+
$serializer = $this->getMock(SerializerInterface::class);
157+
$serializer
158+
->expects($this->once())
159+
->method('serialize')
160+
->with(array(), 'json', array('json_encode_options' => 15))
161+
->will($this->returnValue('[]'));
162+
163+
$container
164+
->expects($this->once())
165+
->method('get')
166+
->with('serializer')
167+
->will($this->returnValue($serializer));
168+
169+
$controller = new TestController();
170+
$controller->setContainer($container);
171+
172+
$response = $controller->json(array());
173+
$this->assertInstanceOf(JsonResponse::class, $response);
174+
$this->assertEquals('[]', $response->getContent());
175+
}
176+
177+
public function testJsonWithSerializerContextOverride()
178+
{
179+
$container = $this->getMock(ContainerInterface::class);
180+
$container
181+
->expects($this->once())
182+
->method('has')
183+
->with('serializer')
184+
->will($this->returnValue(true));
185+
186+
$serializer = $this->getMock(SerializerInterface::class);
187+
$serializer
188+
->expects($this->once())
189+
->method('serialize')
190+
->with(array(), 'json', array('json_encode_options' => 0, 'other' => 'context'))
191+
->will($this->returnValue('[]'));
192+
193+
$container
194+
->expects($this->once())
195+
->method('get')
196+
->with('serializer')
197+
->will($this->returnValue($serializer));
198+
199+
$controller = new TestController();
200+
$controller->setContainer($container);
201+
202+
$response = $controller->json(array(), 200, array(), array('json_encode_options' => 0, 'other' => 'context'));
203+
$this->assertInstanceOf(JsonResponse::class, $response);
204+
$this->assertEquals('[]', $response->getContent());
205+
$response->setEncodingOptions(JSON_FORCE_OBJECT);
206+
$this->assertEquals('{}', $response->getContent());
207+
}
127208
}
128209

129210
class TestController extends Controller
@@ -137,4 +218,9 @@ public function getUser()
137218
{
138219
return parent::getUser();
139220
}
221+
222+
public function json($data, $status = 200, $headers = array(), $context = array())
223+
{
224+
return parent::json($data, $status, $headers, $context);
225+
}
140226
}

src/Symfony/Component/HttpFoundation/JsonResponse.php

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -29,24 +29,27 @@ class JsonResponse extends Response
2929

3030
// Encode <, >, ', &, and " for RFC4627-compliant JSON, which may also be embedded into HTML.
3131
// 15 === JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT
32-
protected $encodingOptions = 15;
32+
const DEFAULT_ENCODING_OPTIONS = 15;
33+
34+
protected $encodingOptions = self::DEFAULT_ENCODING_OPTIONS;
3335

3436
/**
3537
* Constructor.
3638
*
37-
* @param mixed $data The response data
38-
* @param int $status The response status code
39-
* @param array $headers An array of response headers
39+
* @param mixed $data The response data
40+
* @param int $status The response status code
41+
* @param array $headers An array of response headers
42+
* @param bool $preEncoded If the data is already a JSON string
4043
*/
41-
public function __construct($data = null, $status = 200, $headers = array())
44+
public function __construct($data = null, $status = 200, $headers = array(), $preEncoded = false)
4245
{
4346
parent::__construct('', $status, $headers);
4447

4548
if (null === $data) {
4649
$data = new \ArrayObject();
4750
}
4851

49-
$this->setData($data);
52+
$this->setData($data, $preEncoded);
5053
}
5154

5255
/**
@@ -88,34 +91,37 @@ public function setCallback($callback = null)
8891
* Sets the data to be sent as JSON.
8992
*
9093
* @param mixed $data
94+
* @param bool $preEncoded If the data is already a JSON string
9195
*
9296
* @return JsonResponse
9397
*
9498
* @throws \InvalidArgumentException
9599
*/
96-
public function setData($data = array())
100+
public function setData($data = array(), $preEncoded = false)
97101
{
98-
if (defined('HHVM_VERSION')) {
99-
// HHVM does not trigger any warnings and let exceptions
100-
// thrown from a JsonSerializable object pass through.
101-
// If only PHP did the same...
102-
$data = json_encode($data, $this->encodingOptions);
103-
} else {
104-
try {
105-
// PHP 5.4 and up wrap exceptions thrown by JsonSerializable
106-
// objects in a new exception that needs to be removed.
107-
// Fortunately, PHP 5.5 and up do not trigger any warning anymore.
102+
if (!$preEncoded) {
103+
if (defined('HHVM_VERSION')) {
104+
// HHVM does not trigger any warnings and let exceptions
105+
// thrown from a JsonSerializable object pass through.
106+
// If only PHP did the same...
108107
$data = json_encode($data, $this->encodingOptions);
109-
} catch (\Exception $e) {
110-
if ('Exception' === get_class($e) && 0 === strpos($e->getMessage(), 'Failed calling ')) {
111-
throw $e->getPrevious() ?: $e;
108+
} else {
109+
try {
110+
// PHP 5.4 and up wrap exceptions thrown by JsonSerializable
111+
// objects in a new exception that needs to be removed.
112+
// Fortunately, PHP 5.5 and up do not trigger any warning anymore.
113+
$data = json_encode($data, $this->encodingOptions);
114+
} catch (\Exception $e) {
115+
if ('Exception' === get_class($e) && 0 === strpos($e->getMessage(), 'Failed calling ')) {
116+
throw $e->getPrevious() ?: $e;
117+
}
118+
throw $e;
112119
}
113-
throw $e;
114120
}
115-
}
116121

117-
if (JSON_ERROR_NONE !== json_last_error()) {
118-
throw new \InvalidArgumentException(json_last_error_msg());
122+
if (JSON_ERROR_NONE !== json_last_error()) {
123+
throw new \InvalidArgumentException(json_last_error_msg());
124+
}
119125
}
120126

121127
$this->data = $data;

src/Symfony/Component/HttpFoundation/Tests/JsonResponseTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,18 @@ public function testConstructorWithCustomContentType()
7575
$this->assertSame('application/vnd.acme.blog-v1+json', $response->headers->get('Content-Type'));
7676
}
7777

78+
public function testConstructorWithPreEncoded()
79+
{
80+
$response = new JsonResponse('1', 200, array(), true);
81+
$this->assertEquals('1', $response->getContent());
82+
83+
$response = new JsonResponse('[1]', 200, array(), true);
84+
$this->assertEquals('[1]', $response->getContent());
85+
86+
$response = new JsonResponse('true', 200, array(), true);
87+
$this->assertEquals('true', $response->getContent());
88+
}
89+
7890
public function testCreate()
7991
{
8092
$response = JsonResponse::create(array('foo' => 'bar'), 204);

0 commit comments

Comments
 (0)