Render dynamic block name with Sonata Block Bundle - symfony

Does anyone know how to render a dynamically generated block name using the Sonata Block Bundle? An example of what I am trying to achieve is:
page.html.twig:
<div class="content">
{{ sonata_block_render({
'name': '/content/blocks/{{ suffix }}'
}) }}
</div>
where suffix is a variable passed to the twig template, e.g. about-us. This allows me to use a single template for rendering all my CMS content. I have tried doing the above, but that doesn't seem to work.

You're already in twig context, that's why {{ }} didn't work. You'll need the string concatenation operator (~) like this:
<div class="content">
{{ sonata_block_render({
'name': '/content/blocks/' ~ suffix
}) }}
</div>

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 =)

symfony & translation : How to translate standard expressions & forms?

New to Symfony I created a login form (make:auth) and installed the translator.
I added in my form template login.html.twig
{% block body %}
<h1>{% trans %}Hello{% endtrans %}</h1>
<form method="post">
...
and defined in translations directory a messages.fr.yml, containing Hello : Bonjour.
That works and when I display my form, hello is well translated to Bonjour
But, all the other labels are not translated (username, password, etc)
which seems to be logical as the entries do not have the {% trans %} {% endtrans %} commands
<h1 class="h3 mb-3 font-weight-normal">Please sign in</h1>
<label for="inputUsername" class="sr-only">Username</label>
question 1 : is there a way to automatically translate all these labels?
question 2 : is there existing translation files containing all the standard used messages / labels?
Thank you for your help
to manage the translation in twig there is the appropriate trans function (example):
<label for="inputUsername" class="sr-only">{{'username' | trans}}</label>
and in your messages.fr.yml add:
username: "Nom d'utilisateur"
The default for form labels is to use a "humanized" version. And that one then may be translated in the messages translation domain.
You can change that by either setting the label on the form (element) directly, either in the builder
->add('fieldName', TextType::class, [
'label' => 'fieldName_translation_key',
])
or in the template:
{{ form_row(form.fieldname, {label: 'fieldname_translation_key'}) }}
{# this also works with form_widget/form_label, depending on the form element #}
If you want to use keyword translations for fields, you can set the label_format on the form itself (in the configure method, as an option) or on all its elements manually (with the placeholders described).
I personally prefer the label_format method because I rarely render the form "manually".
You can also set the translation_domain parameter to change the used translation domain (messages) to something else.

How to change template of controller rendered in twig file (Symfony 3)?

I know that we can render the content of a controller in twig file like this:
{{ render(controller('FOSUserBundle:Security:login',{"baseTemplate": true})) }}
However, I don't know if we can pass the new template so that the controller will use it instead of the default. Anyone tried to override template in this way?
I don't really understand the issue here
If you do
{{ render(controller('FOSUserBundle:Security:login',{"baseTemplate": true})) }}
You could aswell do:
{{ render(controller('FOSUserBundle:Security:login',{"template": "your_template.html.twig"})) }}
Or
{{ render(controller('FOSUserBundle:Security:login',{"templateNumber": "4"})) }}
Where templateNumber is used in a condition inside your controller ?

Drupal 8 - reach node/content needed variables in view

New user of D8 : my problem is to access to fields in a view or even in general with Drupal 8.
As we could do with ACF in Wordpress.
a {{ kint() }} crash my chrome but works with Firefox to explore the content var.
Unfortunately I do not managed to find and use fields' variables in my view.
I create a new view, which actually display the last three articles. These are well displayed in ugly list but I want to extract fields to put them in a custom html integration.
I create and use a new template for the view :
x node--view--liste-des-actualites--page-2.html.twig
In a custom parent :
x node--page-accueil.html.twig
But when I try to kint() content in my node--view--liste-des-actualites--page-2.html.twig, I have the custom field of the page (Page accueil) and can't find the article's one.
I managed to do it in my custom page but not in this view.
{%
set classes = [
'node',
'node--type-' ~ node.bundle|clean_class,
node.isPromoted() ? 'node--promoted',
node.isSticky() ? 'node--sticky',
not node.isPublished() ? 'node--unpublished',
view_mode ? 'node--view-mode-' ~ view_mode|clean_class,
'clearfix',
]
%}
{{ attach_library('classy/node') }}
<article{{ attributes.addClass(classes) }}>
<div{{ content_attributes.addClass('node__content', 'clearfix') }}>
{{ content }}
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-4">
<a href="{{ LINK_VAR }}" class="bloc-type">
<div class="categ categ_projet">{{ CATEGORY_VAR }}</div>
<div class="img"> <img src="{{ IMAGESRC_VAR }}" alt=""> </div>
<span class="wrapper">
<p class="date">{{ DATE_VAR }}</p>
<h3>{{ TITLE_VAR }}</h3>
</span>
</a>
</div>
</div>
</article>
EDIT
I managed to guess some fields but this is definitely not a good way to find variables..
{{ node.label }} + {{ content.field_tags }} (But I do not want a rendered one, I just want the text/value)
if you use kint(); to debug large arrays can crash your browser.
I would suggest to use the devel module https://www.drupal.org/project/devel. With devel you can debug your arrays inside of the Drupal8 UI for each content type, block or view.
In my case i use the UI of devel (additional tab on each content). in the module settings, you can chose how devel debugs, the error handling and the output.
As the OP commented it is possible to use a preprocess to display the array on your site:
function <themename>_preprocess_page(&$variables) {
dpm($variables);
}

for in twig templates of drupal is behaving strangely

I am trying to show only upcoming events from a list of events. Below is how I have tried to display.
<div class="row">
{% for item in items %}
{% if item.content['#node'].field_event_type.getValue()|first.value == 'upcoming' %}
<div class="col">{{item.content}}</div>
{% endif %}
{% endfor %}
</div>
But the output rendering is, the second event is displaying after the row div like below. I don't understand how this is happening as the for loop is inside the row div
<div class="row">
<div class="col"> content </div>
</div><div class="col"> content </div>
Expected output
<div class="row">
<div class="col"> content </div>
<div class="col"> content </div>
</div>
Twig does lots of things:
loading (open your Twig content)
parsing (create a parse tree from your Twig content)
compiling (browse that tree to create a php file)
caching (store the php file somewhere to avoid recompile it next time)
executing (execute the generated php file)
When a {% for %} is detected during parsing, Twig calls the token parser recursively until it finds {% endfor %} and builds a token tree. In your case, it would look like:
root
|
--- string
|
--- for
| |
| --- if
| |
| --- string
|
--- string
Then, Twig compiler crosses over that tree recursively and generates the corresponding php code. In that way, the following Twig loop:
{% for i in 1..5 %}
Value = {{ i }}
{% endfor %}
Compiles to this in PHP:
// line 1
$context['_parent'] = $context;
$context['_seq'] = twig_ensure_traversable(range(1, 5));
foreach ($context['_seq'] as $context["_key"] => $context["i"]) {
// line 2
echo "Value = ";
echo twig_escape_filter($this->env, $context["i"], "html", null, true);
}
$_parent = $context['_parent'];
unset($context['_seq'], $context['_iterated'], $context['_key'], $context['i'], $context['_parent'], $context['loop']);
$context = array_intersect_key($context, $_parent) + $_parent;
As you can see, a {% for %} is no more than a simple foreach and as Twig tokens are stored into a tree, it is by design not possible to display contents located below a pair of open/close tags.
The only possibility I can see is that one of the tag you're using in Twig is playing with output buffering, and one of the methods you're using in your loop breaks the ob stack (like a ob_get_clean() without any ob_start() for example, that have been open previously).
My advice is to grep your twig file name into your cache directory (eg: grep -Ri 'test.twig' cache/) in order to see that file compiled to PHP, to understand exactly what it does, and debug it.
Instead of filtering your content in twig, filter the results in your Drupal view.
In the "filter criteria" on your view, select the field_event_type field and set it "is equal to" and select/add 'upcoming' as the option.
If you filter in the view, you don't have to mess with the twig template.

Resources