Problem with or in Regexp - php

I have this Regexp:
/\{%\s([^else|endloop|endif][a-z0-9\.\|_]+)\s%\}/si
I use this regexp in preg_replace.
And this markup:
{# comment %}
{# comment number 2$% %}
{% variable %}
{% array.key1.key2 %}
{% array.key1.key2|escape|bold %}
{% variable|escape %}
{% loop array as item %}
My item is {% item.text %}
{% endloop %}
{% if (something): %}
do something truly
{% else: %}
nothing to do
{% endif; %}
Why this regexp is not working for {% item.text %} but works with other?
I think that I made some mistake here [^else|endloop|endif]
What I'm doing wrong?

I think you may intend:
/\{%\s((?!(else|endloop|endif))[a-z0-9\.\|_]+)\s%\}/si
The square brackets previously containing the else, endloop and endif keywords treats each individual character as an exception. Here they are treated as whole strings.

Related

Printing out an array in twig using a for loop

i have to configurate a .csv file.
I have a variable that is either a single value or an array of values. If it is a single value, i want to put that single value into the cell, otherwise i want to put every value in the array into the cell.
This is my approach, but it's not iterating through the array. If the item is an array, it just puts nothing into to table cell. Do i need to increment i in some sort of way?
{% if item is iterable %}
{% for i in item[0..10]%}
*{{ item[i] }}
{% endfor %}
{% else %}
{{item}}
{% endif %}
Not sure why are you using {% for i in item[0..10]%} to iterate the item?
0..10 returns an array in twig, which will result in the following "code"
{% for i in item[Array] %}
This will return nothing as the index Array doesn't exist in the array item.
The proper way to iterate the value would be
{% if item is iterable %}
{% for i in item %}
{{ i }}
{% endfor %}
{% else %}
{{item}}
{% endif %}
If you are trying to display only 10 values from the array u'd go with
{% for i in item[0:10]%}
{{ i }}
{% endfor %}
or
{% for i in item|slice(0, 10) %}
{{ i }}
{% endfor %}

Find value in array and return with new from different array

Currently I have two arrays
{% set code = [AMS, EIN, RTM] %}
{% set city = [Amsterdam, Eindhoven, Rotterdam] %}
I would like to check if the value of {{airport}} exists in the first array and if it is code[0] I would like to change {{airport}} into the value of city[0]. Is this possible with Twig?
You can loop over the code array:
{% for c in code %}
{# ... #}
{% endfor %}
Documentation: https://twig.symfony.com/doc/2.x/tags/for.html
Then if the item does match:
{# ... #}
{% if airport == c %}
{# ... #}
{% endif %}
{# ... #}
Documentation: https://twig.symfony.com/doc/2.x/tags/if.html
Replace the variable airport, at the same loop index:
{# ... #}
{% set airport = city[loop.index0] %}
{# ... #}
Documentation: https://twig.symfony.com/doc/2.x/tags/for.html#the-loop-variable
So, in full:
{% for c in code %}
{% if airport == c %}
{% set airport = city[loop. index0] %}
{% endif %}
{% endfor %}
Running fiddle: https://twigfiddle.com/xflfas/2
Out of the scope note: your arrays would be better named cities and codes.
This way, when you loop over them, you end up with meaningful naming
{% set codes = ['AMS', 'EIN', 'RTM'] %}
{% for code in codes %}
{{ code }}
{% endfor %}
{# and #}
{% set cities = ['Amsterdam', 'Eindhoven', 'Rotterdam'] %}
{% for city in cities %}
{{ city }}
{% endfor %}
Use {% if value in array %} to search from the first array and Twig's merge function to replace the value in the second array. See this https://twig.symfony.com/doc/2.x/filters/merge.html

Print Twig variable x times based upon randomized range

I am using Twig and Timber for a WordPress project. I have the following loop in my template that prints my custom post type titles into a HTML structure.
{% for company in companies %}
{% set dot = "<div class='company-dot'></div>" %}
{% set range = range(10, 20) %}
{{dot}}
{{random(range)}}
<div class="company">
<div class="company-dot dot-active"></div>
<p class="dot-caption">{{ company.title }}</p>
</div>
{% endfor %}
I would like to print my {{dot}} variable x amount of times based upon the number that is generated by {{random(range)}}. How can I do this?
The simplest solution would be to iterate random(range) times with a for loop:
{% for i in 0..random(range(10, 20)) %}
{{ dot }}
{% endfor %}
I don't really know Twig but my guess is that you could to the following:
{% for i in random(range) %}
{{dot}}
{% endfor %}
You already know how to use range, just use it again :
{% set dots_count = random(range) %}
{% for dot_index in range(1,dots_count) %}
{{dot}}
{% endfor %}
{{dots_count}}
Here is a fiddle : https://twigfiddle.com/ko595z

Is it possible to concatenate a variable to an if statement in Twig?

I am trying to concatenate a variable to an array key to get access to certain values in Twig, but no success so far.
I have a large PHP array that has for example keys like this:
$array = [
...
...
...
'test_1' => $test_1,
'test_2' => $test_2
];
I tried the following in my Twig template:
{% for i in 1..2 %}
{% if array.test_{{ i }} != 0 %}
<div>Test</div>
{% endif %}
{% endfor %}
but that doesn't work.
Is there a way to access values like this in Twig?
Try this:
{% for i in 1..2 %}
{% if array['test_' ~ i] != 0 %}
<div>Test</div>
{% endif %}
{% endfor %}

Regex to match blocks inside blocks

I have the follow string:
{% if a == 3 %}
Yes
{% else %}
{% if b == 2 %}
Maybe
{% else %}
{% if c == 1 %}
Hm... Not
{% else %}
No way!
{% endif %}
{% endif %}
{% endif %}
{% if d == 0 %}
Ok
{% endif %}
If I use this regexp
/\{%\s*if\s*(.*?)\s*%\}(.*)(\{%\s*else\s*%\}(.*))?\{%\s*endif\s*%\}/ism
(in preg_match_all function on PHP), my return is all code above. But when I use
/\{%\s*if\s*(.*?)\s*%\}(.*?)(\{%\s*else\s*%\}(.*?))?\{%\s*endif\s*%\}/ism
(just out of greedy mode), my return ends at {% endif %} of {% if c == 1 %} if (the first endif found).
I want to get the following return:
1.
{% if a == 3 %}
Yes
{% else %}
{% if b == 2 %}
Maybe
{% else %}
{% if c == 1 %}
Hm... Not
{% else %}
No way!
{% endif %}
{% endif %}
{% endif %}
2.
{% if d == 0 %}
Ok
{% endif %}
How should be my regex to archive this return?
PS. I know, if I put some name on ifs and use this name on endif, it could be easily resolved using backreference... But I DO NOT want a palliative answer
Thanks in advance.
You can use this recursive pattern:
$pattern = '~{% if [^%]+%}(?>[^{]+|(?R))*(?>{% else %}(?>[^{]+|(?R))*)?{% endif %}~';
online demo
pattern details:
~
{% if [^%]+%}
(?> # this atomic group describes the content
# between if/else/endif markups:
[^{]+ # - all that is not an opening curly bracket
| # OR
(?R) # - recursion (repeat the whole pattern)
)* # repeat the group zero or more times
(?>
{% else %} # The "else" part works exactly in the same way,
(?>[^{]+|(?R))*
)? # but is optional
{% endif %}
~
I extended this example to solve my own problem, specially to have some random {% ... %} in it: regex101 online demo

Categories