Symfony2 JSON response returns weird UTF characters - json

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!"}]

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;
}

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;
}

You can use just normalizer without serializer to solve this:
$normalizer = new ObjectNormalizer();
$array = $normalizer->normalize($newEntry);
$entryJSONFile = json_encode($array, JSON_UNESCAPED_UNICODE);

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)

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();

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))
...

Related

Symfony request with json for postman

I have my CRUD but I need to do a POST request with postman. I've been reading some posts but I don't really understand how it works.
My routing for that:
jugador_create:
path: /{_format}
defaults: { _controller: "FutbolBundle:Jugador:new", _format: html }
requirements: { _method: post, _format: html|xml|json }
My controller is this:
public function newAction(Request $request)
{
$entity = new Jugador();
$form = $this->createCreateForm($entity);
if ($request->getMethod() == 'POST'){
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('jugador_show', array('id' => $entity->getId())));
}}
return $this->render('FutbolBundle:Jugador:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
));
}
How do I do it so in postman I can do a JSON post and it creates it? I think I need to do a switch with Json, xml and default case but I don't really understand how to do the Json part.
Thank you so much.
Also, in my index I already did the switch with Json and xml but it's pretty different to a GET than a POST.
public function indexAction(Request $request){
$request = $this->getRequest();
$serializer = new Serializer(array(new GetSetMethodNormalizer()),array(new XmlEncoder(), new JsonEncoder()));
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('FutbolBundle:Jugador')->findAll();
switch ($request->getRequestFormat()){
case "json":
$response=new Response();
$response->setContent($serializer->serialize($entities,'json'));
return $response;
break;
case "xml":
$response=new Response();
$response->setContent($serializer->serialize($entities,'xml'));
return $response;
break;
default:
return $this->render('FutbolBundle:Jugador:index.html.twig', array(
'entities' => $entities,
));
}
}
My sugestion is as follow:
Implemet a format listener to avoid repeating your code in all controllers
public function onKernelRequest(GetResponseEvent $event)
{
$request = $event->getRequest();
if ('json' === $request->getContentType() && $request->getContent()) {
$data = json_decode($request->getContent(), true);
$request->request->replace($data);
}
}
After that your controller should not change because you already transformed the data from json to regular posted data. You can do the same with the xml format or what ever format you want but html.
Specify the headers in postman
At Headers options below the method/url just add the Content-type header as follow.
Content-type(key) application/json (value)
Content-type(key) application/xml (value)
That should work
Hope it helps.
PD: Si no entiendes todo lo que he escrito hazmelo saber.
Just in case anyone needs help, I actually did it pretty simple using sets and the entity of Symfony.
$data = json_decode($request->getContent(),true);
$entity->setNom($data["nom"]);
$entity->setEquip($data["equip"]);
... (more sets if you need them)
and this for inserting it into the data base.
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();

Getting access to the keys of an array of objects in es6

i'm new to es6 and i have an array of objects like below:
checkProps = [ {symbol: rwerwe}, {side: Buy}, {status: Hey} ]
With a for loop i want to create a string like:
myurl = localhost:3000/symbol=rwerwe&side=Buy&status=Hey
For this i have to get access to the keys of each object and use concat for the string composition. I used Object.keys but it returns integers. I want something to return the symbol, side and status. How to do this?
Please try this:
var checkProps = [ {symbol: 'rwerwe'}, {side: 'Buy'}, {status: 'Hey'} ];
var urlStr = 'localhost:3000/';
var urlParams = [];
checkProps.forEach(function(o) {
var keys = Object.keys(o);
keys.map(function(key) {
urlParams.push(key + '=' + o[key])
});
});
urlStr += urlParams.join('&');
console.log(urlStr)
You need to loop over the array and apply Object.keys to the items.
const parameters = checkProps.map(item => Object.keys(item).map(key => key + "=" + item[key])[0])
.join("&");
const myUrl = `localhost:3000/${parameters}`;
It's a bit cleaner with ES2017 and Object.entries:
const parameters = checkProps.map(item => Object.entries(item)[0])
.map(parameter => parameter.join("="))
.join("&");

AngularJS - Create dynamic properties to an object/model from json

