How to access JSON data in a twig template?

13,063

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.

Share:
13,063

Related videos on Youtube

blamb
Author by

blamb

Cloud and Web Architecture are my strong suits. Cloud(AWS)/Linux SRE/DevOps, web services development, RESTful, IOT/anything web, creating frameworks and stacks, based mainly on the frontier of open source, or open source derivatives. You know you have a career match when you don't want to stop your days work, just have more work to do and want to get it done, and your spouse has a hard time peeling you off the linux terminal late at nights...

Updated on June 05, 2022

Comments

  • blamb
    blamb almost 2 years

    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?

    • Nathaniel Ford
      Nathaniel Ford about 10 years
      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".
  • blamb
    blamb over 4 years
    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.