I know twig can count elements of an array using {{ array|length}}, but is there a way to combine this feature with an if or where statement?
Something like {{ array|length|array.key is null }}, where it would count all the instances where key is null.
The filter filter should help you achieve this.
Something like
{% set array = [null, 42, null, null, 42] %}
{{ array | filter(item => item is null) | length }}
Outputs 3
And so if I understand your data structure correctly:
{% set array = [{key: null}, {key: 42}, {key: null}, {key: null}, {key:
42}] %}
{{ array | filter(item => item.key is null) | length }}
Related
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.
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);
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've encountered this problem. I wanted to merge these two hashes:
{% set additional_context = {
attributes:{
'class': 'post-link',
'data-confirm-text': params.confirm
}
} %}
{% set ajax_context = {
attributes: {
'class': '',
'data-href': target,
}
} %}
Doing this:
{% additional_context = additional_context|merge(ajax_context) %}
would override additiona_context.attributes with ajax_context.attributes.
I'd like to have attributes hashes merged as well, not overriden. I cannot change the name of the sub-hash - it has to be attributes.
I didn't find a neat way to do it. Ideas much appreciated. Thanks
In PHP I can designate which element / property to use simply by passing a variable with the name of it, such as:
$array[$name]
$object -> $name
How to do this with Twig?
For instance, with an array row read from MySQL database whose primary key field can be id, ItemId, Serial, number, or anything, how can I pass in the column name of the primary key so Twig correctly displays the primary key of the row?
{{ row.id }}
{{ row.ItemId }}
{{ row.Serial }}
{{ row.number }}
But just something like:
{{ row.primary }}
Wherein primary is the name of the actual column name of the primary key, be it id, ItemId, or whatever.
Any way I can do this?
Seems rather simple, just use attribute().
Pass:
array(
'primaryKey' => 'id'
'row' => array(
'id' => 1,
'title' => 'some title'
)
)
In twig template:
{{ attribute(row, primaryKey) }}
Which would have the same effect as:
{{ row.id }}