i have time in format HHMM as string and would like to add " : " after hours. is there a simple filter to split string after two characters and add a delimiter?
You can split by position like this
{% set bar = "aabbcc"|split('', 2) %}
{# bar contains ['aa', 'bb', 'cc'] #}
As described in the doc
So you can do something like:
{% set bar = "1203"|split('', 2) %}
{# bar contains ['12', '03'] #}
now let's do:
{{ bar[0]~":"~bar[1] }}
this will output:
12:03
Better if you build a macro or a TWIG extension with the function
Hope this help
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.
How to print available form string in twig
In my code php
$data['fruits'] = array('apple', 'banana', 'orange');
$data['help_apple'] = 'This is help apple';
$data['help_banana'] = 'This is help for banana';
$data['help_orange'] = 'This is help for orange';
In twig template
{% for fruit in fruits %}
{{ "help_" ~ fruit }}
{% endfor %}
The print screen is help_apple, help_banana, help_orange
How to print correct data i need for help_ fruit key ?
You need to use the attribute function with _context. Tested on twigfiddle.com. Hope this helps.
{% for fruit in fruits %}
{# Here is how you do it #}
{{ attribute(_context, 'help_'~ fruit) }}
{% endfor %}
The _context variable holds all variables in the current context. Instead of using the attribute function, you can access values of the _context array with the regular bracket notation as well:
{% for fruit in fruits %}
{{ _context['help_' ~ fruit] }}
{% endfor %}
I would personally do it this way as it's more concise and in my opinion clearer.
You might want to check for undefined variables when accessing values of the _context array. I have written about it in my answer to this question: Symfony2 - How to access dynamic variable names in twig.
You also asked whether something like this is possible:
{% set attribute(context, 'help' ~ fruit, "value") %}
That's not possible. If you want to set variables with dynamic names, you need to create a Twig extension. Take a look at my answer to this question: How to set a variable name with dynamic variables?
But, like #user9189147 mentioned, it would be easier and in my opinion clearer if you instead created a new array to hold the help values. Then you wouldn't need to create an extension.
$data['fruits'] = ['apple', 'banana', 'orange'];
$data['help'] = [];
$data['help']['apple'] = 'This is help apple';
$data['help']['banana'] = 'This is help for banana';
$data['help']['orange'] = 'This is help for orange';
{% for fruit in fruits %}
{{ help[fruit] }}
{% endfor %}
Then you can set new values to the help values in Twig using the merge filter, like this (though I don't know why you would want to do it in Twig):
{# Set single value #}
{% set help = help|merge({
banana: 'New help for banana',
}) %}
{# Or multiple values #}
{% set help = help|merge({
apple: 'An apple a day keeps the doctor away',
orange: 'Orange is the new black',
}) %}
I have a situation where I need to identify if there is a blank space in a variable in a twig template, and to treat it slightly differently.
Given names in this application are stored with middle initials in the given name field; they are not stored separately.
What I'm trying to achieve is this: Typically most given names are one word, e.g. "John" or "Susan" or something similar. In some of these cases we have cases where the middle initial is stored within this variable (e.g. John J)
Following standard citation standards, we need to be able to list items like this:
{{ surname }}, {{ given_name }}, ed.
This way it would appear like "Smith, John, ed." This is normally fine, however in some situations, where there is a middle initial, it appears as "Smith, John J, ed." - this is incorrect. I can't add a period after the given name, as "Smith, John., ed" would be an incorrect citation standard.
What I'm trying to do is to identify if a given_name contains a space, followed by a single letter, and then format it differently.
Something like this:
{% if given_name [has a blank space preceding a single letter] %}
{{ given_name }}., ed.
{% else %}
{{ given_name }}, ed.
{% endif %}
Is there a way to do this with regex within twig, or is there another method?
Thanks in advance
We can translate your requirement:
has a blank space preceding a single letter
In this little algorithm:
{% set given_name = 'John J' %}
{% set given_name_elems = given_name|split(' ') %}
{% set size = given_name_elems|length %}
{% if size >0 and given_name_elems[size-1]|length == 1%}
{ given_name }}., ed.
{%else%}
{{ given_name }}, ed.
{%endif%}
I suggest you to incapsulate this logic in a function or in a macro.
You could made some try in this working example
This is possible, but is not necessarily going to handle edge cases well. Assuming that you need to do the whole thing in twig, you could do something like this:
{% set nameArray = given_name | split(' ') %}
{% set first_name = nameArray[0] %}
{% set middle_initial = nameArray[1] is defined ? " "~nameArray[1]~"." : ""%}
At this point `middle_initial is now set to either an empty string or the middle initial with the period so you can output the full name like:
{{ surname }}, {{first_name ~ middle_initial}}, ed
You could use a regex with the matches comparison operator and add the dot if given_name matches the pattern.
{{ given_name }}{% if given_name matches '/^.+ .$/' %}.{% endif %}
Sorry, I didn't give you a good answer initially. I've updated my code and my twigfiddle. It's a bit simpler than #Matteo 's:
{% set given_name = 'John J' %}
{% set nameArray = given_name|split(' ') %}
{% if nameArray[1] is defined %}
{{ nameArray[0] }} {{ nameArray[1] }}., ed.
{% else %}
{{ nameArray[0] }}, ed.
{% endif %}
Where {{ nameArray[0] }} specifies the first element of the array. If nameArray1 contains anything, then it is defined.
Here is a working twigfiddle to show you it works.
I tried the answers of this question, but it's not working. It's weird and I cannot reproduce the behavior:
I cleared the cache
Concat works (it output's the right string)
The concated string as a variable is not translateable
The concated string pasted as a string is translateable
Edit: obj2arr casts the object to an array, to make it iterable. prepareForTwig is just using trim(), etc. - the string is outputted correctly.
Edit 2: {% set transVar = (key|prepareForTwig) %} (without prefix) doesn't work as well.
yml:
# Resources/translations/messages.en.yml
my:
keywords:
keyword1: K1
keyword2: K2
# ...
twig:
{# my.twig.html #}
{% for key, value in data|obj2arr %}
{% set transVar = 'my.keywords.' ~ (key|prepareForTwig)) %}
{{ transVar }}<br/> {# output, e.g.: my.keywords.keyword1 #}
{{ transVar|trans}}<br/> {# output, e.g.: my.keywords.keyword1 #}
{{ 'my.keywords.keyword1'|trans }} {# output: K1 #}
{% endfor %}
EDIT:
CustomTwigExtension.php
class CustomTwigExtension extends \Twig_Extension
{
public function getFilters()
{
return array(
new \Twig_SimpleFilter('obj2arr', array($this, 'obj2arrFilter')),
new \Twig_SimpleFilter('prepareForTwig', array($this, 'prepareForTwigFilter')),
);
}
public function obj2arrFilter($obj)
{
return (array)$obj;
}
public function prepareForTwigFilter($str) {
$str = trim($str);
$str = strtolower($str);
$str = substr($str, 2, strlen($str)); // obj2arr() prefixes "*"
return $str;
}
public function getName()
{
return 'custom_twig_extension';
}
}
Thanks in advance!
Others examples didn't seem to work in my case, this is what I ended up using:
{{ "my.prefix.#{ myVariable }.my.postfix" | trans }}
The translation string has to be between double quotes.
Every answer of outputting concated translationstrings was right, example:
{% 'my.prefix.' ~ extendByKeyword | trans }}
The problem was a weird generated space:
(array) $obj added * (there are two spaces after the star) as a prefix to the key-variable.
I used substr() to get rid of the * (star + 1 space), but didn't notice/expect the second space.
After comparing the strings with strlen(), I found the cause.
Thanks to #Artamiel and #CarlosGranados for your help.
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.