represent a variable in twig using for loop - symfony

In my Service I return an array which looks like this:
$array = [
'bible_anagram_word' => $result->getBibleAnagramWord(),
'word_1' => $result->getWord1(),
'word_2' => $result->getWord2(),
'word_3' => $result->getWord3(),
...
'word_22' => $result->getWord22(),
'word_23' => $result->getWord23(),
'word_24' => $result->getWord24(),
'word_25' => $result->getWord25(),
'Bible_verse_reference' => $result->getBibleVerseReference(),
'Bible_verse_text' => $result->getBibleVerseText(),
'Bible_translation' => $result->getBibleTranslation(),
];
How do I represent document.word_## in this for loop?
{% for i in 1..25 %}
{{ document.word_ ~ i|slice(0,1) }}
{% endfor %}
In PHP this code is:
substr ( $this->document['word_'.$i] , 0 , 1 )
My unsuccessful attempts include:
{{ document.word_ ~ i|slice(0,1) }}
{{ (document.word_ ~ i)|slice(0,1) }}
{{ 'document.word_ ~ i'|slice(0,1) }}

This should do the trick
{{ attribute(document, 'word_' ~ i) }}
More on attribute function

Related

Sf/Twig - count number of property with same value

I just want to display on a twig view the number of a property with a value defined like
<div class="list-group">
{% for ticket in tickets %}
{% if ticket.statut == 'En attente' %}
{{ loop.index }}
{{ ticket.statut }}
<div class="d-flex justify-content-start"><i class="fas fa-ticket-alt"></i> {{ ticket.getNomProduit }}</div>
{% endif %}
{% endfor %}
</div>
but i got the right number(2) but i would only display the number of this specific ticket with value "En attente"
If I had to implement such a thing, I would do it somewhere in the PHP controller, something like this:
// In the controller:
$ticketsEnAttente = array_filter($tickets,
function($ticket) {
return $ticket['statut'] === 'En attente';
}
);
return $this->render('my_template.html.twig', [
'tickets_en_attente' => $ticketsEnAttente,
]);
Then it is trivial to show the count and the different tickets in Twig, something like:
<div>
{{ tickets_en_attente | length }} tickets en attente:
</div>
{% for ticket in tickets_en_attente %}
{{ loop.index }}
<div class="d-flex justify-content-start">
<a href="{{ path('ticket', {id:ticket.id}) }}" class="list-group-item list-group-item-action active">
<i class="fas fa-ticket-alt"></i>
{{ ticket.getNomProduit }}
</div>
</a> {# NOTE: there is an html error in your code, </div> and </a> are inverted #}
{% endfor %}
The only difference here is that the loop index will not be the same as the original code you gave, because it takes only into account the filtered list.
In a general way, it is a good idea to put as few as possible complex computations in the twig templates. Controllers and services are a better place for it.
EDIT
To answer to your comment, if there are several statuses, you can create a variable which groups tickets by their status:
// In your controller:
// Mock data:
$tickets = [
[ 'id' => 1, 'statut' => 'Fermé' ],
[ 'id' => 2, 'statut' => 'En attente' ],
[ 'id' => 3, 'statut' => 'Ouvert' ],
[ 'id' => 4, 'statut' => 'En attente' ],
];
// Group tickets by status:
$ticketsByStatus = [];
foreach ($tickets as $ticket) {
$ticketsByStatus[$ticket['statut']][] = $ticket;
}
// This is equivalent to writing this by hand:
$ticketsByStatus = [
'Fermé' => [
[ 'id' => 1, 'statut' => 'Fermé' ],
],
'En attente' => [
[ 'id' => 2, 'statut' => 'En attente' ],
[ 'id' => 4, 'statut' => 'En attente' ],
],
'Ouvert' => [
[ 'id' => 3, 'statut' => 'Ouvert' ],
],
];
return $this->render('default/index.html.twig', [
'tickets_by_status' => $ticketsByStatus,
]);
Then you can iterate over each status in the template (or access them manually if you prefer), something like this:
{% for status in tickets_by_status|keys %}
<h4>{{ status }}:</h4>
<ul>
{% for ticket in tickets_by_status[status] %}
<li>
{{ ticket.id }}
{# {{ ticket.getNomProduit }} #}
</li>
{% endfor %}
</ul>
{% endfor %}
Up to you to make this fit to your own needs.
Try this:
<div class="list-group">
{% set count = 0 %}
{% for ticket in tickets %}
{% if ticket.statut == 'En attente' %}
{{ loop.index }}
{{ ticket.statut }}
<div class="d-flex justify-content-start"><i class="fas fa-ticket-alt"></i> {{ ticket.getNomProduit }}</div>
{% set count = count + 1 %}
{% endif %}
{% endfor %}
{{ count }} Total File En attente
</div>

Symfony Twig parse Json

I have route that is using cUrl.
The cUrl returns Json data.
So, I did $data = json_decode($results);
It returns:
(
.....
[dovecot] => stdClass Object
(
[info_str] => Running
[name] => Dovecot
[version] => 2.3.4
)
[exim] => stdClass Object
(
[info_str] => Running
[name] => Exim
[version] => 4.91
)
.......
}
So when I do return $data; on my route to twig and do:
{% for info in data %}
{{ info }}
{% endfor %}
It doesn't show anything.
My point point is to print only the [name], so I also tried:
{% for info in data %}
{{ info.name }}
{% endfor %}
And it's not working.

Symfony2 how to render all rows of form in twig

I built a form in symfony with this code:
foreach ( $options as $field => $title ) {
$form->add( $field, 'text', array('label' => $title, 'mapped' => false ) );
}
And I can't find a way to render all the rows of this form in twig.
Is this possible?
Ok. I've found how to do this.
In Twig:
{% for child in form.children|keys %}
{{ form_row(attribute(form.children,child)) }}
{% endfor %}
Are you looking for something like this : ?
{{ form(form) }}
or
{{ form_widget(form) }}
http://symfony.com/doc/current/cookbook/form/form_customization.html

Symfony2 - how to print joined tables output

I have two joined tables. With print_r I am getting something like this
Array
(
[0] => GameShelf\UsersBundle\Entity\Ownership Object
(
[id:GameShelf\UsersBundle\Entity\Ownership:private] => 1
[type:GameShelf\UsersBundle\Entity\Ownership:private] => 1
[time:GameShelf\UsersBundle\Entity\Ownership:private] => 2010-02-05 11:00:00
[game:GameShelf\UsersBundle\Entity\Ownership:private] => Doctrine\ORM\PersistentCollection Object
(
[snapshot:Doctrine\ORM\PersistentCollection:private] => Array
(
[0] => GameShelf\GamesBundle\Entity\Game Object
(
[id:GameShelf\GamesBundle\Entity\Game:private] => 1
[parent_id:GameShelf\GamesBundle\Entity\Game:private] => 0
[name:GameShelf\GamesBundle\Entity\Game:private] => Somebody
[slug:GameShelf\GamesBundle\Entity\Game:private] => somebody
[reldate:GameShelf\GamesBundle\Entity\Game:private] => 2010-10-10
[genres:GameShelf\GamesBundle\Entity\Game:private] => 1,2
[platforms:GameShelf\GamesBundle\Entity\Game:private] => 1,2
[developers:GameShelf\GamesBundle\Entity\Game:private] => 1,2
[description:GameShelf\GamesBundle\Entity\Game:private] => Lipsum
[desc_src:GameShelf\GamesBundle\Entity\Game:private] => http://onet.pl
[rate:GameShelf\GamesBundle\Entity\Game:private] => 0
[ownership:GameShelf\GamesBundle\Entity\Game:private] => GameShelf\UsersBundle\Entity\Ownership Object
*RECURSION*
)
)
What I want, is to print name:GameShelf\GamesBundle\Entity\Game:private] => Somebody, but I don't know how. I use Twig, my current template is:
{% for game in games %}
{{ game.id }}
{% endfor %}
But it outputs only id from Ownership table.
My controller:
public function getOwnedAction($type = 1, $user = 1) {
$games = $this->getDoctrine()
->getRepository('GameShelfUsersBundle:Ownership')
->getOwned();
echo '<pre>';
//print_r($games);
echo '</pre>';
return $this->render('GameShelfUsersBundle:Default:index.html.twig',
array(
'games' => $games->getGame()
));
}
Repo:
public function getOwned($type = 1, $user = 1) {
$query = $this->getEntityManager()
->createQuery('
SELECT o, g FROM GameShelfUsersBundle:Ownership o
JOIN o.game g
WHERE o.type = :type
')
->setParameter('type',$type);
try {
return $query->getResult();
} catch (\Doctrine\ORM\NoResultException $e) {
return null;
}
}
It works only when I set getSingleResult instead of getResult.
In Twig you use the same methods to access Entity information.
[edit] After looking at the recursion, you might need to do it this way:
{% for owners in games %}
{% for game in owners.getGame() %}
{{ game.getId() }}
{{ game.getName() }}
{{ game.getParentId() }}
{# etc... #}
{% endfor %}
{% endfor %}

Symfony2: background color of date widget

For a template that includes a date field widget, non-date input fields will have their background colors changed per CSS. The same does not occur on the date widget. How should the background color of the date widget be effected? (Adding an attr array in the form class has no effect.)
A screenshot of the (small but real) difference:
Code samples:
Template:
<td>{{ form_widget(form.fname, {'attr': {'class':'smallform'}}) }}
<td>{{ form_widget(form.sname, {'attr': {'class':'smallform'}}) }}
<td>{{ form_widget(form.dateAdded, {'attr': {'class':'smallform'} }) }}
Form class:
->add('fname', null, array('required' => false))
->add('sname', null, array('required' => false))
->add('dateAdded', 'date', array(
'widget' => 'choice',
'format' => 'MM/dd/yyyy',
'pattern' => '{{ year }}-{{ month }}-{{ day }}',
'years' => range(Date('Y'), Date('Y') - 5),
'required' => false,
'data' => date_create(),
))
CSS:
.smallform {
background-color: #f5f5f5;
font-size: 9pt;
color: #000066;
border: 1px solid #CCCC99;
}
A less-than-subtle solution: modify the date widget in my application's customized copy of fields.html.twig. The more precise solution would be to define a specific widget for this, or figure out how to retain the class attribute all the way into the date widget:
{% block date_widget %}
{% spaceless %}
{% if widget == 'single_text' %}
{{ block('form_widget_simple') }}
{% else %}
<div {{ block('widget_container_attributes') }}>
{{ date_pattern|replace({
'{{ year }}': form_widget(form.year, {'attr': {'class':'smallform'}}),
'{{ month }}': form_widget(form.month, {'attr': {'class':'smallform'}}),
'{{ day }}': form_widget(form.day, {'attr': {'class':'smallform'}}),
})|raw }}
</div>
{% endif %}
{% endspaceless %}
{% endblock date_widget %}
Try:
->add('fname', null, array(
'required' => false,
'attr' => array('class' => 'smallform')
))
->add('sname', null, array(
'required' => false,
'attr' => array('class' => 'smallform')
))
->add('dateAdded', 'date', array(
'attr' => array('class' => 'smallform'), // ADDED
'widget' => 'choice',
'format' => 'MM/dd/yyyy',
'pattern' => '{{ year }}-{{ month }}-{{ day }}',
'years' => range(Date('Y'), Date('Y') - 5),
'required' => false,
'data' => date_create(),
))
also, view-source to make sure the classes are actually set in the html tags, it could be a problem with your CSS.
There is a problem with these lines:
<td>{{ form_widget(form.fname, {'attr': {'class':'smallform'}}) }}</td>
I dont think you can set a class on the entire widget, only for individual rows.
you can try this if you need to set the class via twig.
<form action="" method="">
{{ form_errors(form) }}
{{ form_row(form.fname, { 'attr': {'class': 'smallform' } }) }}
{{ form_row(form.sname, { 'attr': { 'class': 'smallform' } }) }}
<div class="smallform">
{{ form_row(form.dateAdded) }}
</div>
{{ form_rest(form) }}
<input type="submit" name="submit" value="Submit" />
</form>

Resources