I have a problem with twig. I need to use nested variables such as (account is an object)
{{ likes_array.[account.idOnSn].lifetime }}
This is a result of print_r(likes_array)
array(2) {
["tanitweb"]=> array(2) {
["lifetime"]=> int(1420)
["daily"]=> int(0)
}
["fstjuniorentreprise"]=> array(2) {
["lifetime"]=> int(3310)
["daily"]=> int(3310)
}
}
I get this exception
Expected name or number in StatsDotTnMainBundle:Default:acceuil.php.twig at line 188
Use index notation, with square brackets:
{{ likes_array[account.idOnSn].lifetime }}
Related
This is my first question on stackoverflow.
I have a problem with ACF and Timber. I have created an ACF group like this :
My acf group
I want to check if type_pre-footer = XXX,so in my Twig template I have made this :
{% if post.meta('pre-footer').type_pre-footer == 'Titre et liens' %}
<section class="join-us">
<img src="https://picsum.photos/1800/537" class="alwaysgray" alt="">
<div class="top-right">
<h5>Rejoignez-nous !</h5>
<ul>
<li>{{ macros.svg('arrow','12','as--white', assetsDir) }}
Offres d'emploi</li>
<li>{{ macros.svg('arrow','12','as--white', assetsDir) }}
Candidature spontanée</li>
<li>{{ macros.svg('arrow','12','as--white', assetsDir) }}
Recrutement d'équipes</li>
</ul>
</div>
...
But it's not working, I have tried to display post.meta('pre-footer').type_pre-footer with a {{dump()}, but it return 'int(0)'. When I try to display only post.meta('pre-footer'), it return an array :
array(3) {
["type_pre-footer"]=> string(14) "Titre et liens"
["titreliens"]=> array(3) { ["titre"]=> string(0) "" ["liens"]=> bool(false) ["image"]=> string(0) "" }
["articles"]=> array(2) { ["titre"]=> string(0) "" ["articles"]=> bool(false) } }
have you any idea about how to solve it ?
if you need more logs, you can ask me, thanks
I'm new to Symfony, currently working with 4.4, and am trying to implement a simple form theme for one specific form, i.e. the theme is in the same file as the form's html.twig file. I have my own form_row block and I'm trying to pass in custom data (an icon to use within the div) when calling it, so something like (this is highly summarised!):
{{ form_row(signUpForm.email, {
attr: { placeholder: 'e.g. bobsmith#gmail.com' },
icon: 'envelope'
}) }}
then try to render in the form as
{%- block form_row -%}
<div>
{{ form_label(form) }}
{{ form_widget(form, {attr: class: 'input'}) }}
<i class="icon {{ icon }}"></i>
</div>
I tried also passing icon via the formBuilder, along the lines of
$builder
->add('email', EmailType::class, [
'attr'=> ['icon' => 'envelope']
])
but no joy. Surely this must be possible! Any assistance would be much appreciated. Thanks
I'm not sure but you can access to your form variable with {{form}} in your theme. So you can use it.
Hope this help
Edit:
You can add property in your entity and use it in template like this :
{%- block form_row -%}
<div>
{{ form_label(form) }}
{{ form_widget(form, {attr: class: 'input'}) }}
{% set myData = form.vars.value %}
<i class="icon {% if myData.type == 'mail' %}envelope{% endif %}"></i>
I think you have a better way to do this but i do something like that and it's work.
So, I managed to find the "proper" way to do what I want: a Form Type Extension. The Symfony Casts tutorial on it is pretty good. In short, you create a class to extend your main form input class; in my case I was dealing with a text based input, so I created an App\Form\ypeExtension\TextIconExtension class, extended from FormTypeExtensionInterface, then implemented configureOptions and buildView (I removed the functions in the interface I didn't fill in):
class TextIconExtension implements FormTypeExtensionInterface
{
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->vars['icon'] = $options['icon'];
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'icon' => 'user'
]);
}
public function getExtendedType()
{
return TextType::class;
}
public function getExtendedTypes(): iterable
{
return [TextType::class];
}
}
Then, in my form template, I can simply pass a value for icon:
{{ form_row(signUpForm.email, {
attr: { placeholder: 'e.g. bobsmith#gmail.com' },
icon: 'envelope'
}) }}
I test if a custom Twig function exists:
{% if methodExist('sg_datatables_render') %}
{{ sg_datatables_render(datatable) }}
{% else %}
{{ datatable_render((datatable)) }}
{% endif %}
methodExist is a simple Twig_Function:
/**
* #param $name
* #return bool
*/
public function methodExist($name){
if($this->container->get('twig')->getFunction($name)){
return true;
}else{
return false;
}
}
But I get an exception:
Unknown "sg_datatables_render" function. Did you mean "datatable_render"?
500 Internal Server Error - Twig_Error_Syntax
I tried to replicate this, and indeed, {{ sg_datatables_render(datatable) }} seems to always cause a Twig_Error_Syntax exception when sg_datatables_render has not been registered as a Twig function.
I then tried something like this. It's ugly, but I wanted to know if it works. The idea is that a non-existing function will be created to avoid the exception being thrown:
$twig->addFunction(new Twig_Function('methodExist', function(Twig_Environment $twig, $name) {
$hasFunction = $twig->getFunction($name) !== false;
if (!$hasFunction) {
// The callback function defaults to null so I have omitted it here
return $twig->addFunction(new Twig_Function($name));
}
return $hasFunction;
}, ['needs_environment' => true]));
But it didn't work. I also tried to add a simple callback function to the new function with no success.
I tried the same trick with filters, i.e.:
{% if filterExists('sg_datatables_render') %}
{{ datatable|sg_datatables_render }}
{% else %}
{{ datatable|datatable_render }}
{% endif %}
It didn't work either.
Solution 1: {{ renderDatatable(datatable) }}
Something like this does work (yay!):
$twig->addFunction(new Twig_Function('renderDatatable', function(Twig_Environment $twig, $datatable) {
$sgFunction = $twig->getFunction('sg_datatables_render');
if ($sgFunction !== false) {
return $sgFunction->getCallable()($datatable);
}
return $twig->getFunction('datatable_render')->getCallable()($datatable);
}, ['needs_environment' => true]));
And then in Twig:
{{ renderDatatable(datatable) }}
The renderDatatable function is specific to rendering datatables, i.e. it's not a general/multipurpose function like your methodExist is, but it works. You can of course try to create a more general implementation yourself.
Solution 2: {{ fn('sg_datatables_render', datatable) }}
Here's a more general approach. Create an additional Twig function to accompany methodExist:
$twig->addFunction(new Twig_Function('fn', function(Twig_Environment $twig, $name, ...$args) {
$fn = $twig->getFunction($name);
if ($fn === false) {
return null;
}
// You could add some kind of error handling here
return $fn->getCallable()(...$args);
}, ['needs_environment' => true]));
Then you could modify your original code to this:
{% if methodExist('sg_datatables_render') %}
{{ fn('sg_datatables_render', datatable) }}
{% else %}
{{ datatable_render((datatable)) }}
{% endif %}
Or even use the ternary operator:
{{ methodExist('sg_datatables_render') ? fn('sg_datatables_render', datatable) : datatable_render(datatable) }}
PS
Here's how I'd write the methodExist function:
$twig->addFunction(new Twig_Function('methodExists', function(Twig_Environment $twig, $name) {
return $twig->getFunction($name) !== false;
}, ['needs_environment' => true]));
I added s to the end of the function's name because the function checks whether a method/function exists.
I added ['needs_environment' => true] so I can use $twig instead of $this->container->get('twig'). (Kudos to yceruto for this tip.)
getFunction returns false if the function doesn't exist (see the docs), so I simplified the function body to a single-line return statement.
I have a twig template where I am displaying certain details based on the type of person.
But the condition is not working, I'm just wondering what is wrong with the IF clause?
{% if field_person_type == 'XXXXXXX' %}{{ (content.field_position) }}, {{ (content.field_unit) }}
{% else %} {{ (content.field_position) }}, {{ (content.field_institution) }} {% endif %}
And the content is defined below
Position field_position Text Text field
Person Type field_person_type Term reference Check boxes/radio buttons
Unit field_unit Text Text field
Institution field_institution Term reference Check boxes/radio buttons
When I use dump(field_person_type), it shows following
ARRAY(1) {
[0]=> ARRAY(2) {
["TID"]=> STRING(2) "40"
["TAXONOMY_TERM"]=> OBJECT(STDCLASS)#179 (8) {
["TID"]=> STRING(2) "40"
["VID"]=> STRING(1) "5"
["NAME"]=> STRING(7) "XXXXXXX"
["DESCRIPTION"]=> STRING(0) ""
["FORMAT"]=> STRING(2) "21"
["WEIGHT"]=> STRING(1) "2"
["VOCABULARY_MACHINE_NAME"]=> STRING(11) "PERSON_TYPE"
["PATH"]=> ARRAY(1) {
["PATHAUTO"]=> STRING(1) "1"
}
}
}
}
Try this field_person_type.0.taxonomy_term.name
Twig cannot access the name magically, you have to access it like you would access an array.
As the dump states: Your field (field_person_type) is an array. Inside you have [0] which is also an array with 2 entries. The "TAXONOMY_TERM" inside is an object so should be accessed as an object.
The following should give you your result
field_person_type[0]["TAXONOMY_TERM"].NAME
I want to know if a user has the 'VIEW_GEOLOC_DATA' role, but I have a problem using the twig function is_granted().
If I use in a template :
Roles : {{ dump(app.user.getRoles()) }}
is_granted('ROLE_SUPER_ADMIN') : {{ dump(is_granted('ROLE_SUPER_ADMIN')) }}
is_granted('VIEW_GEOLOC_DATA') : {{ dump(is_granted('VIEW_GEOLOC_DATA')) }}
This is what I get when rendering :
array(2) {
[0]=>
string(16) "ROLE_SUPER_ADMIN"
[1]=>
string(16) "VIEW_GEOLOC_DATA"
}
is_granted('ROLE_SUPER_ADMIN') : bool(true)
is_granted('VIEW_GEOLOC_DATA') : bool(false)
I've tried to logging in and out, emptying symfony's cache.
I also tried to switch the order of roles in the array returned by the method getRoles() of my User : the function is_granted will only take into account the first role of the array
If you are expecting Symfony2 to handle your roles, then your roles need to start with "ROLE_".
Change
'VIEW_GEOLOC_DATA'
to
'ROLE_VIEW_GEOLOC_DATA'
Of course, you'll need to change this in your config and add the new role.
This answer does not apply, if you are using a dedicated Role class.
I ended up creating a new method hasRole in my User Class :
public function hasRole($role)
{
return in_array($role, $this->getRoles());
}
Then, in a template, I use:
{% if app.user.hasRole('ROLE_VIEW_GEOLOC_DATA') %}
{# do something #}
{% endif %}
EDIT:
As #JonnyS said, it may be possible that roles must start with ROLE_ to work with is_granted Symfony's function. Didn't tested.
Create a Security Voter that checks this.
http://symfony.com/doc/current/cookbook/security/voters_data_permission.html
This is much cleaner then creating an method on an entity for this.