Twig - Output array key if array is referenced - twig

I have a series of templates which target the Twig variable {{ file }}, which currently outputs the file's src e.g. "/path/to/file.jpg".
I want to update the contents of file to an array so that it stores multiple properties e.g. {{ file.src }} {{ file.size }}.
If I make this change then all uses of {{ file }} will output Array.
Is it possible to set Twig so that it will instead target the first property of the array? In this case {{ file.src }}.
Many thanks!

You can't if your variable is a pure array, but you can do it with objects.
If you want your object to be usable like an array, you need to extend ArrayObject in your class.
You can implement the magic method __toString to make your object printable as a string (in your case, $this['src']).
Let's have an example.
1) Create the following class :
class File extends \ArrayObject
{
public function __toString()
{
if (isset($this['src']))
{
return $this['src'];
}
}
}
2) In a controller, initialize your object.
$file = new File();
$file['src'] = 'my_file.png';
$file['size'] = 42;
3) In your twig file, try it :
{{ file }}<br/>
{{ file.src }}<br/>
{{ file.size }}<br/>
4) Enjoy

Related

Interpret variable inside another

I am trying to interpret a variable inside another. Something like:
// list of variables
foo: 'test';
bar: 'this is {{ foo }}'
// Twig
{{ bar }}
// result :
this is a test
I try this but I think it is old : Twig variables in twig variable
You can do this with template_from_string Twig function.
{% set foo = 'test' %}
{{ include(template_from_string('this is {{ foo }}')) }}
The template will render with the context of the containing template, meaning, it will have access to all variables that the main template has access to.
Note that template_from_string Twig function is not available by default. It only becomes available once you activate Twig\Extension\StringLoaderExtension extension found in Twig package.

How to put a dynamic custom attribute in HTML(PUG) in VueJS 2?

I am using VueJs 2 with Pug and I have the following code:
.mb-3(v-for="(payments, index) in historyPayments" :key="index" no-body='')
b-btn(variant="default" block='' href='#' v-b-toggle.accordion2016="") // I need to change accordion2016 using a dynamic variable
| {{ index }}
In my iterator I have data that I would like to put as an attribute in an HTML tag.
The current attribute I have is: v-b-toggle.accordion2016, but I would like to change it to something like in the following code:
.mb-3(v-for="(payments, index) in historyPayments" :key="index" no-body='')
b-btn(variant="default" block='' href='#' "`v-b-toggle.#{index}`"="")
| {{ index }}
How could I change the attribute dynamically using Pug? I have tried but I get syntax error.
You should use v-bind like this:
v-bind="{ [`v-b-toggle.${index}`]: '' }"
By using ES6 template string syntax and single element array, you can bind a variable in an attribute. Finally you only need to use v-bind to bind attrs dinamically in components.
You could use v-b-toggle to toggle a value and have your href as a computed value which is returned based on your toggled value
I.E:
computed: {
computedHref () {
return toggledValue ? "first-href-link" : "second-href-link"
}
}
And just use computedHref value in your href like so
b-btn(variant="default" block='' href='computedHref')
If you use bootstrap vue, then you can do it like this:
.mb-3(v-for="(payments, index) in historyPayments" :key="index" no-body)
b-btn(variant="default" block href='#' v-b-toggle="`accordion${index}`")
| {{ index }}

Call Helper functions inside Twig (Timber)

