How to create a counter with TWIG? - symfony

I have a site with Drupal 8 and I want to create a task counter with TWIG.
I use views with conditions. The counter must be incremented whether the view has a result or not.
Here is the code I just made :
<span class="badge badge-warning task-badge-warning">
{% if drupal_view_result('boutique_page_liste_des_taches_produit_non_publie', 'block_1') is not empty %}
1
{% endif %}
{% if drupal_view_result('boutique_page_liste_des_taches_role_marchand', 'block_1') is empty %}
1
{% endif %}
</span>
<span class="badge badge-danger task-badge-danger">
{% if drupal_view_result('boutique_page_liste_des_taches_aucun_produit', 'block_1') is empty %}
1
{% endif %}
{% if drupal_view_result('boutique_page_liste_des_taches_aucune_variation', 'block_1') is not empty %}
1
{% endif %}
{% if drupal_view_result('boutique_page_liste_des_taches_commande', 'block_1') is not empty %}
1
{% endif %}
{% if drupal_view_result('boutique_page_liste_des_taches_mode_de_livraison', 'block_1') is empty %}
1
{% endif %}
{% if drupal_view_result('boutique_page_liste_des_taches_passerelle_de_paiement', 'block_1') is empty %}
1
{% endif %}
</span>
There are 2 counters :
a "Warning" badge
a "Danger" badge
Do you know a solution to do this ?
The "Warning" badge must display the total number of "Warning" tasks.
The "Danger" badge must display the total number of "Danger" tasks.

You can set variables and then increment them:
{% set warnings = 0 %}
<span class="badge badge-warning task-badge-warning">
{% if drupal_view_result('boutique_page_liste_des_taches_produit_non_publie', 'block_1') is not empty %}
{% set warnings = warnings + 1 %}
{% endif %}
{% if drupal_view_result('boutique_page_liste_des_taches_role_marchand', 'block_1') is empty %}
{% set warnings = warnings + 1 %}
{% endif %}
{{ warnings }}
</span>
{% set dangers = 0 %}
<span class="badge badge-danger task-badge-danger">
{% if drupal_view_result('boutique_page_liste_des_taches_aucun_produit', 'block_1') is empty %}
{% set dangers = dangers + 1 %}
{% endif %}
{% if drupal_view_result('boutique_page_liste_des_taches_aucune_variation', 'block_1') is not empty %}
{% set dangers = dangers + 1 %}
{% endif %}
{% if drupal_view_result('boutique_page_liste_des_taches_commande', 'block_1') is not empty %}
{% set dangers = dangers + 1 %}
{% endif %}
{% if drupal_view_result('boutique_page_liste_des_taches_mode_de_livraison', 'block_1') is empty %}
{% set dangers = dangers + 1 %}
{% endif %}
{% if drupal_view_result('boutique_page_liste_des_taches_passerelle_de_paiement', 'block_1') is empty %}
{% set dangers = dangers + 1 %}
{% endif %}
{{ dangers }}
</span>

Related

Is there a way to define logic in a block rather than in a bunch of individual tags?

For Example I have quite a lot of logic that looks like this
{% set allowed_observations = ["PAR;101;ZN_GYM", "PAR;101;ZN_CARDIOGYM", "PAR;101;0;G15"] %}
{% set allowed_observations_names = ["Downstairs Gym", "Upstairs Gym (Cardio)", "Swimming Pool"] %}
{% for observation in observations %}
{% if (observation.location.locationCode in allowed_observations) %}
{% if ("HeadCount" in observation.observationTag) %}
{% set name = "" %}
{% for key,value in allowed_observations %}
{% if (value == observation.location.locationCode) %}
{% set name = allowed_observations_names[key] %}
{% endif %}
{% endfor %}
{% set data = data | push({
name: name,
location: observation.location.locationCode,
value: observation.value
}) %}
{% endif %}
{% endif %}
{% endfor %}
I was wondering if you can just do a single {% ...all code... %} type thing, using ; for line breaks or something?

Twig use one value in different for loop

