Notice when using Timber::get_posts together with an include - timber

I've got this code:
Twig template:
<div class="content-items-wrapper">
{% for item in home.latest_posts %}
{% include "partials/content-item.twig" with item %}
{% endfor %}
</div>
In my theme file:
$context['home']['latest_posts'] = new Timber::get_posts([
'posts_per_page' => 6,
]);
When using these line of code I get the following notice:
Warning: array_merge(): Argument #2 is not an array in //content/plugins/timber-library/vendor/twig/twig/lib/Twig/Environment.php(462) : eval()'d code on line 86
Followed by a fatal error:
Catchable fatal error: Argument 1 passed to Twig_Template::display() must be of the type array, null given, called in /content/plugins/timber-library/vendor/twig/twig/lib/Twig/Environment.php(462) : eval()'d code on line 86 and defined in //content/plugins/timber-library/vendor/twig/twig/lib/Twig/Template.php on line 401
The strange thing is: when I don't use the include in the Twig template, but just use the contents of this include directly the errors are gone.
Also just putting one character (or even nothing) in the included partial gives the errors.
Also when not using Timber::get_posts(), but just filling an array with the correct data, I don't get any errors.
But obviously both are not really wanted solutions :-)
What could this be?
PS: I've got a frontend-only version (running of gulp-twig), feeded by JSON data, which is just running fine.
Edit: fixed the example (copy/paste mistake)

Don't you need to add the context home.items like $context['home'] or $context['home']['latest_posts'] just like with $context['posts']?

Problem solved!
Changing
{% include "partials/content-item.twig" with item %} into {% include "partials/content-item.twig" with { 'item' : item } %} did the trick.

Related

translation strings in twig inside an object

I'm trying to put translation strings inside an object within Twig. So far I haven't got it right and can't figure out how to properly do it. I didn't think this would work, but it was my best effort so far.
{% set options = {
0 : {{ 'user.first_name'|trans }},
1 : {{ 'user.surname'|trans }},
2 : {{ 'user.initials'|trans }}
} %}
I get the error:
A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "punctuation" of value "{".
Any one any ideas? Thanks in advance.
The syntax {{ ... }} is used to output content. You don't need to interpolate the variable in order to add it to the object
{% set options = {
0 : user.first_name|trans,
1 : user.surname|trans,
2 : user.initials|trans,
} %}
Some extra notes. As you are using numeric indices you could use the following snippet
{% set options = [
user.first_name|trans,
user.surname|trans,
user.initials|trans,
] %}
demo

Render field directly in page.html.twig

How can i render a field directly in the page.html.twig?
When i try to render it like:
{{ node.field_my_field.value }}
I get:
Exception: Object of type Drupal\entity_reference_revisions\EntityReferenceRevisionsFieldItemList cannot be printed
When i add a .value, it does still not render right (well i use paragraphs with subfields) but get following error:
User error: "target_id" is an invalid render array key in
Drupal\Core\Render\Element::children() (line 97 of core/lib/Drupal/Core/Render/Element.php).
User error: "target_revision_id" is an invalid render array key in Drupal\Core\Render\Element::children() (line 97 of core/lib/Drupal/Core/Render/Element.php).
User error: "_loaded" is an invalid render array key in Drupal\Core\Render\Element::children() (line 97 of core/lib/Drupal/Core/Render/Element.php).
User error: "_accessCacheability" is an invalid render array key in Drupal\Core\Render\Element::children() (line 97 of core/lib/Drupal/Core/Render/Element.php).
So how can i render it?
In Drupal 8 & Twig you can render a lot of stuff such:
 Render field value
For example, the node title
{{ node.title.value }}
Render field entity value
For example, a field of taxonomy term categories
{{ node.field_categories.entity.name.value }}
 Render field value of Paragraph (entity)
