George Katsanos
George Katsanos

Reputation: 14165

Symfony2 JSON response returns weird UTF characters

Here's my controller method:

  public function sendjsonAction()
  {

    $message = $this->getDoctrine()
    ->getRepository('AcmeStoreBundle:Message')
    ->findAll();
    $serializer = new Serializer(array(new GetSetMethodNormalizer()), array('message' => new 
JsonEncoder()));
    $message = $serializer->serialize($message, 'json');    
    return new JsonResponse($message);

  }

Here's my router:

acme_store_sendjson:
    pattern:  /sendjson/
    defaults: { _controller: AcmeStoreBundle:Default:sendjson}

And here's what I get when I go to /sendjson/ :

"[{\u0022id\u0022:1,\u0022iam\u0022:1,\u0022youare\u0022:2,\u0022lat\u0022:50.8275853,\u0022lng\u0022:4.3809764,\u0022date\u0022:{\u0022lastErrors\u0022:{\u0022warning_count\u0022:0,\u0022warnings\u0022:[],\u0022error_count\u0022:0,\u0022errors\u0022:[]},\u0022timezone\u0022:{\u0022name\u0022:\u0022UTC\u0022,\u0022location\u0022:{\u0022country_code\u0022:\u0022??

(and it goes on similarly)

I attempt to make an ajax call (with jQuery) with the following:

$.getJSON('/app_dev.php/sendjson', function(data) {
  var items = [];

  $.each(data, function(key, val) {
    items.push('<li id="' + key + '">' + val + '</li>');
  });

  $('<ul/>', {
    'class': 'my-new-list',
    html: items.join('')
  }).appendTo('body');
});

And I get a

Uncaught TypeError: Cannot use 'in' operator to search for '1549' in [{"id":1,...

When I change the Response type of Symfony2, I get a list of

[Object] [Object] [Object] [Object] [Object] [Object] ...

What am I doing wrong? Should I be parsing the answer to convert \u0022 to " or is my response faulty from the beginning?

EDIT

I also tried by changing the controller to:

  public function sendjsonAction()
  {
$encoders = array(new XmlEncoder(), new JsonEncoder());
$normalizers = array(new GetSetMethodNormalizer());
$serializer = new Serializer($normalizers, $encoders);

    $message = $this->getDoctrine()
    ->getRepository('AcmeStoreBundle:Message')
    ->findAll();
$serializer = $serializer->serialize($message, 'json');
    return new Response($serializer);
}

This time I got VALID JSON, (according to Jsonlint) buuttt the headers are not application/json... (makes sense because I am sending a Response and not a JsonResponse...) (but thats what I m trying to avoid as JsonResponse seems to be changing adding weird characters)

[{"id":1,"iam":1,"youare":2,"lat":50.8275853,"lng":4.3809764,"msgbody":"I saw you over there what's up!"},{"id":2,"iam":1,"youare":2,"lat":50.8275853,"lng":4.3809764,"msgbody":"I saw you over there what's up!"},{"id":3,"iam":1,"youare":2,"lat":50.8275853,"lng":4.3809764,"msgbody":"I saw you over there what's up!"},{"id":4,"iam":1,"youare":2,"lat":50.8275853,"lng":4.3809764,"msgbody":"I saw you over there what's up!"},{"id":5,"iam":1,"youare":2,"lat":50.8275853,"lng":4.3809764,"msgbody":"I saw you over there what's up!"},{"id":6,"iam":1,"youare":2,"lat":50.8275853,"lng":4.3809764,"msgbody":"I saw you over there what's up!"}]

Upvotes: 4

Views: 16240

Answers (6)

Sepideh
Sepideh

Reputation: 133

your code is encoding in json twice. Use the Response class when you are doing the json encoding yourself with the serializer.

replace return new JsonResponse($message) with return new Response($message)

Upvotes: 1

EarthLing
EarthLing

Reputation: 11

https://www.php.net/manual/en/json.constants.php

https://www.php.net/manual/en/function.json-encode.php

Object \Symfony\Component\HttpFoundation\JsonResponse to output JSON string uses function json_encode, by method of object setEncodingOptions you can set outputting JSON string options by bitwise constants like JSON_UNESCAPED_UNICODE:

Encode multibyte Unicode characters literally (default is to escape as \uXXXX). Available as of PHP 5.4.0.

$jsonResponse = new \Symfony\Component\HttpFoundation\JsonResponse($arrayForJSON);
$jsonResponse->setEncodingOptions($this->getEncodingOptions()|JSON_UNESCAPED_UNICODE|JSON_NUMERIC_CHECK|JSON_PRETTY_PRINT);
$jsonResponse->send();

Upvotes: 0

f0rt
f0rt

Reputation: 101

You can use just normalizer without serializer to solve this:

    $normalizer = new ObjectNormalizer();
    $array = $normalizer->normalize($newEntry);
    $entryJSONFile = json_encode($array, JSON_UNESCAPED_UNICODE);

Upvotes: 1

Yuri Borges
Yuri Borges

Reputation: 325

Serialization is the process of normalizing - making an array that represents the object - and encoding that representation (i.e. to JSON or XML ). JsonResponse takes care of the encoding part for you(look at the name of the class) so you can't pass a 'serialized object' otherwise it will be encoded once more. Hence the solution is only normalizing the object and passing it to JsonResponse:

public function indexAction($id)
{
    $repository = $this->getDoctrine()->getRepository('MyBundle:Product');
    $product = $repository->find($id);

    $normalizer = new GetSetMethodNormalizer();

    $jsonResponse = new JsonResponse($normalizer->normalize($product));
    return $jsonResponse;
}

Upvotes: 2

Vladimir
Vladimir

Reputation: 11

Issue is you are passing a string to JsonResponse and not an array.

Your Controller code is:

...
return new JsonResponse($message)
...

Your Controller code has to be:

...
return new JsonResponse(json_decode($message, true))
...

Upvotes: -2

George Katsanos
George Katsanos

Reputation: 14165

I Found the answer.

1) It doesn't "really matter" the content-type is not application/json but text/html, as long as the JSON is Valid. The reason my JS wasn't playing was that I was asking for val and not a property of val such as val.msgbody. :

So my Javascript should be

$.getJSON('/app_dev.php/sendjson', function(data) {
  var items = [];

  $.each(data, function(key, val) {
    items.push('<li id="' + key + '">' + val.msgbody + '</li>');
  });

  $('<ul/>', {
    'class': 'my-new-list',
    html: items.join('')
  }).appendTo('body');
});

In case the Content-Type is a requirement, then the controller could be like that:

 public function sendjsonAction()
  {
    $encoders = array(new JsonEncoder());
    $normalizers = array(new GetSetMethodNormalizer());
    $serializer = new Serializer($normalizers, $encoders);
    $message = $this->getDoctrine()
      ->getRepository('AcmeStoreBundle:Message')
      ->findAll();
    $response = new Response($serializer->serialize($message, 'json')); 
    $response->headers->set('Content-Type', 'application/json');
    return $response;
  }

Upvotes: 4

Related Questions