twig convert a string to the object that it represent - symfony

imaging that i have a object and which can be called in a twig template like this:
{{ object1.object2.object3.property3A }}
well, it will show me the content if we use php to write is :
$object1->getObject2()->getObject3()->getProperty3A();
My question is if i have a string ,
$refString="object1.object2.object3.property3A";
and then it is passed to twig, how could i get the property3A? For my experience, we can do this in php like this:
$refString="object1->getObject2()->getObject3()->getProperty3A()";
echo $$refString;
But i do not know how to make it work in twig.

I didn't tested this, but i think it schould do the trick.
{#
recursively reading attributes from an object
! object1 must be available !
theValue is the value of property3A
#}
{% for key in "object1.object2.object3.property3A"|split('.') %}
{% if not loop.first %}{# skip the 'object1' part #}
{% set theValue = attribute(theValue|default(object1), key) %}
{% endif %}
{% endfor %}

I don't think there is a "shortcut" to do this in twig. If you can't find a simple way to do this, you can write you own extension, that would convert a STRING_TYPE to a VAR_TYPE.
Twig internals might put you on the right track. This is an example of what is feasable with twig extension and might inspire you.

I ran into a similar situation. This answer will only work if the object you need is available to the template and you know the name of it with a string.
In this case, you can access the object using Twig's Global Variable _context:
{% set object1 = _context['object1'] %}
And then access the methods and variables of the object as normal:
{{ object1.object2.object3.property3A }}

Related

pluralize results if plural in symfony (good practice)

I have a filter bar that let me search some results within my database.
I have a flash message that shows how many results are found when I enter a word inside it.
this is my controller
if ($filter != '') {
$this->get('session')->getFlashBag()->add('info', 'worked!');
}
and this is in my template
{% for message in app.session.flashbag.get('info') %}
{{ message }}
{% endfor %}
so when i research things actually, whether I have 1 result or more it doesn't change my sentence.
résultats is still written with an s as it is hard coded. How can I create something that will allow me to pluralize and singularize a word in my template? Should I go directly in the controller for that ?
EDIT
I used this method directly in the template but I don't think it is a "good practice" one. Any help for making that better?
{{ results.getTotalItemCount }}
{% if results.getTotalItemCount <= 1 %}
{{ 'this.is.your.result'|trans({ '%count%': results.getTotalItemCount}) }}
{% else %}
{{ 'this.is.your.results'|trans({ '%count%': results.getTotalItemCount}) }}
{% endif %}
in translation
this:
is:
your.result: "résultat"
your.results: "résultats"
You should maybe check pluralization in translations here, you can use transChoice() method, it is explained here how to use it.
Here you can see how to use it in twig:
https://stackoverflow.com/a/10817495/5258172
Edit:
your answer in question can be done like this:
this:
is:
your.result: "1 résultat|%count% résultats"
and then in your twig:
{{ 'this.is.your.result'|transchoice(results.getTotalItemCount) }}

How to use twig object variable with at-sign # inside

I send from Symfony object which contains at-sign # in variable.
Object name is invoice and with {{ dump(invoice) }} in twig template I see object and parameter with path:
invoice[0].banSpojDod#showAs
But I dont know how to get value of this banSpojDod#showAs because there is at-sign #.
Could you help me someone please?
You could try with The attribute function can be used to access a "dynamic" attribute of a variable:
{{ attribute(invoice[0], 'banSpojDod#showAs') }}
Hope this help
Ok thanks. Problem was that I used it in loop, and some parameters not exists. I needed to add exist conditions. So my final code works:
{% for f in invoice %}
{% if attribute(f,'banSpojDod#showAs') is defined %}
{{ attribute(f,'banSpojDod#showAs') }}
{% endif %}
{% endfor %}

Indicates if an URL is tight to current controller in Twig

assume you are in Twig template and want to indicate if you are on a controller with any action.
The simple process you can check a single route is
{% if app.request.attributes.get('_route') == 'app_user_list' %}
// code...
{% endif %}
But I need something with a wildcard to determine if the action is under current controller like 'app_user_*' to match also 'app_user_add' or 'app_user_delete'. It is nonsence to if-else all possible routes.
Any thoughts?
Thanks!
You can use the slice Twig filter, from the doc:
The slice filter works as the array_slice PHP function for arrays and
mb_substr for strings with a fallback to substr.
So you can archive as example of matching a group of routing with the prefix of app_user_ (app_user_add, app_user_delete, etc):
{% if app.request.attributes.get('_route')|slice(0,9) == 'app_user_' %}
// code...
{% endif %}
Hope this help

Symfony2.7 Twig How to obtain a token?

Inside Twig file I have this code:
{% set player = app.security.getToken().getUser().getPlayer() %}
{% if player.getSelectedCharacter() is not null %}
{% set character = player.getSelectedCharacter() %}
{% .... %}
{% endif %}
But at now, app.security is deprecated. So I want to change this. I can obtain user token inside my controller and send it to the Twig. But I prefer to get it directly via Twig.
How I can do this?
As you said and mentioned in the documentation.
The app.security global is deprecated as of 2.6. The user is already
available as app.user and is_granted() is registered as function.
I think you can just try something like this in your view.
app.user.getPlayer()

Use placeholders in translation using tags

In Symfony / Twig, I could use tags by using percentages in my translated block. For example:
Hello {{nickname}}
would become
{% trans %}Hello %nickname%{% endtrans %}
This works as expected. The array with placeholders that I pass to Twig, are automatically mapped to %placeHolder%. No extra work involved. So this works with my PHP array from the controller being:
Array('nickname' => 'rolandow')
When I want to use the nickname inside the translation block, all I have to do is surround it with percentages %. Unfortunately, this doesn't seem to work when I pass it to trans.
Now I would like to translate a whole block of text, using tags. I can't figure out how I can use the tags in my translation. So, my twig would look something like this:
{{ say.hello|trans }}
And my translation snippet
<trans-unit id="1">
<source>say.hello</source>
<target>Hello %nickName%, how are you doing today? lots-of-text-here</target>
</trans-unit>
I got it working by using this in my template, but it feels like doing things twice. I now need to put the array of placeholder into the trans function again. For example:
{{ say.hello|trans('%nickName%' : nickName) }}
If I want to use other tags that are given to twig in my controller, I need to pass them to the translator as well. Can't I just pass the complete array somehow?
{{ say.hello|trans('%nickname%': 'rolandow') }}
There are several questions here so let's cover them.
1) Twig's behaviour is not like a Doctrine query, where each parameter must be bounded. You can pass an array that contains unused parameters to trans, so if you don't want to specify {'key': 'value', 'key2': 'value2'...} to the filter, just pass the entire array (example: | trans(array)). That's #Luke point.
2) You can translate block of texts using several ways, the most simple is {% set %}. The {% set %} tag can be used two ways :
{% set var = expression %} or {% set var1, var2 = expression1, expression2 %} is the most known and used way: you just put some value inside one or several variables.
{% set var %} block of text {% endset %} allow you to set an entire block of text inside that variable. This is useful if you want to put that block into a filter (such as, escape, or in your case, trans).
So to translate a block of text, you'll do something like:
{% set variable %}
block to translate %placeholder%
{% endset %}
{{ variable | trans(array) }}
Anyway, I don't see any interest of translating a whole block in one time : we use | trans generally after a property (such as say.hello), and I can't imagine your xlf/yml translation file with such a design. If you want to use the translator just to fulfill placeholders, just use Twig as it is written for that job :-)
3) About replacing placeholder by %placeholder% in your parameters array's keys : the point of Twig is: put what you want as placeholder. In such a way, if your translated sentence contains several %, you can use $something$, #something# or even something as placeholder.
If your array keys does not contain those %, you need to add them, you don't have any choice. If you really want to do it on a Twig file, you can create a macro that will do the job for you, and put it in a file you import in your base layout.
Something like :
{% macro trans_pct(property, params) %}
{% set newParams = [] }
{% if params %}
{% for key, value in params %}
{% set newParams['%' ~ key ~ '%'] = value %}
{% endfor %}
{% endif %}
{{ property | trans(newParams) }}
{% endmacro %}
And then use it with {{ _self.trans_pct('hello.say', array) | trim }}.
Notes :
_self is the template where is stored the macro (see the documentation for more details).
trim is used because I wrote the macro with indentation and line breaks (that's cleaner to read). Those spaces are, by default, printed.

Resources