Using twig translations inside Moustache inside Twig - symfony

I have a moustache template inside my twig template. I use the moustache template in javascript and it contains some text and JS variables.
{# _partial.html.twig #}
{% verbatim %}
<script id="insuranceOptionTpl" type="text/template">
{{ #. }}
<strong>My template is {{ adjective }}</strong>
{{ /. }}
</script>
{% endverbatim %}
Now I need to internationalize this page but my twig translations won't work inside verbatim. Is there any elegant ways to do that? I will probably have many different texts to translate, so ending and starting a new verbatim block all the time is not ideal.

By removing the verbatim block and by customizing Twig delimiters to be differents than Mustache ones, replacing {{ and }} by [[ and ]] for example (as explained in Twig doc), you'll be able to use Twig and Mustache in the same template:
$twig = new Twig_Environment();
$lexer = new Twig_Lexer($twig, array(
'tag_comment' => array('{#', '#}'),
'tag_block' => array('{%', '%}'),
'tag_variable' => array('[[', ']]'),
'interpolation' => array('#{', '}'),
));
$twig->setLexer($lexer);
As most of your templates are already in Twig, you can change Mustache delimiters instead:
$(document).ready(function () {
var output = $("#output");
var template = $("#insuranceOptionTpl").html();
//Custom tags for Mustache
var customTags = [ '[[', ']]' ];
Mustache.tags = customTags;
// render string
var data1 = "Hello world!";
var html = Mustache.render(template, data1);
output.append(html);
});

Related

Is it possible to pass twig variables into templates?

I'm using the Timber plugin for my Wordpress site. For a little button component, i'm trying to pass the variable {{ site.link }} to use as my href.
Like so:
{% include 'component/icon-button.twig' with { href: '{{ site.theme.link }}/faq' } %}
icon-button.twig
<button class="icon-button" data-href="{{ href }}">text</button>
But that only results in {{ site.link }}/faq being output as is, as a string, not the actual URL.
How would i do this?
That's just because when you use include in twig you don't need to use double {{ again. The correct syntax would be:
{% include 'component/icon-button.twig' with { href: site.theme.link ~ '/faq' } %}
The "~" is used for string concatenation in twig. You were passing the whole thing as a string and nothing more =)

call twig function from custom twig function

I created a custom twig function in AppExtension Class. I need to call form_label() from this new function. ¿Is it posible? I tried but does not work:
from template I call:
{{ myFunc(form.someField) }}
public function myFunc( $field )
{
$html = form_label($field);
}
The idea is to render each form field in a different order/way than the form_widget(form) twig function. The "form_label()" function it's not reconized.
Thx for any suggestion.
I feel like this is the wrong approach to handle this. Extensions are for transforming data not really to manipulate the form definition itself.
First of all the order is defined as in the form type, so you can swap those around. To render the fields differently you can use form themes, or even rendering a custom form type.
Alternatively if its a one time thing (you could also create a macro for this) you can also instead of form_widget(form) order them in the way you like.
{{ form_start(form) }}
{{ form_row(form.field3) }}
{{ form_row(form.field1, { attr: { class: 'im-different' } }) }}
{{ form_row(form.field2) }}
{{ form_end(form) }}
Or even go deeper.
{{ form_start(form) }}
{{ form_row(form.field3) }}
<div>
{{ form_label(form.field1) }}
{{ form_widget(form.field1) }}
{{ form_errors(form.field1) }}
</div>
{{ form_row(form.field2) }}
{{ form_end(form) }}
To see these functions and how they all rendered by default you can look at form_div_layout.html.twig.
I agree with Jenne van der Meer and Nico Haase that your approach isn't particularly optimal. If I had the choice, I would go a different route: Instead of rendering in your function, render in twig, then pass the result to the function (like {{ myFunc(form_label(form), form) }}). Since you omit what your function actually needs and/or does, it's hard to provide further advice. However, I'm absolutely sure, that rendering can be done in twig before or after entering your function, via a macro/block, maybe even a form theme).
However, if you really really require your function to render the form field ... the following will possibly help you. I strongly advise against doing this, there's probably a better suited solution.
The form_label function is slightly more complex than a simple function. Instead, it uses twig's compile mechanisms to generate specific php code. It will eventually call:
FormRenderer::searchAndRenderBlock(FormView $view, string $blockNameSuffix, array $variables = [])
Diving deep into the compiler, the template call form_label(form, options) would be turned into:
$this->env->getRuntime('Symfony\Component\Form\FormRenderer')->searchAndRenderBlock(
$form, 'label', $options
);
where the $this->env seems to be the twig environment. That means, to call this in your twig extension you need to have access to the proper Twig environment, and then it should already work with the recipe I just provided. Especially if you can omit the options argument, I didn't take a deeper look into how that one's assembled (but it's probably just straight forward).
So your twig function must be defined via:
public function getFunctions(): array
{
return [
new TwigFunction('myFunc', [&$this, 'myFunc'], [
'needs_environment' => true, // <--- this!
'is_safe' => ['html'],
]),
];
}
public function myFunc(\Twig\Environment $env, $field) {
// other stuff
$html = $env->getRuntime(\'Symfony\Component\Form\FormRenderer\')->searchAndRenderBlock(
$field, 'label', $options
);
return $html;
}

Save charts on server

I have a symfony3 project with working Highcharts functions implemented through the ob/highcharts-bundle and I really like the way the generated charts look with a custom theme.
I would like to be able to run a script on the server that generates an email and along the way builds the charts that I need (complete with my custom theme) and saves to the server so I can link to them from the email.
I've previously done this in pChart, and saving an image on the server from a script is as easy as $myPicture->autoOutput('myimage.png'). While that's easy, I prefer the look of charts from Highcharts.
Is there a similar simple way to do this something like this using Highcharts?
My scripts look like this:
// Controller
$xdata = array(1, 2, 3, 4);
$data_series = array(
0 => array(
"name" => "Series 1",
"data" => array(
0 => 2.0, 1 => 0.0, 2 => 5.0, 3 => 2.3, 4 => 0.45, 5 => 0.4
)
)
);
$ob = new Highchart();
$ob->chart->renderTo('trendchart'); // id of the div where the chart gets rendered
$ob->title->text('Chart title');
$ob->xAxis->categories($xdata);
$ob->series($data_series);
return $this->render('dashboard/main.html.twig', [
'trendChart' => $ob,
]);
and I render this in a twig template:
// twig template
{% extends 'base.html.twig' %}
{% block javascripts %}
{{ parent() }}
<script src="//code.highcharts.com/highcharts.js"></script>
<script src="//code.highcharts.com/modules/exporting.js"></script>
<script src="{{ asset('js/highchartThemes/mytheme.js') }}"></script>
<script>
{{ chart(trendChart) }}
</script>
{% endblock %}
{% block body %}
<div id="trendchart"></div>
{% endblock %}
What I'm hoping for is to make a call from my controller like:
$ob->save('myimage.png');
Does anyone know of a simple/clean way to do something like this?

Symfony - pass custom data from Form Builder to form theme

I would like to set a special div surrounding a bunch of my fields. For that I want to add something to the form builder that I could detect in my form_theme, and set the div when it's there.
I tried to add
->add('field', new myCustomType(), array('inherit_data' => true, "label" => false, "required" => false, 'attr' => array("test" => "aaa")))
to the form builder, setting an custom attr, it's actually rendered in the html as an attribute... But I'm unable to detect it in the form theme.
{{ block('widget_container_attributes') }}
Only gives the widget attributes, and
{{ block('row_container_attributes') }}
doesn't work. I actually have a hard time finding any source online about what variables are available in the blocks of the form theme and how to use them (it was already difficult to know how to call blocks).
I looked for some more information on the official site, here mostly but without any success...
Thanks ahead for any help !
If you put it in your form builder, then you might as well permanently set in your template. If there is some logic required to set the data, then that belongs in your controller anyway, so just put it there to start with.
Controller:
public function someAction()
{
// ....
return $this->render('some_twig_template.twig.html', array(
'attr' => array("test" => "aaa")
);
}
Then in your twig template
{{ dump(attr) }}
{{ dump(attr.test) }}
EDIT:
To render in your template every time, you can set a class on the rendered field directly:
{{ form_label(form.field, 'My label', { 'label_attr': {'class': 'js-hidden-row'} }) }}
{{ form_widget(form.field, { 'attr': {'class': 'js-hidden-row'} }) }}
Then in my javascript you can hide with some simple jQuery:
<script>
jQuery(document).ready(function() {
$('.js-hidden-row').hide();
});
</script>

How to set a Symfony2 path to Jeditable plugin

I'm trying to use Jeditable plugin for javascript. Here is the code (I took it from here):
In a .js file:
$('.edit').editable(function (value, settings) {
var data = {};
data[this.id] = value;
data["_token"] = "{{form._token.vars.value}}";
$.post("{{ path('edit_category', { 'id': cat.id}) }}", data);
return(value);
}, {
indicator:'Saving...',
tooltip:'Click to edit',
cancel:'Cancel',
submit:'Save'
});
This isn't working, it says that
No route found for "POST /{{ path('edit_category', { 'id': cat.id}) }}"
which I understand, because I have no idea how to pass the id parameter to the path (cat.id).
This is the way I'd do the edit only with Symfony in a template file:
<a href="{{ path('edit_category', { 'id': cat.id}) }}">
<i class="icon-pencil right-spacer"></i>
</a>
Any help will be appreciated! Thanks in advance!
The expression {{ path() }} is a twig expression, so it must be parsed by the twig template parser. Javascript files are usually not parsed.
You have some options on how to work around this. One idea is to inline your javascript code into your twig template. Of course that's not suitable for big code blocks and not very clean.
A better approach is to store the pathes in a variable in your layout twig template:
<script>
var token = "{{form._token.vars.value}}";
var path = "{{ path('edit_category', { 'id': cat.id}) }}";
</script>
In your js file, you only use the variables:
data["_token"] = token;
$.post(path, data);
Of course you might need to tweek that code if you have many pathes or variables.

Resources