Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit ecd3587

Browse filesBrowse 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 512abd7 commit ecd3587
Copy full SHA for ecd3587

File tree

4 files changed

+152
-24
lines changed
Filter options

4 files changed

+152
-24
lines changed

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

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php
+24Lines 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

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTest.php
+86Lines 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

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpFoundation/JsonResponse.php
+30-24Lines 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

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpFoundation/Tests/JsonResponseTest.php
+12Lines 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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.