1

We are using twig render engine, to populate json with payload data.

Or said in other words:

{
    "payload": {
        "sld": "{{sld}}",
        "tld": "{{tlds}}"
    }
}

I am looping all variables and "rendering" the values. When everything is strings, it is working perfectly


{
    "payload": {
        "sld": "test",
        "tld": "com"
    }
}

BUT, if any of the twig variables is array it is crashing. Or said with other words:

{{tlds}} is array === ["com", "net"]

because it is stored in json, I can not write it without the string quotes "".

The expected result should be:

{
    "payload": {
        "sld": "test",
        "tld": ["com", "net"]
    }
}

Can you help me with a solution or workaround?

4
  • 2
    Why are you using twig to render JSON? Commented Nov 16, 2020 at 12:38
  • 2
    https://twig.symfony.com/doc/2.x/filters/json_encode.html might help Commented Nov 16, 2020 at 12:39
  • 2
    Don't build a JSON string manually. Build an object and JSON encode it. Commented Nov 16, 2020 at 12:41
  • The "end customer", via UI is setting what data is required for specific functionality. (Stored in DB in json). We are using twig due to the huge library of tools for manipulating the data. But in the case, when we want to pass the whole array node, we are hitting a huge issue. Commented Nov 16, 2020 at 12:46

2 Answers 2

1

As pointed in the comments, you should use the built in json_encode filter for that.
This said, doing this only would result in an HTML encoded version of you JSON object. In order to overcome this, you will also have to use the raw filter.

So with this one liner of Twig:

{{ data | json_encode() | raw }}

And data like:

$data = [
  [
    "payload" => [
      "sld" => "test",
      "tld" => "com"
    ]
  ],
  [
    "payload" => [
      "sld" => "test",
      "tld" => [
        "com",
        "net"
      ]
    ]
  ]
];

This will gives you the this JSON (beautified for a matter of readability):

[
   {
      "payload":{
         "sld":"test",
         "tld":"com"
      }
   },
   {
      "payload":{
         "sld":"test",
         "tld":[
            "com",
            "net"
         ]
      }
   }
]

All of this being testable here: https://twigfiddle.com/i604iv

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

Comments

0

After some testing and brainstorming, I've decided to remove the twig renderer and migrate it to a more simple version.

Long story short, this will render all {{variable.something}} like syntax and will populate it with the corresponding value from the payload.

IF the value is an array, it will json encode it, and after that decode it, in order to achieve the requested functionality.


 private function renderVariables(array $variables = [], array $payload = [])
    {
        $rendered = [];

        foreach ($variables as $key => $value) {
            if (is_array($value)) {
                $rendered[$key] = $this->renderVariables($value, $payload);
            } else {
                $rendered[$key] = $this->replaceMarkdown($value, $payload);

                if (strpos($rendered[$key], '[') !== false || strpos($rendered[$key], '{') !== false) {
                    $rendered[$key] = json_decode($rendered[$key]);
                }
            }
        }
        return $rendered;
    }

    public function replaceMarkdown(string $param, array $argv)
    {
        return preg_replace_callback('/\{\%\s*(.*)\s*\%\}|\{\{(?!%)\s*((?:[^\s])*)\s*(?<!%)\}\}/i',
            function ($field) use ($argv) {
                $field = $field[2];

                if (strpos($field, '.') !== false) {
                    $fields = explode('.', $field);
                } else {
                    $fields = array($field);
                }

                $currentData = $argv; # we should take care for magic before foreach

                foreach ($fields as $currentField) {
                    if (isset($currentData[$currentField])) {
                        $currentData = $currentData[$currentField];
                    } else {
                        return $field . '-not-found';
                    }

                }
                if (is_array($currentData)) {
                    $currentData = json_encode($currentData);
                }
                return (string)$currentData;
            }, $param);
    }

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.