You can't print a Paragraph entity in Twig, but you can print every fields
{{ node.field_my_field.entity.field_title.value }}
In the previous example, field_title is a field of my Paragraph.
To go further, you could render a display mode using the module Bamboo Twig.
- Project page
- Article about Bamboo Twig
- Official Documentation
Render entity with display mode using Bamboo Twig
After installing the module and enable the submodule bamboo_twig_loader.
{# Render node with nid 1 #}
{{ bamboo_render_entity('node', 1) }}
{# Render the teaser of node with nid 2 #}
{{ bamboo_render_entity('node', 2, 'teaser') }}
Render field using Bamboo Twig
{# Render the title of node 1 #}
{{ bamboo_render_field('title', 'node', 1) }}
Hopes it will help you !
In order to render the field in a twig template, you will need a contrib module; unless you go with the hook_preprocess_page() implementation.
Using Bamboo Twig definitely does your job, as already mentioned in the suggested answer. It seems a bit awkward at first that you have to enable one of its submodules in order to achieve this though.
An alternative and more common solution is to use the Twig Tweak module with which you could do the following (copying from their cheat sheet):
{{ drupal_field('field_image', 'node', 1) }}
{{ drupal_field('field_image', 'node', 1, 'teaser') }}
{{ drupal_field('field_image', 'node', 1, {type: 'image_url', settings: {image_style: 'large'}}) }}

Cannot render text filtered with trans in twig template using Sandbox Security Policy

I am a little bit confused. First of all, look at my code, I guess.
public function renderTemplate($templateType, $data)
{
$layoutName = "$templateType.layout.html.twig";
$policy = new \Twig_Sandbox_SecurityPolicy(
['if', 'for', 'block', 'set', 'extends'],
['escape', 'format', 'dateformat', 'trans', 'raw', 'striptags'],
self::$allowedMethods,
self::$allowedProperties,
['gettext']
);
$sandboxExt = new \Twig_Extension_Sandbox($policy);
$intlExt = new \Twig_Extensions_Extension_Intl();
$i18nExt = new \Twig_Extensions_Extension_I18n();
$twig = new \Twig_Environment(new \Twig_Loader_Filesystem(__DIR__ . "/../Resources/views/Something/", "__main__"));
$sandboxExt->enableSandbox();
$twig->addExtension($sandboxExt);
$twig->addExtension($intlExt);
$twig->addExtension($i18nExt);
try {
$result = $twig->render($layoutName, $data);
} catch (\Exception $e) {
\Doctrine\Common\Util\Debug::dump($e);die();
}
return $result;
}
Here it is the template I want to render
{% extends 'layout.html.twig' %}
{% block title %}{{ entity.id }}{% endblock %}
{% block bodyTitle %}
{{ entity.id }} {{ 'translation_key.created_at'|trans({}, 'entities', locale) }} {{ entity.createdAt|dateformat(null, locale) }}
{% endblock %}
Here, as you can see, I want to render a template according to its type. The problem is: half of the template renders just fine, and then, when it tries to render the translated string, it throws an error.
Fatal error: Call to undefined function gettext() in /home/dev/vhosts/my-project/vendor/twig/twig/lib/Twig/Environment.php(403) : eval()'d code on line 69
I checked if this function existed right before trying to call render method, and it was really undefined. Basically, I have 2 questions here:
Question 1
How does it work in other parts of my project, but not in this specific handler? See "Important update" below.
Question 2
Can I solve my problem in another way? For example, without using Sandbox or using Sandbox with some kind of a flag "everythingAllowed=true"?
ATTENTION! IMPORTANT UPDATE
Previously, I misunderstood my own question. I thought the error was thrown while rendering the variable, but I re-checked the situation (When Alain Tiemblo asked me for twig template code here in comments) and now 100% sure it's thrown while trying to translate smth. Also, I have translations all over my project, and it works just fine, but in this specific situation it's not. I think it worth to mention, that I also tried to render the template without using Sandbox. I tried to render it directly from Twig Engine like this
return $this->templating->render($layoutName, $data);
//$this->templating is injected in the constructor via services.yml like this
//arguments:
// - "#templating"
The result - not properly translated text. When I dumped "locale" - I got one specific language, but the text was translated in another. But at least using this method - I didn't get any errors.. Can anybody clarify this for me? Because I really don't understand how the Intl/i18n extension works and why it doesn't want to work in Sandbox or not in Sanbox?
P.S. My guess, why it doesn't work directly from Twig Engine - probably I should inject not like "#templating" or it injects just right, but the Intl or I18n extensions are not enabled? How to enable. And I have no clues why it doesn't work with Sandbox

Symfony2 - Cast a String to Int in twig

I would like to know if it was possible to cast a String to an Int in twig. I try to see if a user has enough credit or not to buy a cours. For that, I calculate the amount of credit with a render in the template (because I need the value in the template, and I didn't found a better way to do it...) like this :
{% set creditUser %}
{{render(controller('L3L2EntraideBundle:Credits:sommeCredits'))}}
{% endset %}
But when I try to compare creditUser :
{% if creditUser < c.idCompetenceCours.prix %}disabled="false"{% endif %}
Symfony return me a beautiful error : An exception has been thrown during the rendering of a template ("Notice: Object of class Twig_Markup could not be converted to int") in L3L2UserBundle:Profile:modal_prendre_rdv.html.twig at line 21.
Any idea ? Thank you in advance for my first question on Stackoverflow and sorry for my english.
This is not string but Twig_Markup
{% if creditUser.__toString < c.idCompetenceCours.prix %}
but this is not good approach you should get this value from object/variable not from rendered template

Test if a method exists in entity from twig

I want to edit the default form template to include a thumbnail preview of an image when I display an upload field, so I put a method called getFormThumbnail() in my entity that returns the path. When the entity has the method it works, but when it doens't I get an error:
An exception has been thrown during the rendering of a template ("Warning: call_user_func_array() expects parameter 1 to be a valid callback, class 'Acme\UserBundle\Entity\UserTranslation' does not have a method 'getFormThumbnail' in C:\...\symfony\vendor\knplabs\doctrine-behaviors\src\Knp\DoctrineBehaviors\Model\Translatable\TranslatableMethods.php line 140") in kernel.root_dir/Resources/views/Form/form_div_layout.html.twig at line 43.
500 Internal Server Error - Twig_Error_Runtime
I am editing the code in {% block form_widget_simple %}
I added :
{% if type == 'file' %}
{% if form.vars.form.parent.vars.value.getFormThumbnail is not null %}
<img src="{{ form.vars.form.parent.vars.value.getFormThumbnail | imagine_filter('thumb_250') }}" style="display: block; margin-bottom: 10px">
{% endif %}
{% endif %}
This code works perfectly when getFormThumbnail exists. So I tried adding is defined and it doesn't work, I even tried things like:
form is defined
and
form is not null
and
form.vars is defined
and
form.vars is not null
and
form.vars.form is defined
and
form.vars.form is not null
and
form.vars.form.parent is defined
and
form.vars.form.parent is not null
and
form.vars.form.parent.vars is defined
and
form.vars.form.parent.vars is not null
and
form.vars.form.parent.vars.value is defined
and
form.vars.form.parent.vars.value is not null
and
form.vars.form.parent.vars.value.getFormThumbnail is defined
and
form.vars.form.parent.vars.value.getFormThumbnail is not null
Still, I always get the same error, the line in the error by the way is the line where I test if getFormThumbnail is defined
So if the error is does not have a method is there a way to test if it has a method?
You can create a custom fragment only for that field. So you don't have to check if the method exists or not http://symfony.com/doc/current/cookbook/form/form_customization.html#how-to-customize-an-individual-field.
Or you can create a form type extension: http://symfony.com/doc/current/cookbook/form/create_form_type_extension.html

Resources