Lets say I have an associative array like so:
{% set settings = { 'foo':'bar', 'cat':'mouse', 'apple':'banana' } %}
To use this data I would do the following:
{{ settings.foo }}
{{ settings.cat }}
{{ settings.apple }}
However, I wondered if there is a way to extract the keys to variables, and the values to values? Essentially the same as the PHP Extract function. So I can just do this instead:
{{ foo }}
{{ cat }}
{{ apple }}
My very amateurish attempt to do this started out like this:
{% for key,val in settings %}
{% set key = val %}
{% endfor %}
But obviously that doesn't work (or I wouldn't be here). Is there another approach I could take?
Thanks,
Mark
As most things in Twig this can be done by extending Twig
ProjectTwigExtension.php
class ProjectTwigExtension extends Twig_Extension {
public function getFunctions() {
return array(
new Twig_SimpleFunction('extract', array($this, 'extract'), ['needs_context' => true, ]),
);
}
public function extract(&$context, $value) {
foreach($value as $k => $v) $context[$k] = $v;
}
public function getName() {
return 'ProjectTwigExtension';
}
}
Register class in Twig
$twig = new Twig_Environment($loader);
$twig->addExtension(new ProjectTwigExtension());
template.twig
{{ extract({'foo': 'bar', }) }}
{{ foo }} {# output : bar #}
(sidenote) Seems you can't do this by using a closure (see example below) because the compiler of Twig passes the variables in an array, thus creating a copy
With closure
$twig->addFunction(new Twig_SimpleFunction('extract', function (&$context, $value) {
foreach($value as $k => $v) $context[$k] = $v;
}, ['needs_context' => true, ]));
Compiled result
echo twig_escape_filter($this->env, call_user_func_array($this->env->getFunction('extract')->getCallable(), array($context, array("foo" => "bar", "foobar" => "foo"))), "html", null, true);
Related
I have the following variables in twig:( I can see them with kint)
data.po_user_setting.us_highlight_color1 = '#008080'
data.po_user_setting.us_highlight_color2 = '#00FFFF'
data.po_user_setting.us_highlight_color3 = '#FFFF00'
data.po_user_setting.us_highlight_color4 = '#FF0000'
data.po_user_setting.us_highlight_color5 = '#FF00FF'
and
verse.po_verse_highlight.hl_rating = Returns [1-5]
How can I show the dynamic variable like this? Neither of these lines work:
{{_context['data.po_user_setting.us_highlight_color' ~ verse.po_verse_highlight.hl_rating]}}
{{attribute(_context, 'data.po_user_setting.us_highlight_color' ~ verse.po_verse_highlight.hl_rating)}}
The problem you are facing is the variable you want to access is actually an array.
With your current code, twig is looking for a variable called e.g., data.po_user_setting.us_highlight_color.foo, translated to $_context['data.po_user_setting.us_highlight_color.foo']
To actually access the variable you want, you would need to treat the variable like an array:
{{ {{ _context['data']['po_user_setting']['us_highlight_color'~ verse.po_verse_highlight.hl_rating] }} }}
This is quite long to type every time, so to reduce the typing you could use a macro or extend twig
macro
{% macro get_array_value(context, key) %}
{% set value = null %}
{% for key in key|split('.') %}
{% set value = loop.first ? context[key]|default : value[key]|default %}
{% endfor %}
{{ value }}
{% endmacro %}
As macro's don't have access to the special variable _context you would to pass this every time when you want to call the macro, e.g.
{% import _self as macros %}
{{ macros.get_array_value(_context, 'data.po_user_setting.us_highlight_color' ~ verse.po_verse_highlight.hl_rating) }}
extending twig
<?php
$twig->addFunction(new \Twig\TwigFunction('get_array_value', function ($context, $variable) {
$keys = explode('.', $variable);
if (empty($keys)) return;
$value = $context[array_shift($keys)] ?? [];
foreach($keys as $key) {
$value = $value[$key] ?? [];
}
return !empty($value) ? $value : null;
}, ['needs_context' => true,]));
Then you can call this function like the following in twig
{{ get_array_value('data.po_user_setting.us_highlight_color' ~ verse.po_verse_highlight.hl_rating) }}
I want to retrieve a JSON from a webservice and incorporate it into a Twig template.
I went through the docs and I found that I could use this option.
I have followed the steps from the doc and I have prepared this plugin:
/var/www/html/grav/user/plugins/category# ls
category.php category.yaml twig
/var/www/html/grav/user/plugins/category# cat category.yaml
enabled: true
/var/www/html/grav/user/plugins/category# cat category.php
<?php
namespace Grav\Plugin;
use \Grav\Common\Plugin;
class CategoryPlugin extends Plugin
{
public static function getSubscribedEvents()
{
return [
'onTwigExtensions' => ['onTwigExtensions', 0]
];
}
public function onTwigExtensions()
{
require_once(__DIR__ . '/twig/CategoryTwigExtension.php');
$this->grav['twig']->twig->addExtension(new CategoryTwigExtension());
}
}
/var/www/html/grav/user/plugins/category# cat twig/CategoryTwigExtension.php
<?php
namespace Grav\Plugin;
class CategoryTwigExtension extends \Twig_Extension
{
public function getName()
{
return 'CategoryTwigExtension';
}
public function getFunctions()
{
return [
new \Twig_SimpleFunction('get_child_category', [$this, 'getChildCategoryFunction'])
];
}
public function getChildCategoryFunction()
{
$json = file_get_contents('http://localhost:8888/get_child_category/2/es_ES');
$obj = json_decode($json);
return $json;
}
}
I then incorporate the following function invocation in the Twig template:
{{ get_child_category() }}
But:
I can get $json string, but how can I pass the whole JSON data and retrieve individually the fields?
In my case if I use:
<span>{{ get_child_category() }}</span>
in Twig I get the following string:
[{"id": 11, "name": "Racoons"}, {"id": 10, "name": "Cats"}]
How would I access individual records in Twig, including iteration over the JSON array and individual field extraction (id, name) for each record?
Your function is returning an array. You need to iterate through it. Here is an example from the Grav docs.
<ul>
{% for cookie in cookies %}
<li>{{ cookie.flavor }}</li>
{% endfor %}
</ul>
A simple list of names from your example is a simple edit.
<ul>
{% for child in get_child_category() %}
<li>{{ child.name }}</li>
{% endfor %}
</ul>
In twig template I have an object with multiple levels
I need to add a new object into the multiple object as the sub object
{%
set data = {
'first': 'First',
'data': {
'val_1': 'val_1'
}
}
%}
this should be added to data val_2: val_2
expected result:
{%
set data = {
'first': 'First',
'data': {
'val_1': 'val_1',
'val_2': 'val_2'
}
}
%}
First, in Twig terminology, that's not an object or a key-value array but a hash (see Twig's documentation of literals).
You can't add an item to a hash e.g. by doing {% set data.second = 'Second' %}. Instead you need to use the merge filter:
{%
set data = data|merge({
second: 'Second',
})
%}
{{ dump(data) }}
{# Prints this:
array(3) {
["first"]=>
string(5) "First"
["data"]=>
array(1) {
["val_1"]=>
string(5) "val_1"
}
["second"]=>
string(6) "Second"
}
#}
So, to add an item to a hash inside a hash, you need to use the merge filter twice:
{%
set data = data|merge({
data: data.data|merge({
val_2: 'val_2',
}),
})
%}
{# Prints this:
array(3) {
["first"]=>
string(5) "First"
["data"]=>
array(1) {
["val_1"]=>
string(5) "val_1"
["val_2"]=>
string(5) "val_2"
}
["second"]=>
string(6) "Second"
}
#}
If you do lots of this kind of variable manipulation in Twig, it might be a sign that some of that code might be better put in a controller or model or whatever.
I have a question, I have this code :
{% set texte_article = 'Simple text' %}
{% set url_article = 'simple/url' %}
What is the idea of text_article|twitter_share..., I don't understand what do |. Can you help me please ? Thx in advance
And what is the difference between : {{ 40|lipsum }} and {{ lipsum(40) }} ?
the filter method is :
public static function getShareLink($s_url)
{
$a_params = array(
'url' => 'url',
'hl' => 'share'
);
return self::URL . http_build_query($a_params, '', '&');
}
| is to apply a Twig fliter.
I guess you have a twitter_share_link function in your project which need url_article as parameter
I am new to the Symfony2 framework and am trying to parse some XML from the lastfm API and display information to the user. this would be in the format of album title, playcount and album image for each item.
I can display all this information so far to the user but this is not really useful as I intend to add CSS styling to my page. Any suggestions would be appreciated.
This is my Controller
/**
* #Route("/lastfm/albums", name="albums")
* #Template()
*/
public function albumsAction()
{
$albumsclass = new Album();
// pull in artist albums
$albums = simplexml_load_file('http://ws.audioscrobbler.com/2.0/? method=artist.gettopalbums&artist=imagine+dragons&api_key=370f98844440c2ecc8e5f7 c6cea8a7a4');
$rank = $albums->xpath('/lfm/topalbums/album/#rank');
$album_name_array=array();
$album_playcount_array=array();
$album_url_array=array();
$album_image_array=array();
foreach ($rank as $ranks){
foreach ($ranks as $rank_id) {
$album_name = $albums->xpath('/lfm/topalbums/album[#rank="'.$rank_id.'"]/name');
$album_playcount = $albums->xpath('/lfm/topalbums/album[#rank="'.$rank_id.'"]/playcount');
$album_url = $albums->xpath('/lfm/topalbums/album[#rank="'.$rank_id.'"]/url');
$album_image = $albums->xpath('/lfm/topalbums/album[#rank="'.$rank_id.'"]/image[4]');
}
$album_name = implode($album_name);
array_push($album_name_array,$album_name);
$album_playcount = implode($album_playcount);
array_push($album_playcount_array,$album_playcount);
$album_url = implode($album_url);
array_push($album_url_array,$album_url);
$album_image = implode($album_image);
array_push($album_image_array,$album_image);
}
$container=array();
for($i=0; $i<sizeof($album_name_array); $i++) {
array_push($container,$album_name_array[$i],$album_playcount_array[$i],$album_ur l_array[$i],$album_image_array[$i]);
}
//$hello = array('album_name'=>$album_name_array,
// 'album_playcount'=>$album_playcount_array,
// 'album_url'=>$album_url_array,
// 'album_image'=>$album_image_array,);
//array_push($album_name_array,$album_playcount_array);
return $this->render('AcmelastfmBundle:Default:albums.html.twig', array(
// 'pageData' => array(
// 'artistxml' => $artistxml,
'rank' => $rank,
'ranks' => $ranks,
//'rank_id' => $rank_id,
// 'ranks' => $ranks,
'album_name' => $album_name_array,
//'album_playcount' => $album_playcount_array[$i],
'album_url' => $album_url_array,
'album_image' => $album_image_array,
'container' =>$container,
'data' => var_export($container, true),
//
// 'hello' => $hello,
// 'james' => array('album_name' => $albumsclass->getAlbumName()),
// ),
));
}
This is my view
{% extends '::lastfmbase.html.twig' %}
{% block title %}Albums{% endblock %}
{% block body %}
{% for key in container %}
{{key}} <br>
{% endfor %}<br>
{% endblock %}
I am basically trying to convert this code in PHP to symfony2. However I cannot find a way to pass the associative array values to twig as I get an array to string conversion error
<?php
// pull in artist albums
$albums = simplexml_load_file('http://ws.audioscrobbler.com/2.0/? method=artist.gettopalbums&artist=imagine+dragons&api_key=370f98844440c2ecc8e5f7 c6cea8a7a4');
$rank = $albums->xpath('/lfm/topalbums/album/#rank');
foreach ($rank as $ranks){
foreach ($ranks as $rank_id) {
$album_name = $albums->xpath('/lfm/topalbums/album[#rank="'.$rank_id.'"]/name');
$album_playcount = $albums->xpath('/lfm/topalbums/album[#rank="'.$rank_id.'"]/playcount');
$album_url = $albums->xpath('/lfm/topalbums/album[#rank="'.$rank_id.'"]/url');
$album_image = $albums->xpath('/lfm/topalbums/album[#rank="'.$rank_id.'"]/image[4]');
}
$album_name = implode($album_name);
$album_playcount = implode($album_playcount);
$album_url = implode($album_url);
$album_image = implode($album_image);
print_r($rank_id);
?>
<article class="album">
<?php
echo "".$album_name."<br>";
echo $album_playcount." listeners<br>";
echo "<div><img src=\"".$album_image."\" title=\"$album_name\" /></div><br>";
?>
</article>
<?php
}
I am not sure exactly what you are asking.
Do you mean this?
{% for key, value in container %}
{{ key }}: {{ value }}
{% endfor %}