OK, we all know this works:
vm.myObject = {
required : "This field requires data",
.....
}
But how can I create that same object dynamically when the property 'keys' and 'values' come from a json file, eg:
json:
[
{ "key" :"required", "value": "This field requires data"},
.....
]
service:
var myObject = {}
DynamicObjSvc.get()
.success(function(data){
data.forEach(function(item){
// pass each key as an object property
// and pass its respective value
?????????
})
.....
UPDATE:
Kavemen was mostly correct, this turned out to be the solution:
var myObject = {};
DynamicObjSvc.all()
.success(function(data){
angular.forEach(data, function(msg) {
myObject[msg.key] = msg.value; <-- his answer was incorrect here
});
$fgConfigProviderRef.validation.message(myObject);
})
.error(function(err){
console.log(err.message);
})
You can use angular.forEach and the bracket notation for setting (and getting) object properties in Javascript
var myObject = {}
DynamicObjSvc.get().success(
function(data) {
angular.forEach(data, function(value, key) {
myObject[key] = value;
});
}
);
See also Working with Objects from MDN
EDIT
I see now that your data is really an array of objects, not just a single object, so yes, the code above could lead you astray.
In any case, the method of setting an object's properties dynamically using the bracket notation is sound; the loop could be reworked to handle your data array as such:
//we have an array of objects now
var myObjects = [];
DynamicObjSvc.get().success(
function(data) {
//for each object in the data array
for(var i = 0; i < data.length; i++) {
//create and populate a new object for the ith data element
var newObject = {};
angular.forEach(data[i], function(value, key) {
newObject[key] = value;
});
//and add it to the overall collection
myObjects.push(newObject);
}
}
);

CakePHP JSON Rendering

I cannot for the life of me work out why
$xml['interaction']['twitteraccount'] = 'hello';
Causes my JSON output to render as HTML rather than JSON. I've tried all options and played around for a while. Surely I'm missing something? As soon as I take that line out again, it renders as JSON!
public function lifestream()
{
$this->RequestHandler->setContent('json', 'application/json' );
$this->set('interactions', $this->Interaction->find('all'));
$xmlArray = array();
foreach($this->Interaction->find('all') as $interaction) {
$sourceexploded = explode("/",$interaction['Interaction']['source']);
if($sourceexploded[0] == "twitter") {
$xml['interaction']['source'] = $sourceexploded[0];
$xml['interaction']['twitteraccount'] = 'hello';
} else {
$xml['interaction']['source'] = $interaction['Interaction']['source'];
}
$xml['interaction']['timestamp'] = $interaction['Interaction']['timestamp'];
$xml['interaction']['receivedfrom'] = $interaction['Interaction']['receivedfrom'];
$xmlArray[] = $xml;
}
echo json_encode($xmlArray);
You have to use the JsonView.
In your route.php write: Router::parseExtensions('json');
In your controller you have to set the RequestHandler Component.
class SomeNameController{
public $components = array('RequestHandler');
public function lifestream(){
$this->RequestHandler->setContent('json', 'application/json' );
$this->set('interactions', $this->Interaction->find('all'));
$xmlArray = array();
foreach($this->Interaction->find('all') as $interaction) {
/* do stuff */
$xmlArray[] = $xml;
}
$this->set('data', $xmlArray);
$this->set('_serialize', array(
'data',
));
}
}
Try to go on "samename/lifestream.json" now or make an HTTP request with "Content-Type: application/json".
Look at : http://book.cakephp.org/2.0/en/views/json-and-xml-views.html
add this 2 line of code:
$this->layout = 'ajax';
$this->autoRender = false;
The first line instructs the render to use an empty layout called ajax (you can find it on Views/Layouts/ajax.ctp
The second one instruct the render to not look for an view template (ctp file)
Then when you echo the json_encode it will rendered as xml

How to return Repository Objects as Json on Symfony2

I'm trying to return the users like this, but of course it doesn't work, I need the data as JSon since im working with BackboneJs
/**
* #Route("/mytest",name="ajax_user_path")
*/
public function ajaxAction()
{
$em = $this->get('doctrine')->getManager();
$users = $this->get('doctrine')->getRepository('GabrielUserBundle:Fosuser')->findAll();
$response = array("users"=>$users);
return new Response(json_encode($response));
}
Thanks for your help guys, here is the Solution
Get the JMSSerializerBundle,
This is the code on the controller
/**
* #Route("/user")
* #Template()
*/
public function userAction()
{
$em = $this->get('doctrine')->getManager();
$users = $this->get('doctrine')->getRepository('GabrielUserBundle:Fosuser')->findAll();
$serializer = $this->get('jms_serializer');
$response = $serializer->serialize($users,'json');
return new Response($response);
}
So, findAll returns an array of entities (objects) and json_encode cannot correctly encode that array. You have to prepare your data berofe send response like that:
Example:
use Symfony\Component\HttpFoundation\JsonResponse;
/**
* #Route("/mytest",name="ajax_user_path")
*/
public function ajaxAction()
{
$users = $this->get('doctrine')->getRepository('GabrielUserBundle:Fosuser')->findAll();
$response = array();
foreach ($users as $user) {
$response[] = array(
'user_id' => $user->getId(),
// other fields
);
}
return new JsonResponse(json_encode($response));
}
Moreover, it would be great if you put preparing response to ex. UserRepository class.
With Symfony you have JsonResponse like :
return new JsonResponse($users);
And don't forget to add the header :
use Symfony\Component\HttpFoundation\JsonResponse;
I have never tried to encode a complete object, but I have used json with arrays of informations like this:
$vars = array(
'test' => 'test'
);
$response = new JsonResponse($vars);
return $response;
As you can see in JsonResponse, its function setData() is encoding the array, so you don't have to do it yourself:
public function setData($data = array())
{
// Encode <, >, ', &, and " for RFC4627-compliant JSON, which may also be embedded into HTML.
$this->data = json_encode($data, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT);
return $this->update();
}