Decoding JSON in Twig

Is is possible to decode JSON in twig? Googling doesn't seem to yield anything about this. Does decoding JSON in Twig not make sense?


I'm trying to access 2 entity properties on an Symfony2's entity field type (Entity Field Type).

After coming across 2 previous SO questions ( Symfony2 entity field type alternatives to "property" or "__toString()"? and Symfony 2 Create a entity form field with 2 properties ) which suggested adding an extra method to an entity to retrieve a customized string rather than an entity attribute, I thought of (and did) returning a JSON string representing an object instance.

Somewhere in the entity class:

/**
 * Return a JSON string representing this class.
 */
public function getJson()
{
   return json_encode(get_object_vars($this));
}

And in the form (something like):

$builder->add('categories', 'entity', array (
...
'property' => 'json',
...
));

Afterwards, I was hoping to json_decode it in Twig...

{% for category in form.categories %}
    {# json_decode() part is imaginary #}
    {% set obj = category.vars.label|json_decode() %}
{% endfor %}

That's easy if you extend twig.

First, create a class that will contain the extension:

<?php
 
namespace Acme\DemoBundle\Twig\Extension;

use Symfony\Component\DependencyInjection\ContainerInterface;  
use \Twig_Extension;

class VarsExtension extends Twig_Extension
{
    protected $container;
 
    public function __construct(ContainerInterface $container) 
    {
        $this->container = $container;
    }
      
    public function getName() 
    {
        return 'some.extension';
    }
    
    public function getFilters() {
        return array(
            'json_decode'   => new \Twig_Filter_Method($this, 'jsonDecode'),
        );
    }

    public function jsonDecode($str) {
        return json_decode($str);
    }
}

Then, register that class in your Services.xml file:

<service id="some_id" class="Acme\DemoBundle\Twig\Extension\VarsExtension">
        <tag name="twig.extension" />
        <argument type="service" id="service_container" />
</service>

Then, use it on your twig templates:

{% set obj = form_label(category) | json_decode %}

An alternative to all above.
And I don't know whether this is the optimal solution, but it works.

1) Create a helper function and register that function it.

<?php
function twig_json_decode($json)
{
    return json_decode($json, true);
}


2) Use this function in your twig file.

{% set res = twig_json_decode(json) %}
# above will return an array which can be iterated

{% for r is res %}
    {{ r }}
{% endfor %}

I came up with a way of getting to my JSON and I thought I'd share it here in case its usefult to someone else.

so in my case I have maybe 10 records (layouts) returned from a mysql db and each row has a field called properties which is a json string. So, I can easily pull out the records and send them to the template like so:

echo $twig->render('template.html.twig', array(
      "layouts" => $layouts,
));

So far so good, However when I do my {% for layout in layouts %} in twig there is no way to get to the properties field items as they are still a json string.

So just before I passed $layouts to the twig template I did the following:

foreach($layouts as $i => $v)
{
      $layouts[$i]->decoded = json_decode($v->getProperties());
}

by doing this Ive created a variable on the fly within my object called 'decoded' which contains the json decoded object.

So now in my template I can access my json items by {{ layout.decoded.whatever }}

This might be a bit hacky and not to everyones idea of a good solution. I works well for me, very little overhead and means I dont have to mess about with extending twig as Im doing the work before it gets to the template.


Updated code for Symfony2.8 or Symfony3:

<?php

namespace Acme\DemoBundle\Twig\Extension;

use Symfony\Component\DependencyInjection\ContainerInterface;  
use \Twig_Extension;

class VarsExtension extends Twig_Extension
{
    protected $container;

    public function __construct(ContainerInterface $container) 
    {
        $this->container = $container;
    }

    public function getName() 
    {
        return 'some.extension';
    }

    // Note: If you want to use it as {{ json_decode(var) }} instead of 
    // {{ var|json_decode }} please use getFunctions() and 
    // new \Twig_SimpleFunction('json_decode', 'json_decode') 
    public function getFilters() {
        return [
            // Note that we map php json_decode function to 
            // extension filter of the same name
            new \Twig_SimpleFilter('json_decode', 'json_decode'),
        ];
    }
}

This is an old question but I'm adding my solution for the record... Just extend Twig with a SimpleFunction:

// Return a string of separated values from a JSON string
// Can optionally specify a separator.  If none provided, ", " is used.
$function = new Twig_SimpleFunction('json_to_list', function($json, $separator = ", ")
{
    $result = "";
    $array = json_decode($json, true);
    foreach ($array as $item)
    {
        if ($result != "") { $result .= $separator; }           
        $result .= $item;
    }
    return $result;
});
$twig->addFunction($function);

Usage:

set a_json_variable to the string '["1","2","3","4","5"]' before calling the Twig render.

Twig template:

The values are: {{ json_to_list(a_json_variable) }}

Will produce

The values are: 1, 2, 3, 4, 5