Since I'm using a SaaS platform I don't have much space to do things differently.
I have two for loops in Twig:
{% for option in product.options %}
{{ option.title }}
{% if option.values %}
{% for value in option.values %}
{{ value.title }}
{% endfor %}
{% endif %}
{% endfor %}
{% for variant in product.variants %}
{{ variant.stock.level }}
{% endfor %}
What I try to do is to use variant.stock.level value inside the product.options for loop to show some HTML. This value always match the corresponding index value of the other for loop. I also think that's the only way to do this.
So what I mean is.....Let's say both for loops contain 3 elements.
Option1
Option2
Option3
Variant1
Variant2
Variant3
So option1 needs to have the value from variant1.
For the end result I need to know what the value of eg Variant1 is to show some HTML like so:
{% for value in option.values %}
{% check if value from corresponding variant is greater then 0 %}
<li class="on-stock">{{ value.title }}</li>
{% else %}
<li class="out-of-stock">{{ value.title }}</li>
{% endif %}
{% endfor %}
I don't know no other way to explain this :) Any help appreciated....
You are looking for attribute.
The attribute function can be used to access a "dynamic" attribute of a variable
Since the indexes are the same, you can use loop.index0
Example for your case
{% if attribute(option.variants, loop.index0) > 0 %}
// some stuff
{% endif %}
I'm not sure if I understood you correctly but you may use key from first loop to access product.variants with the same index.
{% for key, option in product.options %}
{{ option.title }}
{% if option.values %}
{% for value in option.values %}
{{ value.title }}
{% endfor %}
{% endif %}
{{ product.variants[key].stock.level }}
{% endfor %}

KnpMenuBundle not working with Bootstrap 4 navbar

