I use form theme like it is explain in the documentation https://symfony.com/doc/current/form/form_themes.html with :
{% form_theme form.methodes 'form_table_layout.html.twig' %}
In order to have table and not "div".
My problem is :
For a normal form with "div", i use this code to modify and adapt a collection :
{% block _Examplebundle_methodes_entry_widget %}
Documentation "How to Customize a Collection Prototype" : https://symfony.com/doc/3.4/form/form_customization.html
It work for theme with "div" but with the theme 'form_table_layout.html.twig' it didn't work. I don't know how to custom block with the table theme.
here is a part of my code :
{% form_theme form.methodes 'form_table_layout.html.twig' %}
//////// Block to custom the collection/////////////
{% block _Examplebundle_methodes_entry_widget %}
<tr>
<td>
{{ form_widget(form.methodeEssai) }}
{{ form_errors(form.methodeEssai)}}
</td>
<td>
{{ form_widget(form.ind, {'attr' : {'placeholder' : 'Index'}}) }}
{{ form_errors(form.ind)}}
</td>
<td>a</td>
<td>z</td>
<td>e</td>
<td>r</td>
<td>t</td>
</tr>
{% endblock %}
//////// End Block custom /////////////
{% block body %}
{{ form_start(form) }}
....
<table id="eagle_laboratorybundle_pvp_methodes" class="row"
data-prototype="
{{form_widget(form.methodes.vars.prototype)|e('html_attr') }}"
data-index="{{ form.methodes|length }}">
<thead>
<tr>
<th>x</th>
<th>y</th>
<th>z</th>
<th>a</th>
<th>r</th>
<th>e</th>
<th>t</th>
</tr>
</thead>
<tbody>
{{ form_widget(form.methodes) }}
{{ form_errors(form.methodes) }}
</tbody>
</table>
/// Some JS etc...///
So with the block _entry_widget i expected to custom rows of my table like it permit to custom div when i'm using original layout theme.
Someone know how to custom form rendering with table theme ?
Related
I am working on a webapplication but ive ran into a hiccup, I have gathered data from my database and displayed the records into a datatable, my problem is that I can not just have one table the client wants me to divide the table into multiple based on what interger is in a column(omloopNummer).
The best ive gotten so far is with the following code it wil split the table up into lets say 4 tables if the interger in the database wil go 1,2,3,4 but it wil only show 1 record in each table while it should be more.
If there is any other simple solution to this instead of using twig I would be happy to try it.
<div id="index" class="table-responsive">
{% set i = 1 %}
{% for duel in duels %}
{% if duel.omloopNummer == i %}
{% set i = i + 1 %}
<table id="" class="table display-" style="width: 90%; margin-top: 30px">
<thead>
<tr>
<th>Omloop</th>
<th>Team 1</th>
<th>vs</th>
<th>Team 2</th>
<th>Acties</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{ duel.omloopNummer }}</td>
<td>{{ duel.team1 }}</td>
<td>vs</td>
<td>{{ duel.team2 }}</td>
<td>{{ include('duel/_delete_form.html.twig') }}</td>
</tr>
</tbody>
</table>
{% endif %}
{% endfor %}
You could use PHP to group Duels by omloopNummer in the controller before passing to twig.
$duels = $duelRepository->findAll();
$sorted = [];
foreach($duels as $duel){
$sorted[$duel->getOmloopNummer()][] = $duel;
}
return $this->render('template.html.twig', [
'duel_groups' => $sorted,
]);
Then in twig, loop through the sorted array building a table for each non-empty group and inside each tbody loop through the group.
{% for group in duel_groups %}
...
{% if group is not empty %}
<table>
...
<tbody>
{% for duel in group %}
<tr>...</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
...
{% endfor %}
First of all, sorry by advance for my english which is not perfect.
I have a problem for days by reporting 3 doctrine entity in a Twig Table template.
It's a table for manage stocks at work. I have different materials which have each different sizes. Each couple (1 material + 1 size) got a number as amound to order.
So I first created 3 entity :
Stock (represent materials) ManyToMany Dimension (represent sizes)
Besoin (needs) got a ManyToOne relation with both Stock and Dimension.
Then, I created few Stocks, Dimensions and needs with my forms to get a test database.
The goal is now to create a double entry table with the dimensions list, Stocks list and in each cell the needed number.
It's in this step that I have bugs.
For now I can give you my code and hope someone can help me by giving me a tips.
Controller :
public function commandeAction()
{
$em = $this->getDoctrine()->getManager();
$materiauxlist = $em->getRepository('TGComptaBundle:Stock')->findAll();
$dimensionslist = $em->getRepository('TGComptaBundle:Dimension')->findAll();
$tab1 = array_merge($materiauxlist, $dimensionslist);
$besoins = array();
foreach ($materiauxlist as $stock) {
foreach ($dimensionslist as $dimension) {
$besoin = $em->getRepository('TGComptaBundle:Besoin')->findBesoins($stock, $dimension);
}
}
return $this->render('TGProdBundle:Projet:stocks.html.twig', array(
'materiauxlist' => $materiauxlist,
'dimensionslist' => $dimensionslist,
'besoin' => $besoin));
}
View :
{% block tgprod_body %}
<div class="well">
<table class="table table-hover table-bordered">
<thead>
<tr>
<th>#</th>
{% for dimension in dimensionslist %}
<th>{{ dimension.name }}</th>
{% endfor %}
</tr>
</thead>
{% for stock in materiauxlist %}
<tr>
<td>{{ stock.name }}</td>
{% for dimension in dimensionslist %}
{% if besoin %}
<td>{{ besoin.nombre }}</td>
{% else %}
<td>X</td>
{% endif %}
{% endfor %}
</tr>
{% endfor %}
</table>
</div>
{% endblock %}
Repository :
public function findBesoins($stock, $dimension)
{
$qb = $this->createQueryBuilder('b');
$qb
->where('b.stock = :stock')
->andwhere('b.dimension = :dimension')
->setParameter('stock', $stock)
->setParameter('dimension', $dimension);
$qb
->getQuery()
->getResult();
}
My actual problem is : I have X in all cells
Before I asked your help I tried :
foreach ($materiauxlist as $stock) {
foreach ($dimensionslist as $dimension) {
$besoin = $em->getRepository('TGComptaBundle:Besoin')->findBesoins($stock, $dimension);
$besoins[] = $besoin;
}
}
and :
<table class="table table-hover table-bordered">
<thead>
<tr>
<th>#</th>
{% for dimension in dimensionslist %}
<th>{{ dimension.name }}</th>
{% endfor %}
</tr>
</thead>
{% for stock in materiauxlist %}
<tr>
<td>{{ stock.name }}</td>
{% for dimension in dimensionslist %}
{% for besoin in besoins %}
{% if besoin %}
<td>{{ besoin.nombre }}</td>
{% else %}
<td>X</td>
{% endif %}
{% endfor %}
{% endfor %}
</tr>
{% endfor %}
</table>
But it was wrong result (I had like 10000 X on each row)
I thinked it's the "{% for besoin in besoins %}" which is wrong, it should be something like "{% for besoin.dimension.stock in besoins %}" but I can't write this in twig.
and I tried something like this to :
$table = array('stock' => $stock, 'dimension' => $dimension, 'besoin' => $besoin);
$besoins[] = $table;
when I do a { dump() } in Twig I have array with number of stock x number of dimension and all with a null besoin so it seems strange ... and finally I didn't find how to render this array in my table so I let this solution away :/
My code is aimed at getting items from database. Those item may have either debit values or credit values. In template I present all of the values but would like also to provide information about sum of debit and account values connected with the account ($account_id)
What would be your best practice how to do this?
Should I simply run another two SQL queries:
first to SUM(value) where accountdebet = '.$account_id
secound to SUM(value) where accountcredit = '.$account_id?
Will it be the right approach?
Controller:
// Get items for acccount and paginate
$rp_items = $this->getDoctrine()->getManager()->getRepository('AppBundle:Items');
$query = $rp_items->createQueryBuilder('p')
->where('p.accountdebet = '.$account_id)
->orWhere('p.accountcredit = '.$account_id)
->getQuery();
$rp_paginator = $this->get('knp_paginator');
$db_pagination = $rp_paginator->paginate($query,$this->get('request')->query->getInt('page', 1),10);
// Render TPL
return $this->render('AppBundle:Accounts:items.html.twig', array('pagination' => $db_pagination, 'account' => $account));
In twig:
{% extends '::base.html.twig' %}
{% block body %}
<B>Item list for account {{ account.id }} </B><BR>
Account id: {{ account.id }}<BR>
Account marker: {{ account.marker }}<BR>
Account name: {{ account.name }}<BR>
<table class="table table-striped">
<tr>
{# sorting of properties based on query components #}
<th>{{ knp_pagination_sortable(pagination, 'Id', 'a.id') }}</th>
<th{% if pagination.isSorted('a.itemdate') %} class="sorted"{% endif %}>{{ knp_pagination_sortable(pagination, 'Date', 'a.itemdate') }}</th>
<th>Document</th>
<th>{{ knp_pagination_sortable(pagination, 'Marker', 'a.marker') }}</th>
<th>Debit</th>
<th>Credit</th>
</tr>
{# table body #}
{% for item in pagination %}
<tr>
<td>{{ item.id }}</td>
<TD>{{ item.itemdate|date('Y-m-d')}}</TD>
<td>{{ item.documentid.marker }}</td>
<td>{{ item.marker }}</td>
<TD>{% if item.accountdebet.id == account.id %}
{{ item.itemvalue}}
{% endif %}
</TD>
<TD>{% if item.accountcredit.id == account.id %}
{{ item.itemvalue}}
{% endif %}</TD>
</tr>
{% endfor %}
</table>
{# display navigation #}
<div class="pagination">
{{ knp_pagination_render(pagination) }}
</div>
{% endblock %}
You can solve it in many ways but i like to make an parent entity eg ItemsCollection that holds an arrayCollection of Items. Then i give the new entity some extra functionality e.g.
public function countItemValues()
{
$total = 0;
foreach($this->items as $item)
{
$total += $item->getValue();
}
return $total;
}
I'm using Twig as template framework for my PHP web application.
I would like to know if there is a fast way to get many element in a foreach block.
This is my data:
users=>[
["name"=>"User1"],
["name"=>"User2"],
["name"=>"User3"],
["name"=>"User4"],
["name"=>"User5"],
["name"=>"User6"]
]
This would be a standard loop (each item):
<ul>
{% for user in users %}
<li>{{ user.name }}</li>
{% endfor %}
</ul>
But this is what I need in block of n elements (in this example n=3)
<ul>
<li>User1</li>
<li>User2</li>
<li>User3</li>
</ul>
<ul>
<li>User4</li>
<li>User5</li>
<li>User6</li>
</ul>
Exists a fast way to do this in Twig or should I prepare the data in a different way with a one more subarray layer?
Looks like you need to use batch filter:
{% set items = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] %}
<table>
{% for row in items|batch(3, 'No item') %}
<tr>
{% for column in row %}
<td>{{ column }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
It will render:
<table>
<tr>
<td>a</td>
<td>b</td>
<td>c</td>
</tr>
<tr>
<td>d</td>
<td>e</td>
<td>f</td>
</tr>
<tr>
<td>g</td>
<td>No item</td>
<td>No item</td>
</tr>
</table>
Source: Twig Documentation
I'm using twig 1.12.2. My code generates some elements from code-behind, when rendering these with the latest version of twig they get html-encoded
{% for item in files_folders %}
<tr class="{{ cycle(['tr_odd', 'tr_even'], loop.index) }}">
<td><img src="../templates/images/sharepoint/{{ item.ContentType }}.gif" border="0" alt=""/></td>
<td>{{ item.Link }}</td>
<td>{{ item.Modified }}</td>
<td>{{ item.FileSize }}</td>
<td>{{ item.FileType }}</td>
</tr>
{% endfor %}
This will output this
<tr class="tr_even">
<td><img src="../templates/images/sharepoint/Document.gif" border="0" alt=""/></td>
<td><a href='?download=/ddd.png'>ddd.png</a></td>
<td>2013-03-04 17:47:38</td>
<td>64.8 KB</td>
<td>png</td>
</tr>
<tr class="tr_odd">
<td><img src="../templates/images/sharepoint/Document.gif" border="0" alt=""/></td>
<td><a href='?download=/asdasd.png'>asdasd.png</a></td>
<td>2013-03-03 20:01:52</td>
<td>66.04 KB</td>
<td>png</td>
</tr>
When I debug and have a look at the data before it's sent to twig it is not escaped. I haven't found any alternative to {{ item.Link }} to render data as-is.
Thanks
You can use the raw filter to make twig render raw html
http://twig.sensiolabs.org/doc/filters/raw.html
{% autoescape %}
{{ var|raw }} {# var won't be escaped #}
{% endautoescape %}
You should be careful with using |raw. Saying that the data is safe, means you are trusting it 100%.
Personally I would suggest using a custom twig filter:
class CustomExtension extends \Twig_Extension
{
public function getFilters()
{
return array(
new \Twig_SimpleFilter('unescape', array($this, 'unescape')),
);
}
public function unescape($value)
{
return html_entity_decode($value);
}
}
Add the following to your services.yml (or alternatively translate into xml).
services:
ha.twig.custom_extension:
class: HA\SiteBundle\Twig\CustomExtension
tags:
- { name: twig.extension }
Or http://twig.sensiolabs.org/doc/filters/raw.html
{% autoescape false %}
{{ your_item }}{# your_item won't be escaped #}
{% endautoescape %}
If you are using Drupal 8 and none of raw or autoscape works, this could happen because of the variable you're trying to print if it's a render array with a template holding a safe output (for example, a hl2br filter).
I that case, you would need to access the value through the render array and filter it, for instance:
{% autoescape false %}
{{ item.content['#context']['value'] }}
{% endautoescape %}