I'm using Symfony2 and making a php curl request to an api. I'm looking to make sure the results are being returned in the correct form: as a json
string (not a php object or something else). The returned json
string is consumed by renderAPIResults() that uses twig to "render" a JsonResponse
. Is this possible?
Can I "render" the response in renderAPIResults
or do I need to return a JsonResponse
and have the twig template render it, having been called from apiAction()?
Is there any built in Symfony2 functionality wherein if one names a template results.json.twig
vs. results.html.twig
, or is this naming convention is just idiomatic?
I have been able to get the results into results.html.twig by rendering a Response()
in the renderAPIResults()
method but I have only been able to console.log()
the results from a .js
file when returning the results as a JsonResponse()
. I have not been able to parse these results in any shape or form in the results.json.twig
template when trying to somehow 'render' a JsonResponse
.
//DefaultController.php
public function curlRestRequest($apiQueryString, $jsonDecode = FALSE, array $post_data = null, $service_url = null){
if(!$service_url) {
$service_url = 'http://website.com/rest';
}
$curl = curl_init($service_url.$apiQueryString);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $post_data);
$curl_response = curl_exec($curl);
if ($curl_response === false) {
$info = curl_getinfo($curl);
curl_close($curl);
die('error occured during curl exec. Additioanl info: ' . var_export($info));
}
curl_close($curl);
if($jsonDecode)
{
$curl_response = json_decode($curl_response);
}
return $curl_response;
}
public function renderAPIResults($data, $asObject = FALSE, $template)
{
if(!$template) {
throw new Exception('Must provide a template name before rendering!');
}
if($asObject != TRUE) {
// we want to cast to array since specified as OBJECT = FALSE, removing all instances of objects
$dataArray = json_decode(json_encode($data), true);
return $this->render($template, array('data' => $dataArray));
} else { // Is JSON Decoded, if it is an object
//just return json data, parse it in javascript instead of with template
$response = new JsonResponse();
$response->setData(array(
'data' => $data
));
return $response;
//return $this->renderView($template, array('data' => $data));
//or
//$content = $this->render($template, array('data' => $data));
//return new JsonResponse($content);
}
}
public function apiAction($type, $query){
$apiQueryString = '/search/' . $type . '?query=' . $query;
//make a curl request
$requestedResults = ($this->curlRestRequest($apiQueryString, TRUE));
//return option three: (dont use any response object, and just pass, just pass curl-results directly)
//note, currently, when set as true, its not rendered in the template, the template is not used
$view = $this->renderAPIResults($requestedResults, TRUE, 'ApiBundle:API:results.json.twig');
return $view;
}
This is the twig template:
//results.json.twig
{{ dump(data) }}
Basically, im asking:
How do I utilize JsonResponse()
in the renderAPIResults()
method to render the results.json.twig
in that same method, returning this rendered template so the template itself can loop over the json
results?
Can I use JsonResponse()
to render a template this way? Or do I have to use only the Response()
method when rendering?
If I can't use JsonResponse
to render, can I parse the results directly in twig using its native language? i.e. {{ dump(results) }}
or do I need to include javascript inside scripts tags and process these results first?
EDIT: I think i found a solution to the problem.
when you json_decode($string,TRUE), if its a deeply nested array, then the nested components don't end up as a perfect nested array as i assumed it would, only the top level ones do. Is this a natural side effect of json_decode, or bad json, or what am i doing wrong?
I think this post help shed some light on this. Accessing JSON array after json_decode/multidimensional array
So it appears the problem i was having was the JSON data wasnt completely clean.
i.e.
$requestedResults = ($this->curlRestRequest($apiQueryString, TRUE));
print_r($requestedResults);
//yields Array
(
[category] =>
[executionTime] => 759
[facets] =>
[resultCount] => 8
[searchCount] => 0
[searchInfo] =>
[searchResults] => Array
(
[0] => Array
(
[description] => Gives instructions for 3 different in-class games.
[taxonomyDataSet] => {"course":[],"topic":[],"unit":[],"lesson":[],"subject":[],"curriculum":{"curriculumName":["Common Core State Standards - Math","Common Core State Standards - Math"],"curriculumCode":["CCSS.M.8.G.C.9","CCSS.M.7.G.B.6"],"curriculumDesc":["Solve real-world and mathematical problems involving area, volume and surface area of two- and three-dimensional objects composed of triangles, quadrilaterals, polygons, cubes, and right prisms.","Know the formulas for the volumes of cones, cylinders, and spheres and use them to solve real-world and mathematical problems."]}}
[thumbnail] => slides/thumbnail.jpg
[title] => Game Suggestions for Volume
)
)
which the "curriculumCode" for e.g. wasnt accessible, or anything in the taxonomyDataSet wasnt accessible, via twig, and i had to massage the data a bit to clean it.
$requestedResults = ($this->curlRestRequest($apiQueryString, TRUE));
foreach ($requestedResults['searchResults'] as $resource) {
$title = $resource["title"];
$description = $resource["description"];
$thumbnailUrl = $resource["thumbnails"]['url'];
$taxonomyDataSet = json_decode($resource['taxonomyDataSet'],TRUE);
$standard = $taxonomyDataSet['curriculum']['curriculumCode'];
if(! file_exists($thumbnailUrl))
{
$thumbnailUrl = NULL;
}
$results[] = array($title,$description,$thumbnailUrl, $standard);
}
print_r($results);
//yields
Array
(
[0] => Array
(
[0] => Game Suggestions for Volume
[1] => Gives instructions for 3 different in-class games.
[2] =>
[3] => Array
(
[0] => CCSS.M.8.G.C.9
[1] => CCSS.M.7.G.B.6
)
))
Why Am i having to take this extra step, isn't there a better way to properly iterate over a JSON string so this doesnt happen?
I would MUCH prefer keeping it an object, then simple return it like this in the controller return $requestedResults->searchResults
where i can safely iterate it in TWIG without all the data massaging.
Edit, ok looking into this once again deeper, i believe that the company's API data is to blame, it looks like one particular portion of the results is double json_encoded, and this make sense why the data is not accessible until i massage it. is it me, or does it appear that this is whats happening?