I am currently making a menu with the Symfony bundle: KnpMenuBundle. I am using Bootstrap 4 as stylesheet.
Bootstrap 4 requires each list item in the navbar to have the class 'nav-item':
<li class="nav-item active"> <-- this
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
I can't seem to figure out how to add the class 'nav-item' to the list item with KnpMenuBundle. Currently I see this when I load the page:
navbar result
This is my Builder class in src/AppBundle/Menu:
namespace AppBundle\Menu;
use Knp\Menu\MenuFactory;
class Builder
{
public function mainMenu(MenuFactory $factory, array $optioins)
{
$menu = $factory->createItem('root');
$menu->setChildrenAttribute('class', 'navbar-nav mr-auto');
$menu->addChild('Home', ['route' => 'homepage']);
$menu->setChildrenAttributes(['class' => 'nav-item']);
return $menu;
}
}
My code in base.html.twig to generate menu:
{{ knp_menu_render('AppBundle:Builder:mainMenu', {'currentClass': 'active'}) }}
What do I do to make it working?
I did this to get top level correct. Haven't worked out dropdowns yet though.
$menu->setChildrenAttribute('class', 'navbar-nav');
// menu items
foreach ($menu as $child) {
$child->setLinkAttribute('class', 'nav-link')
->setAttribute('class', 'nav-item');
}
You can add a class to each child items when you add it like that:
$menu->addChild('Home', ['route' => 'homepage'])
->setAttributes(array(
'class' => 'nav-item'
));
You should create new template file, for example "extended_knp_menu.html.twig" (also filename should not be named knp_menu.html.twig), with contents (src):
{% extends 'knp_menu.html.twig' %}
{% macro setCssClassAttribute(item, type, add) %}
{% set getter = 'get' ~ type %}
{% set setter = 'set' ~ type %}
{% set value = attribute(item, getter, ['class']) %}
{% if value is iterable %}
{% set value = value|join(' ') %}
{% endif %}
{% do attribute(item, setter, ['class', value ~ ' ' ~ add]) %}
{% endmacro %}
{% block item %}
{% import "knp_menu.html.twig" as macros %}
{#
As multiple level is not currently supported by bootstrap 4
This requires you to install
https://github.com/bootstrapthemesco/bootstrap-4-multi-dropdown-navbar
And set the the use_multilevel = true
#}
{% set use_multilevel = false %}
{% if item.displayed %}
{%- set attributes = item.attributes %}
{%- set is_dropdown = attributes.dropdown|default(false) %}
{%- set divider_prepend = attributes.divider_prepend|default(false) %}
{%- set divider_append = attributes.divider_append|default(false) %}
{# unset bootstrap specific attributes #}
{%- set attributes = attributes|merge({'dropdown': null, 'divider_prepend': null, 'divider_append': null }) %}
{%- if divider_prepend %}
{{ block('dividerElement') }}
{%- endif %}
{# building the class of the item #}
{%- set classes = item.attribute('class') is not empty ? [item.attribute('class'), 'nav-item'] : ['nav-item'] %}
{%- if matcher.isCurrent(item) %}
{%- set classes = classes|merge([options.currentClass]) %}
{%- elseif matcher.isAncestor(item, options.depth) %}
{%- set classes = classes|merge([options.ancestorClass]) %}
{%- endif %}
{%- if item.actsLikeFirst %}
{%- set classes = classes|merge([options.firstClass]) %}
{%- endif %}
{%- if item.actsLikeLast %}
{%- set classes = classes|merge([options.lastClass]) %}
{%- endif %}
{# building the class of the children #}
{%- set childrenClasses = item.childrenAttribute('class') is not empty ? [item.childrenAttribute('class')] : [] %}
{%- set childrenClasses = childrenClasses|merge(['menu_level_' ~ item.level]) %}
{# adding classes for dropdown #}
{%- if is_dropdown %}
{%- set classes = classes|merge(['dropdown']) %}
{%- set childrenClasses = childrenClasses|merge(['dropdown-menu']) %}
{%- endif %}
{# putting classes together #}
{%- if classes is not empty %}
{%- set attributes = attributes|merge({'class': classes|join(' ')}) %}
{%- endif %}
{%- set listAttributes = item.childrenAttributes|merge({'class': childrenClasses|join(' ') }) %}
<li{{ macros.attributes(attributes) }}>
{# displaying the item #}
{%- if is_dropdown %}
{{ block('dropdownElement') }}
{%- elseif item.uri is not empty and (not item.current or options.currentAsLink) %}
{{ block('linkElement') }}
{%- else %}
{{ block('spanElement') }}
{%- endif %}
{%- if divider_append %}
{{ block('dividerElement') }}
{%- endif %}
{% if item.hasChildren and options.depth is not same as(0) and item.displayChildren %}
{{ block('dropdownlinks') }}
{% endif %}
</li>
{% endif %}
{% endblock %}
{% block dropdownlinks %}
{% if use_multilevel %}
<ul class="dropdown-menu">
{% else %}
<div class="dropdown-menu">
{% endif %}
{% for item in item.children %}
{{ block('renderDropdownlink') }}
{% if use_multilevel and item.hasChildren and options.depth is not same as(0) and item.displayChildren %}
{{ block('dropdownlinks') }}
{% endif %}
{% endfor %}
{% if not use_multilevel %}
</div>
{% else %}
</ul>
{% endif %}
{% endblock %}
{% block renderDropdownlink %}
{% import _self as ownmacro %}
{%- set divider_prepend = item.attributes.divider_prepend|default(false) %}
{%- set divider_append = item.attributes.divider_append|default(false) %}
{%- set attributes = item.attributes|merge({'dropdown': null, 'divider_prepend': null, 'divider_append': null }) %}
{% if use_multilevel %}
<li>
{% endif %}
{%- if divider_prepend %}
{{ block('dividerElementDropdown') }}
{%- endif %}
{%- if item.uri is not empty and (not item.current or options.currentAsLink) %}
{{ ownmacro.setCssClassAttribute(item, 'LinkAttribute', 'dropdown-item') }}
{{ block('linkElement') }}
{%- else %}
{{ block('spanElementDropdown') }}
{%- endif %}
{%- if divider_append %}
{{ block('dividerElementDropdown') }}
{%- endif %}
{% if use_multilevel %}
</li>
{% endif %}
{% endblock %}
{% block spanElementDropdown %}
{% import "knp_menu.html.twig" as macros %}
{% import _self as ownmacro %}
{{ ownmacro.setCssClassAttribute(item, 'LabelAttribute', 'dropdown-header') }}
<div {{ macros.attributes(item.labelAttributes) }}>
{% if item.attribute('icon') is not empty %}
<i class="{{ item.attribute('icon') }}"></i>
{% endif %}
{{ block('label') }}
</div>
{% endblock %}
{% block dividerElementDropdown %}
<div class="dropdown-divider"></div>
{% endblock %}
{% block dividerElement %}
{% if item.level == 1 %}
<li class="divider-vertical"></li>
{% else %}
<li class="divider"></li>
{% endif %}
{% endblock %}
{% block linkElement %}
{% import "knp_menu.html.twig" as macros %}
{% import _self as ownmacro %}
{{ ownmacro.setCssClassAttribute(item, 'LinkAttribute', 'nav-link') }}
<a href="{{ item.uri }}"{{ macros.attributes(item.linkAttributes) }}>
{% if item.attribute('icon') is not empty %}
<i class="{{ item.attribute('icon') }}"></i>
{% endif %}
{{ block('label') }}
</a>
{% endblock %}
{% block spanElement %}
{% import "knp_menu.html.twig" as macros %}
{% import _self as ownmacro %}
{{ ownmacro.setCssClassAttribute(item, 'LabelAttribute', 'navbar-text') }}
<span {{ macros.attributes(item.labelAttributes) }}>
{% if item.attribute('icon') is not empty %}
<i class="{{ item.attribute('icon') }}"></i>
{% endif %}
{{ block('label') }}
</span>
{% endblock %}
{% block dropdownElement %}
{% import "knp_menu.html.twig" as macros %}
{%- set classes = item.linkAttribute('class') is not empty ? [item.linkAttribute('class')] : [] %}
{%- set classes = classes|merge(['dropdown-toggle', 'nav-link']) %}
{%- set attributes = item.linkAttributes %}
{%- set attributes = attributes|merge({'class': classes|join(' ')}) %}
{%- set attributes = attributes|merge({'data-toggle': 'dropdown'}) %}
<a href="#"{{ macros.attributes(attributes) }}>
{% if item.attribute('icon') is not empty %}
<i class="{{ item.attribute('icon') }}"></i>
{% endif %}
{{ block('label') }}
<b class="caret"></b>
</a>
{% endblock %}
{% block label %}{{ item.label|trans }}{% endblock %}
After just include rendering template for menu:
{{ knp_menu_render('AppBundle:Builder:mainMenu', {
'currentClass': 'active',
'template': 'extended_knp_menu.html.twig'
}) }}
Hope it helped you.

KnpMenuBundle add icon/glyphicon

I have tried to set an icon next to the link of the menu generated by knpMenuBundle but no way to get it.
I found some solutions like ->setAttribute or ->setExtra, but I can't make it work.
Do I have to add specific lines to the base template of knp ?
Do something special in the twig render ?
Here is what I have tried so far:
//Builder.php
$public function mainMenu(FactoryInterface $factory, array $options)
{
$menu = $factory->createItem('root');
$menu->setChildrenAttribute('class', 'nav navbar-nav ');
$menu->addChild('Mes Informations',['route' => 'espace_client_mesInformations'])
->setAttribute('icon','fa fa-home');
$menu->addChild('Mes Factures', array('route' => 'espace_client_mesFactures'));
$menu->addChild('Mon Extrait de Compte', array('route' => 'espace_client_mesReglements'));
$menu->addChild('Mes Services', array('route' => 'espace_client_mesServices'));
$menu->addChild('Mes Consommations', array('route' => 'espace_client_mesConsommations'));
$menu['Mes Consommations']->addChild('Télephone', array('route' => 'espace_client_mesConsoTelephone'));
$menu['Mes Consommations']->addChild('Internet', array('route' => 'espace_client_mesConsoInternet'));
$menu->addChild('Mes Liens Directs', array('route' => 'espace_client_mesLiens'));
return $menu;
}
//menu.html.twig
<div class="panel panel-default">
<div class="panel-heading">
<center><h4> Menu </h4></center>
</div>
<div class="panel-body">
{{ knp_menu_render('EspaceClientBundle:Builder:mainMenu',{'currentAsLink':false, 'template': 'EspaceClientBundle:Menu:knp_menu.html.twig'}) }}
</div>
If anyone have an answer ?
Thanks.
Edit:
I'm a little bit confused by the different files of the bundle, I must have a problem in my php code so there is the content of them:
//knp_menu.html.twig:
{% extends 'knp_menu_base.html.twig' %}
{% macro attributes(attributes) %}
{% for name, value in attributes %}
{%- if value is not none and value is not same as(false) -%}
{{- ' %s="%s"'|format(name, value is same as(true) ? name|e : value|e)|raw -}}
{%- endif -%}
{%- endfor -%}
{% endmacro %}
{% block compressed_root %}
{% spaceless %}
{{ block('root') }}
{% endspaceless %}
{% endblock %}
{% block root %}
{% set listAttributes = item.childrenAttributes %}
{{ block('list') -}}
{% endblock %}
{% block list %}
{% if item.hasChildren and options.depth is not same as(0) and item.displayChildren %}
{% import _self as knp_menu %}
<ul{{ knp_menu.attributes(listAttributes) }}>
{{ block('children') }}
</ul>
{% endif %}
{% endblock %}
{% block children %}
{# save current variables #}
{% set currentOptions = options %}
{% set currentItem = item %}
{# update the depth for children #}
{% if options.depth is not none %}
{% set options = options|merge({'depth': currentOptions.depth - 1}) %}
{% endif %}
{# update the matchingDepth for children #}
{% if options.matchingDepth is not none and options.matchingDepth > 0 %}
{% set options = options|merge({'matchingDepth': currentOptions.matchingDepth - 1}) %}
{% endif %}
{% for item in currentItem.children %}
{{ block('item') }}
{% endfor %}
{# restore current variables #}
{% set item = currentItem %}
{% set options = currentOptions %}
{% endblock %}
{% block item %}
{% if item.displayed %}
{# building the class of the item #}
{%- set classes = item.attribute('class') is not empty ? [item.attribute('class')] : [] %}
{%- if matcher.isCurrent(item) %}
{%- set classes = classes|merge([options.currentClass]) %}
{%- elseif matcher.isAncestor(item, options.matchingDepth) %}
{%- set classes = classes|merge([options.ancestorClass]) %}
{%- endif %}
{%- if item.actsLikeFirst %}
{%- set classes = classes|merge([options.firstClass]) %}
{%- endif %}
{%- if item.actsLikeLast %}
{%- set classes = classes|merge([options.lastClass]) %}
{%- endif %}
{# Mark item as "leaf" (no children) or as "branch" (has children that are displayed) #}
{% if item.hasChildren and options.depth is not same as(0) %}
{% if options.branch_class is not empty and item.displayChildren %}
{%- set classes = classes|merge([options.branch_class]) %}
{% endif %}
{% elseif options.leaf_class is not empty %}
{%- set classes = classes|merge([options.leaf_class]) %}
{%- endif %}
{%- set attributes = item.attributes %}
{%- if classes is not empty %}
{%- set attributes = attributes|merge({'class': classes|join(' ')}) %}
{%- endif %}
{# displaying the item #}
{% import _self as knp_menu %}
<li{{ knp_menu.attributes(attributes) }}>
{%- if item.uri is not empty and (not matcher.isCurrent(item) or options.currentAsLink) %}
{{ block('linkElement') }}
{%- else %}
{{ block('spanElement') }}
{%- endif %}
{# render the list of children#}
{%- set childrenClasses = item.childrenAttribute('class') is not empty ? [item.childrenAttribute('class')] : [] %}
{%- set childrenClasses = childrenClasses|merge(['menu_level_' ~ item.level]) %}
{%- set listAttributes = item.childrenAttributes|merge({'class': childrenClasses|join(' ') }) %}
{{ block('list') }}
</li>
{% endif %}
{% endblock %}
{% block linkElement %}
{% import "knp_menu.html.twig" as macros %}
<a href="{{ item.uri }}"{{ macros.attributes(item.linkAttributes) }}>
<span class="icon">{{ item.getExtra('icon') }}</span>
<span class="entry">{{ block('label') }}</span>
</a>
{% endblock %}
{% block spanElement %}{% import _self as knp_menu %}<span{{ knp_menu.attributes(item.labelAttributes) }}>{{ block('label') }}</span>{% endblock %}
You should edit your menu template EspaceClientBundle:Menu:knp_menu.html.twig like:
{% block label %}
{% if options.allow_safe_labels and item.getExtra('safe_label', false) %}
{{ item.label|raw|trans }}
{% else %}
{{ item.label }}
{% endif %}
{% if item.extras.icon is defined %}
<i class="{{ item.extras.icon }}"></i>
{% endif %}
{% endblock %}
I recommend you, to delete the whitespaces between twig tags.
Then, in menu builder:
$menu->addChild('Mes Informations', [
'route' => 'espace_client_mesInformations',
'extras' => ['icon' => 'fa fa-home']
]);

Symfony : "if" does not work in a twig template

I'm trying to validate the size of an array before print a value, but the if instruction doesn't work. Always pass thought the if.
This is my code:
{% set size = custodian.phoneNumbers|length %}
{% if size > 3 %}
{% block phone_number3 %}{{phoneNumbers[2].phoneNumber }}{% endblock %}
{% endif %}
size is equal to 2
I try with this code and does not work as well.
{% set size = true %}
{% if size == false %}
{{size}}
{% endif %}
Please help!!!
Thanks in advance.
I found the answers myself
The block should be outside of the if.
{% block phone_type3 %}
{% if size >= 3 %}
{{ custodian.phoneNumbers[2].phoneType.value }}:
{% else %}
:
{% endif %}
{% endblock %}
{% block phone_number3 %}
{% if size >= 3 %}
<b>{{ custodian.phoneNumbers[2].phoneNumber }}</b>
{% endif %}
{% endblock %}

Resources