Check if data is the same as previous - twig

I want to know if it's possible to look at what Twig "print" before something coming. Let me explain. I generate a list like :
Actual case :
Item 1
Item 2
Item 3
Item 4
Item 5
Item 6
...
It might be possible that "Item 5" === "Item 1" (for exemple), and I don't want to print the same value twice. I want something like that :
Item 1
Item 2
Item 6
Item 3
Item 4
...
If we take the actual case, it may be possible that "Item 2" === "Item 4", for exemple, and I want :
Item 1
Item 3
Item 2
Item 5
Item 6
...
Here my Twig code :
{% for underActivity in activity.underActivities %}
{% for indice in underActivity.indications %}
{% for adjusting in indice.adjustings %}
{% if adjusting is not null %}
<li>{{adjusting.name}}
<ul>
{% if indice.indicationPostAdjusting == "Green" %}
<li class="text-success">{{underActivity.name}}</li>
{% elseif indice.indicationPostAdjusting == "Orange" %}
<li class="text-warning">{{underActivity.name}}</li>
{% else %}
<li class="text-danger">{{underActivity.name}}</li>
{% endif %}
</ul>
</li>
{% endif %}
{% endfor %}
{% endfor %}
{% else %}
<p>Aucun aménagement n a été trouvée.</p>
{% endfor %}
...
Do you have any ideas ?
-- UPDATE --
I have this :
and I want this :
Travailler en binôme
Toquer à la porte
Signaler la présence dans la chambre
And :
Surélever la table
Ouverture automatique
Ouvrir les volets
To have something like that, at the final :
Travailler en binôme
Toquer à la porte
Signaler la présence dans la chambre
Surélever la table
Ouverture automatique
Ouvrir les volets
-- UPDATE 2 --
I've tried to create the array with datas that I want. Here is my code inside my controller :
foreach ($indications as $key => $value) {
foreach ($value as $k => $indication) {
$datas[] = [
"adjusting" => $indication->getAdjustings(),
"underActivity" => $indication->getUnderActivities(),
];
}
}
And that's what I got :
So now, how can I have the "name" of adjusting and underActivity ? because the "getName()" function doesn't work ? And that's what you want to see ?

Related

Opencart 3 TWIG: how to use AND operator

