4

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?

10
  • Yes, people should not be down voting the question unless it is terrible. Just vote for close if it is unclear since unclear questions can be fixed (but down votes can't). Commented Feb 18, 2014 at 17:57
  • 1
    This question was terrible. It was terribly phrased and caught up in things like how long he'd been working on it and punctuation. Please refer to sscce.org for how to ask a question. Note that while I voted to reopen this question, it is still not very clear. I recommend being specific: name the method you're referring to rather than saying "a method" or "another method". Commented Feb 18, 2014 at 18:22
  • hope that clears it up a bit. i tried my best. Commented Feb 20, 2014 at 22:25
  • Do you want to get data from an API and 1) process it, "JSON" it and use it with a javascript caller 2) process it, "JSON" it and use it with a php script and update the page, 3) process it, "JSON" it and try to use it in a random template to pass it to a javascript, 4) some thing else? An actual question would be grand. Commented Feb 21, 2014 at 1:14
  • Ok, I am getting data from an API call which is being returned in JSON format. I am trying to learn the different ways to use 'symfony response to twig'. I have been able to take this json data and use symfony Reponse() to render a template which then has access to iterate over the param variable thats sent to the template in the response. This part i have figured out, and it works. What im having a hard time figuring out is how to do this same thing, using JsonResponse(). i.e. how i would access this type of response on a twig template? I try to dump it, and its just not available. Commented Feb 21, 2014 at 8:34

2 Answers 2

1

I’m not sure if I understood the question, but let’s go:

In my opinion, you should process your API result before send it to the view, that means you should parse the JSON string into PHP objects, create an array of it, and then iterate on twig as normal.

So, focus your effort on develop a piece of code that turns your JSON string into an array of objects; and don’t pass logic to the view.

Sign up to request clarification or add additional context in comments.

1 Comment

Hi Issac, I think thats what I did, see my last code snippet. I had to massage the data, e.g. see how i packaged up the curriculumCode into $standard, before sending it to the view. I guess the issue was, this wasnt anticipated, for the data to be inconsistent, and had to do alot of massaging in php code, and wanted to make sure I wasnt missing out on some twig methodology that would help overcome do all the repairing of that data in php, which became a bit tedious. I see, and appreciate your point. I know i said "via twig", I just cant recall now if i did that in the model or not.
0

Consider using FOSRestBundle, it will handle your request and return correct JSON responses "automatically". It is simple to configure basic usage and then you have to only follow conventions to achieve simple and valid REST API.

You can use Guzzle as API client for retrieving data. You can write some client class and provide methods implementing some logic (method for each resource). Then in those methods you simply use, for example, $response = $guzzleClient->get($url, $options) and under $reponse->json() you have all the data which you can process and serve in your own API response.

You should register that API client as service and use it in own controllers to retrieve data, then process it and return expected result from controller's action. You can handle it then by FOSRestBundle+JMSSerializerBundle to make JSON response (you can return XML too, it's a matter of using allowed formats and requesting resource with format parameter provided - for example getting /api/users.xml would return XML file, while /api/users.json will result in JSON).

This is wide topic and it's nearly impossible to describe all the stuff you have to do in order to achieve what you want, but I believe it will help you to get right resolution.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.