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 %}
7

Best Answer


That's easy if you extend twig.

First, create a class that will contain the extension:

<?phpnamespace 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 %}

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.

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.

<?phpfunction 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 %}

Updated code for Symfony2.8 or Symfony3:

<?phpnamespace 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 namenew \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

Just going to leave this here:

if some one is trying to pass json to a twig extension ..and they can't phrase it because its escaped ect.this may be just what they are after.

$data_array = json_decode(html_entity_decode($data_string), true);

In my case i have got an JsonArray in my Entity then i've add in my Entity a methode

<?phpnamespace ACME\DefaultBundle\Entity;/*...*/ public function getDecodedPath(){return json_decode($this->path);}