I'm trying to use the "AND" operator in TWIG in Opencart 3 and it doesn't work. Please tell me what I'm doing wrong.
I have some product attributes. And I want to make a condition that if two of the attribute with a specific ID are there, then the condition is met.
{% for attribute_group in attribute_groups %}
{% for attribute in attribute_group.attribute %}
{% if attribute.attribute_id == 2 and attribute.attribute_id == 3 %}
First condition
{% elseif attribute.attribute_id == 2 %}
Second condition
{% elseif attribute.attribute_id == 3 %}
Third condition
{% else %}
{% endif %}
{% endfor %}
{% endfor %
Here is text example:
if there is an attribute with ID equal 2 and an attribute with ID equal 3 then write "Floor/Number of floors".
if there is an attribute with ID equal 2 only then write "Floor"
if there is an attribute with ID equal 3 only then write "Numbers of floors".
Something can't be both X and Y at the same time. Furthermore this is something I'd advice you to test in the controller and not in the view.
Anyway if you wanted to do this in the view you will need to track of the found attributes. You could do this with two booleans or just add a counter.
{% set cnt = 0 %}
{% for attribute_group in attribute_groups %}
{% for attribute in attribute_group.attribute %}
{% if attribute.attribute_id == 2 or attribute.attribute_id == 3 %}
{% set cnt = cnt + 1 %}
{% endif %}
{% endfor %}
{% endfor %}
{% if cnt == 2 %}
{# do something #}
{% endif %}
You can simplify the if by using the test in
{% if attribute.attribute_id in [2, 3,] %}
Update of my answer because OP changed the requirements of the question
{% set words = [] %}
{% for attribute_group in attribute_groups %}
{% for attribute in attribute_group.attribute %}
{% if attribute.attribute_id == 2 %}
{% set words = words|merge(['Floor',]) %}
{% elseif attribute.attribute_id == 3 %}
{% set words = words|merge(['Numbers of floors',]) %}
{% endif %}
{% endfor %}
{% endfor %}
{% if words|default %}
{{ words|join('/') }}
{% endif %}
demo

How to access an element with an unknow name

I need to show a value from an element but his name is not always the same.
In my "competence" object, I have 4 fields, let's say field_1, field_2, field_3, field_4, but in function of an other value, I only have to display on of them.
I have the value in an other field of my "competence" object, "field_niveau_attendu" (it is set to 1, 2, 3 or 4)
I tried to use a "set" function
{% set niveau = "field_descriptif_" ~ competence.field_niveau_attendu.value %}
<p class="">{{ competence.field_competences_transverses.entity.niveau.value }}</p>
but it won't work
if in field_competences_transverses you have only 4 fields (field_1, field_2, field_3, field_4) you can try to use "for"
{% if competence.field_niveau_attendu.value is defined %}
{% set niveau = competence.field_niveau_attendu.value %}
{% for descriptif in competence.field_competences_transverses.entity %}
{% if loop.index == niveau %}
{{ descriptif.value }}
{% endif %}
{% endfor %}
{% endif %}

How to add "Read More" in text displayed on several lines but only a certain number of lines with twig

I am using the following function in twig to show a part of the content of the description of a news item saved in a database:
{{ new.description|striptags|truncate(300,true)|raw|nl2br }}
With this function inside a p element in the html, I get the text whose characters do not exceed 300 and then I add "Read More" with an element a:
<p >{{ new.description|striptags|truncate(200,true)|raw|nl2br }}
<a class="href_blue" href="{{ path('new', {'id': new.id}) }}">
<strong> [Read More] </strong></a>
</p>
This code works for text that comes in a paragraph with more than 300 characters, but if for example I have another one with several "p" elements that are then changed in twig to elements and I need it to only show me several lines because I have A maximum elevation of the container where it is displayed, I would not know how to do it, since it shows me all line breaks until it does not exceed 300 characters.
To clarify it a little more, I show an image of the result:
What I need is that in the case of Title2 having many line breaks, just show some and add the "Read More" before so that the height of the div is equal to the previous one (to show the example I removed the max- Height and overflow: hidden).
How could I get that?
I greet your help in advance.
You could do something like this in Twig:
{% set paragraphs = new.description|split('</p>') %}
{% set summary = '' %}
{% for i in 1..10 %}
{% set summary = summary ~ paragraphs[i] %}
{% endfor %}
{% set summary = summary ~ '[Read More]' %}
Now you can use the summary variable in your twig file to show the truncated summary.
EDIT #2 based on comments
Then try this instead:
{% set paragraphs = new.description|split('</p>') %}
{% set summary = '' %}
{% for i in 1..(paragraphs|length) %}
{% set summary = summary ~ paragraphs[i] %}
{% if summary|length > 300 %}
{% set shortsummary = summary %}
{% endif %}
{% endfor %}
{% set final_summary = shortsummary|slice(:300) ~ '[Read More]' %}
EDIT #3 Code modified with the solution to the problem
{% set paragraphs = new.description|striptags|truncate(300,true)|raw|nl2br %}
{% set paragraphs = paragraphs|split('<br />') %}
{% set summary = "" %}
{% set cont = 90 %}
{% set type = "" %}
{% if paragraphs|length == 1 %}
{% set summary = paragraphs[0] %}
{% if summary|length <= 300 %}
{% set type = "" %}
{% else %}
{% set type = "anything" %}
{% endif %}
{% else %}
{% for i in 1..(paragraphs|length) %}
{% if summary|length + cont + paragraphs[i-1]|length <= 500 %}
{% set summary = summary ~ "<br>" ~ paragraphs[i-1] %}
{% set cont = cont + 90 %}
{% else %}
{% set type = "anything" %}
{% endif %}
{% endfor %}
{% endif %}
//In the case of a description with less than 300 characters the option "Read More" is not shown
{% if type != "" %}
<p>{{ summary|striptags|truncate(300,true)|raw|nl2br }}<a class="href_blue" href="{{ path('new', {'id': new.id}) }}"> <strong> [Read More] </strong></a></p>
{% else %}
<p>{{ summary|striptags|truncate(300,true)|raw|nl2br }}<a class="href_blue" href="{{ path('new', {'id': new.id}) }}"></a></p>
{% endif %}

Print loop within loop with Twig?

I have nested content in a Twig array. I have months, each of which have days:
In my page.twig:
{% set mock = {
main_title: 'Main title',
months:
[
{
sub_title: 'Title 1',
days: [
{
monday: 'Lorum',
tuesday: 'Ipsum'
}
]
},
{
sub_title: 'Title 2',
days: [
{
monday: 'Dolorem',
tuesday: 'Neque'
}
]
}
]
}
%}
{% include "component.twig" %}
I'm trying to print each month's sub title and the day text under it:
<h2>Title 1</h2>
<h3>Lorum</h3>
<h3>Ipsum</h3>
<h2>Title 2</h2>
<h3>Dolorem</h3>
<h3>Neque</h3>
In component.twig:
{% for m in months %}
<h2>{{ m.sub_title }}</h2>
{% for d in months.days %}
<h3>Print test</h3>
{% endfor %}
{% endfor %}
The month's sub_title in <h2> is printing fine but I can't even get the days in the months to loop correctly.
It appears that the mistake is in your second loop. Instead of months.days, you need to use m.days.
Your first loop pulls the month into the variable m. As your main array months does not have an element days, but each individual month does, your inner loop currently has no content to print.
Just as a side note, I would also recommend adding escaping if this template doesn't use autoescape.
{% for m in months %}
<h2>{{m.sub_title| e}}</h2>
{% for d in m.days %}
<h3>{{ d| e }}</h3>
{% endfor %}
{% endfor %}
------edit-----
I missed on first pass that your sample array has an array "days" with a hash inside it instead of being a single level. In this case, you actually have the equivalent (in PHP anyway of an array in an array) for the days key.
This should do the trick in this case
{% for m in months %}
<h2>{{m.sub_title| e}}</h2>
{% for d in m.days[0] %}
<h3>{{ d| e }}</h3>
{% endfor %}
{% endfor %}

Twig - array_pop?

I have a multi dimensional array along the lines of
array(2) {
[11]=> array(1) {
["L2J"]=> array(1) {
["VS7"]=> array(2) {
["26 Feb 2015 12:00"]=> array(2) {
["C"]=> string(1) "9"
["D"]=> string(1) "9"
}
["26 Feb 2015 13:00"]=> array(2) {
["C"]=> string(1) "9"
["D"]=> string(1) "6"
}
}
}
}
}
Now I have done some looping and I am now at the point where I have access to the dates.
{% for sid, psuedos in alerts %}
{% for psuedo, flights in psuedos %}
{% for flight, dates in flights %}
{% endfor %}
{% endfor %}
{% endfor %}
Now I am converting some normal PHP code and at this point, I would do
$firstDate = array_pop(array_keys($dates));
Is there any way to do something like this in Twig? I have searched about but cant seem to find anything.
Update
This is my latest effort, can't seem to get it to slice the last array element though
{% set firstDate = [dates|keys]|last|slice(1) %}
There isn't a Twig function that will do exactly what array_pop() does (return the last array element and shorten the array at the same time), but there are ways to do them separately.
Given:
{% set array = [1,2,3,4,5] %}
To get the last element, use Twig's last filter.
{{ array|last }}
{# returns '5' #}
You can remove only the last element with the slice filter like this: slice(0,-1)
{% set array = array|slice(0,-1) %}
{# array = [1,2,3,4] #}
... or the Craft without filter:
{% set arrayLast = array|last %}
{% set array = array|without(arrayLast) %}
{# array = [1,2,3,4] #}
pop last element
{% set array = [1,2,3] %}
{% set value = array|last %}
{{ value }} {# return 3 #}
{% set array = array|slice(start, length - 1) %}
{% for value in array %}
{{ value }} {# return 1,2 #}
{% endfor %}
pop the first element
{% set array = [1,2,3] %}
{% set value = array|first %}
{{ value }} {# return 1 #}
{% set array = array|slice(start + 1, length) %}
{% for value in array %}
{{ value }} {# return 2,3 #}
{% endfor %}
Just as a quick check, have you tried slice(-1)?
Passing a negative number as the first parameter should start at the end of the array and work that many back.

Resources