I try to call a static helper method inside Twig (Timber).
{{ function('Theme\Helpers::get_template_name') }}
Warning: call_user_func_array() expects parameter 1 to be a valid
callback, class 'ThemeHelpers' not found in
/var/www/html/wp-content/plugins/timber-library/lib/Twig.php on line
268.
Does anyone know how to call a method of a different class inside Twig?
As far as I know you can't call PHP classes directly from your twig template.
What you can do is setting up a Twig filter which communicates with your class
and returns the needed value.
You would have this in your php controller file that is responsible to load your twig template:
<?php
function twg_get_template_name() {
# edit this according to the implementation of your class:
return Helpers::get_template_name();
}
function add_to_twig($twig) {
/* this is where you can add your own fuctions to twig */
$twig->addExtension(new Twig_Extension_StringLoader());
$twig->addFilter('twg_get_template_name', new Twig_Filter_Function('twg_get_template_name'));
return $twig;
}
add_filter('get_twig', 'add_to_twig');
In your Twig template you would call the filter like this:
{{ ''|twg_get_template_name }}
Because it's a filter function it expects a value "to filter", so pass at least an empty string.
If I were in that situation I probably would determine the name of the template in your
controller and send the value to your Twig template directly instead of calling the php class
via a filter-function.
You can call static functions from a Twig file in Timber using the array notation, where first item is the name of the class and the second item the name of the static method you want to call:
{{ function( [ 'Theme\Helpers', 'get_template_name' ] ) }}
Thanks for your answer.
I tried your approach - it works. But using a filter feels a little hacky, especially when no value is passed. Why not create a timber function the same way as a filter?
Bridging own functions from plain php into twig is not great, but I also don't see another solution to this.
After playing around a little, I came up with a different approach. I now fixed my need by customizing the Timber Object and adding a template property to the post variable.
Looks something like this:
class OnepagePost extends TimberPost {
var $_template;
// Add template property to Twig Object
public function template() {
return Helpers::get_template_name( $this->custom['_wp_page_template'] );
}
}
Then inside the .php file where the Twig View gets called, I called the custom object like this:
$context['posts'] = new Timber\PostQuery( $args, 'OnepagePost' );
Timber::render('onepager.twig', $context);
Inside the Twig Template I'm able to get my custom property very easy (in my way the template):
{% for post in posts %}
{% include ["section/section-#{post.template}.twig"] %}
{% endfor %}

How to get route link in Slim3 Twig?

I defined my route so:
$app->get('/about', function ($request, $response, $args) {
return $this->view->render($response, 'about.twig');
})->setName('about.page');
I'm interested to get route link by name like: {% get_route('about.page') %}
How can I achieve this?
In Slim3 there is the path_for(name) function. F.ex:
{{ path_for('about.page') }}
Reference: http://www.slimframework.com/docs/features/templates.html
The slim/twig-view component exposes a custom path_for() function to your Twig templates. You can use this function to generate complete URLs to any named route in your Slim application. The path_for() function accepts two arguments:
1 A route name
2 A hash of route placeholder names and replacement values
Note: The path_for uses the function of the router which is $router->pathFor(..)
Why not to use {%
{% is a control structur in twig, Message: Unknown "path_for" tag in "base.twig" at line XX. is displayed because there is no such tag as control structur defined so twig doesn't know that this is actually a function.
So use the output structur in twig {{.
Is this possible?
Yes.
IIRC
{{ path_for('about.page') }}
Reference:
https://github.com/slimphp/Twig-View/blob/master/src/TwigExtension.php#L37

Twig : Access to variable from outer scope in a form widget customization

I'm trying to customize a specific widget, like in the documentation : http://symfony.com/doc/current/cookbook/form/form_customization.html#how-to-customize-an-individual-field
The problem is that in this custom block, I need to use a variable from my actual template. I thought "blocks have access to variables from outer scopes", but apparently not in this case :
{% extends "CDASvBundle::layout.html.twig" %}
{% block _contact_activity1_widget %}
<select name="contact[activity1]">
{% for key, child_contact_categories in contact_categories_tab %}
<option value="{{key}}">{{child_contact_categories}}</option>
{% endfor %}
</select>
It's saying that contact_categories_tab is undefined, but outside of this block (in the normal content block for example), it works !
I tried something like :
{% use 'form_div_layout.html.twig' with contact_categories_tab as contact_categories_tab %}
But that doesn't either.. Though I'm not sure I understand if I have to use use and how !
I see one other solution that I haven't tried yet : put this customization in another template. But I don't really want to do that (few lines in a new template), there should be a way to do that in only ONE template ?!
Finally found the answer in a previous post :
Each symfony form type extents AbstractType class.
AbstactType class has method:
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->set('img_src', '120x100.jpg');
$view->set('my_variable', $foo);
}
You can create this method on your form type and next in your twig:
{{ asset(img_src) }}
Source : How to get entity or pass variable to Symfony2 twig form widget?

Resources