im reading
Find substring in the string in TWIG
and on a single item it works fine for me.
<!-- language: lang-html -->
<li {% if 'page' in app.request.get('_route')|lower %}class="active"{% endif %}>
<a href="{{path('adminPage')}}">
<i class="fa fa-file-text"></i> <span>{% trans %}pages_text{% endtrans %}</span> <small class="label pull-right bg-{% if nav_options.count_pages > 0 %}primary{% else %}red{% endif %}">{{ nav_options.count_pages }}</small>
</a>
</li>
now I find myself needing it to happen differently.
how would I do to find if "items in this array" are contained in "this substring"
the example would be something like this
{% if ['str1','str2'] in/contained in app.request.get('_route')|lower %}class="active"{% endif %}
I tried this and does not work.
I also would rather avoid using the "or" operator, if its a requirement so be it, but if it can be avoided, the better.
I even went and attempted a split parameter.
{% if 'page,blog'|split(',') in app.request.get('_route')|lower %}active {% endif %}
no dice!
the code is meant to allow me to have "several possible routes" inside a collapsible menu item, and if any of the possible route names (i have several route names, blog, blogAdd, blogEdit, blogPost etc) contains "blog" (same with page, and many others) the "active" class should be printed.
Creating a custom twig function would be an easier solution to use
$function = new Twig_SimpleFunction('array_in_string', function ($haystacks, $needle) {
foreach($haystacks as $haystack) if (stripos($haystack, $needle) !== false) return true;
return false;
});
$twig = new Twig_Environment($loader);
$twig->addFunction($function);
Then you call this function in Twig with :
{% if array_in_string(['page','blog',], app.request.get('_route')) %}
{# do sthing #}
{% endif %}
I don't think you ought to be accessing HTTP stuff - eg get variables - in your view. That's kinda muddying yer MVC a bit.
I'd resolve all that in your controller, and just pass the result to the view (untested, obviously, so treat it as pseudocode):
// controller
$thingIsActive = in_array(strtolower($request->get('_route')), ['str1','str2']);
return $app['twig']->render('whatever.twig', ['thingIsActive' => $thingIsActive]);
{# whatever.twig #}
<li{% if thingIsActive %} class="active"{% endif %}>
Related
I have a twig template where I would like to test if an item begins with a certain value
{% if item.ContentTypeId == '0x0120' %}
<td><a href='?parentId={{ item.Id }}'>{{ item.BaseName }}</a><br /></td>
{% else %}
<td><a href='?{{ item.UrlPrefix }}'>{{ item.LinkFilename }}</a></td>
{% endif %}
The 0x0120 can look like that or be more complex like this 0x0120D52000D430D2B0D8DD6F4BBB16123680E4F78700654036413B65C740B168E780DA0FB4BX. The only thing I want to do is to ensure that it starts with the 0x0120.
The ideal solution would be to solve this by using regex but I'm not aware if Twig supports this?
Thanks
You can do that directly in Twig now:
{% if 'World' starts with 'F' %}
{% endif %}
"Ends with" is also supported:
{% if 'Hello' ends with 'n' %}
{% endif %}
Other handy keywords also exist:
Complex string comparisons:
{% if phone matches '{^[\\d\\.]+$}' %} {% endif %}
(Note: double backslashes are converted to one backslash by twig)
String contains:
{{ 'cd' in 'abcde' }}
{{ 1 in [1, 2, 3] }}
See more information here: http://twig.sensiolabs.org/doc/templates.html#comparisons
Yes, Twig supports regular expressions in comparisons: http://twig.sensiolabs.org/doc/templates.html#comparisons
In your case it would be:
{% if item.ContentTypeId matches '/^0x0120.*/' %}
...
{% else %}
...
{% endif %}
You can just use the slice filter. Simply do:
{% if item.ContentTypeId[:6] == '0x0120' %}
{% endif %}
You can always make your own filter that performs the necessary comparison.
As per the docs:
When called by Twig, the PHP callable receives the left side of the filter (before the pipe |) as the first argument and the extra arguments passed to the filter (within parentheses ()) as extra arguments.
So here is a modified example.
Creating a filter is as simple as associating a name with a PHP
callable:
// an anonymous function
$filter = new Twig_SimpleFilter('compareBeginning', function ($longString, $startsWith) {
/* do your work here */
});
Then, add the filter to your Twig environment:
$twig = new Twig_Environment($loader);
$twig->addFilter($filter);
And here is how to use it in a template:
{% if item.ContentTypeId | compareBeginning('0x0120') == true %}
{# not sure of the precedence of | and == above, may need parentheses #}
I'm not a PHP guy, so I don't know how PHP does regexes, but the anonymous function above is designed to return true if $longString begins with $startsWith. I'm sure you'll find that trivial to implement.
I am trying to add pagination to my current project. I am pretty new to Symfony so I am not sure if there is something out there that can help me build such. My current code looks like this:
Controller class:
class MovieDisplayController extends Controller
{
public function showAction()
{
$movies = $this->getDoctrine()->getEntityManager()->getRepository('AppBundle:Movie')->FindAll();
return $this->render('movies/index.html.twig', array(
'movies' => $movies
));
}
}
Twig template:
{% block body %}
{% if movies|length == 0 %}
There are no movie items available. Add a movie here to get started.
{% elseif movies|length != 0 %}
These are the results: <br />
<ul>
{% for x in movies %}
<li>Title: {{ x.title }} - Price: {{ x.price }} - Edit - Details - Delete</li>
{% endfor %}
</ul>
Add more movie entries
{% endif %}
{% endblock %}
This will return all results within the database. I would like to only show 5 results (rows per page) and add paging buttons below the list and I wonder how/if this is possible?
The findAll() function will not work if you want to set limit.
You can try KnpPaginatorBundle to add pagination in symfony. It will work with fine to add pagination.
https://github.com/KnpLabs/KnpPaginatorBundle
I get a list of collections right from Doctrine and I store them into an array.
For example:
$data['collList'] = $heyDoctrine->giveMeMyColls();
But I also want to retrieve some informations about these collections.
I store it into $data['collectionId'].
Until this point, everything works fine.
But in my Twig template, I want to create ordered lists with the name of my collection and every item of this list would be an information about this collection.
So, in PHP, I would do this:
foreach($data['collList'] as $collItem){
echo $collItem['name'];
echo '<ul>';
foreach($data[$collItem['id']] as $collItemData){
echo '<li>'.$collItemData.'</li>';
}
}
My problem is: how to do this with Twig?
I don't know how to say to Twig «hey, use «coll.id» as THE NAME of an other variable!
I've looked a bit and I've found the «attribute» function, but I wasn't able to make it work.
How should I do that?
Thanks a lot.
So, try next twig code:
{% for key, collItem in data.collList %}
{{ collItem.name }}
<ul>
{% for collItemData in data[collItem.key] if key == 'id' %}
<li> {{ collItemData }} </li>
{% endfor %}
</ul>
{% endfor %}
Are there any nice ways to use while and repeat loops in Twig? It is such a simple task, but without macros I can't find anything nice and simple.
At least do an infinite cycle and then break it in a condition?
EDIT:
I mean something like
do {
// loop code
} while (condition)
or
while (condition) {
// loop code
}
Edit 2:
Looks like it is not supported natively by twig same reason as it is not supported neither continue; or break; statements.
https://github.com/twigphp/Twig/issues/654
You can emulate it with for ... in ... if by using a sufficiently-high loop limit (10000?)
while
PHP:
$precondition = true;
while ($precondition) {
$precondition = false;
}
Twig:
{% set precondition = true %}
{% for i in 0..10000 if precondition %}
{% set precondition = false %}
{% endfor %}
do while
PHP:
do {
$condition = false;
} while ($condition)
Twig:
{% set condition = true %} {# you still need this to enter the loop#}
{% for i in 0..10000 if condition %}
{% set condition = false %}
{% endfor %}
I was able to implement a simple for loop in twig. So the following php statement:
for ($x = 0; $x <= 10; $x++) {
echo "The number is: $x <br>";
}
when translated to twig is:
{% for i in 0..10 %}
* {{ i }}
{% endfor %}
It's not a while loop but a potential workaround. The best suggestion is to leave business logic like this out of the template layer.
In a nutshell: no. This functionality implies advanced logic, which should be in your business logic, not in the template layer. It's a prime example of the separation of concerns in MVC.
Twig supports for-loops completely, which should suffice if you code correctly - being that complex conditional decisions on which data to display are taken in the business logic where they belong, which then pass a resulting array 'ready to render' to the templates. Twig then supports all nice features only needed for rendering.
This is possible, but a little bit complicated.
You can use {% include ... %} to process nested arrays, which from the comments I read is what you need to do.
Consider the following code:
nested_array_display.html
<ul>
{% for key, val in arr %}
<li>
{{ key }}:
{% if val is iterable %}
{% include 'nested_array_display.html' %}
{% else %}
{{ val }}
{% endif %}
</li>
{% endfor %}
</ul>
Warning with the top solution with "high loop limit" : the loop doesn't break when the condition returns false, it just doesn't enter the loop. So the loop runs up to the high indice
First of all, I know that the logic should be in the controller and not in the view and I keep it that way.
But in this particular situation I need to use preg_match within a ternary operation to set the css class of a div.
Example:
{% for list in lists %}
<div class="{{ (preg_match(list.a, b))>0 ? something : else }}"...>...</div>
{% endfor %}
How can I achieve the (preg_match(list.a,b))>0 condition in twig?
Thanks in advance
For those who came here from Google search results (like me).
There's containment operator that allows you to do something like this:
{{ 'cd' in 'abcde' }} {# returns true #}
You can't use preg_match() directly but there are ways to accomplish it:
if your list is an entity, add a method matches(): {{ (list.matches(b)) ? something : else }}
you could create a custom Twig extension function that uses preg_match() internally http://symfony.com/doc/master/cookbook/templating/twig_extension.html
Expanding from Serge's comment and is the correct answer.
In my example my string is "Message Taken - 12456756". I can then use |split to convert it into an array and use |replace to get ride of white space.
{% set mt = 'Message Taken' in d.note %}
{% if mt == true %}
{#.. you can then do something that is true#}
{% set mt_array = d.note|split('-') %}
{{ mt_array[0] }} | {{ mt_array[1]|replace({' ' : ''}) }}
{% endif %}
This would output my string but I now control two parts instead of 1.