How to get the number of result? - Pagerfanta and Twig (in Symfony) - symfony

In my Demo application, use Pagerfanta to read only a few rows from Database.
public function findAllProductsByCategory($category, int $page = 1): Pagerfanta
{
// DQL = Always select full classes from classes
$query = $this->getEntityManager()
->createQuery('
SELECT p
FROM App\Entity\Product p
WHERE p.category = :category
')
->setParameter('category', $category);
return $this->createPaginator($query, $page);
}
Later in Twig, I loop the preselected results. Everything is fine ...
{% if products.haveToPaginate %}
<div class="navigation text-center">
{{ pagerfanta(products, 'default', {routeName: 'category_show_paginated', 'routeParams' : { 'id': category.id}}) }}
</div>
{% endif %}
<table border="1" cellpadding="5">
<tr>
<th>#</th>
<th>Name</th>
<th>Products</th>
<th>Description</th>
</tr>
{% for product in products %}
<tr>
<td>{{ loop.index }}</td>
<td>{{ product.name }}</td>
<td>{{ product.description }}</td>
</tr>
{% endfor %}
</table>
but on each page, "loop.index" is the same 1,2,3,4 ...
I would like to show the number of results 41,42,43 ... with pagerfanta ;)
Is there a special function?
Thank you

Haven't worked with Pagerfanta for a while, but what you want should be doable with something like this:
{{ pagerfanta.currentPageOffsetStart() + loop.index }}
Example test case: https://hotexamples.com/examples/pagerfanta/Pagerfanta/getCurrentPageOffsetStart/php-pagerfanta-getcurrentpageoffsetstart-method-examples.html

Related

Field's Name Table [duplicate]

This question already has an answer here:
Getting column names in a doctrine2 entity
(1 answer)
Closed 5 years ago.
I was trying to display the field name from a database to be used in the table header to be displayed in the twig for admin section propose!
I have my database like this one
id | Gram | Height | Kilos |
1 | 27.1 | 126 cm | 29 kg |
and I want to get the field name "Gram, Height etc" and make it as table header, I was going to make a translation for this like English to Japanese and so on, "the problem is how do I get the data field name and display it like a text any advice for this on", Thank you in advance!
Code for controller
/**
* #Route("/ingredients/header-translation", name = "z_recipe_header_translation")
* #Template("NutritionMainBundle:Admin\create\recipe\ingredients:translate-headers.html.twig")
*/
public function headerTranslationAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$nutrients = $em->getRepository("NutritionAdminBundle:NutritionValue")->findAll();
return array(
'header' => $nutrients
);
}
Twig code
<table class="table" style="width:100%;">
<thead>
<tr>
<th>header</th>
{% for ii in 1..9 %}
<th>language {{ii}}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for i in 1..10 %}
<tr>
<td>header label {{i}}</td>
{% for ii in 1..9 %}
<td><input type="text"/></td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
Oh this is a duplicate question so sorry about that, i'll just make it as an example, The code below will be my final answer, Thank for the help!
controller code:
/**
* #Route("/ingredients/header-translation", name = "z_recipe_header_translation")
* #Template("NutritionMainBundle:Admin\create\recipe\ingredients:translate-headers.html.twig")
*/
public function headerTranslationAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$NutritionValueField = $em->getClassMetadata('NutritionAdminBundle:NutritionValue')->getFieldNames();
$languages = $em->getRepository("NutritionLanguageBundle:Language")->findAll();
$form = $this->createForm(new NutritionValueType());
$form->handleRequest($request);
return array(
'header' => $NutritionValueField,
'languages' => $languages,
'form' => $form->createView()
);
}
For my Twigs display
<table class="table" style="width:100%;">
<thead>
<tr>
<th>header</th>
{% for languages in languages %}
<th>{{languages.langLabel}}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for header in header %}
<tr>
{% if header == 'NDB_NO'%}
{#do nothing#}
{% else %}
<td>{{ header|replace({'_':' '}) }}</td>
{% for languages in languages %}
<td><input id="{{header}}_{{ languages.id }}" type="text" value="{{header|replace({'_':' '})}}"/> </td>
{% endfor %}
{% endif %}
</tr>
{% endfor %}
</t
body>
You can use the database information schema:
SELECT `COLUMN_NAME`
FROM `INFORMATION_SCHEMA`.`COLUMNS`
WHERE `TABLE_SCHEMA` = 'databasename'
AND `TABLE_NAME` = 'tablename';
use sql sentence:desc tablename;

how to separate a row result to grups in TWIG

Form query i have several rows record
Controller:
public function statusTaskAction()
{
$em = $this->getDoctrine()->getManager();
$statusAll = $em->getRepository( 'MyBundle:StatusTask' )
->allStatusQuery();
return [ 'rows' => $statusAll ];
}
statusTask.html.twig
<table class="table ">
<tbody>
{% for entry in row %}
<tr>
<td>{{ entry.endDate is null ? '' : entry.endDate }}</td>
<td>{{ entry.groupID }}</td>
<td>{{ entry.name }}</td>
<td>{{ entry.info }}</td>
</tr>
{% else %}
<tr>
<td colspan="4">No rows</td>
</tr>
{% endfor %}
</tbody>
</table>
groupID displayed status:
g - "Green"
r - "Red"
f - "Future to plan"
p - "Planed"
I'll try to separate result by groupID and for this result add label, decription to each displayed grupID in TWIG and separate it in TWIG.
How can I do it in TWIG?
Since row is an Entity, you don't call the column name, but instead the Entity getters like so:
<table class="table ">
<tbody>
{% for entry in rows %}
<tr>
<td>{{ entry.getDate is null ? '' : entry.getDate }}</td>
<td>{{ entry.getGroupID }}</td>
<td>{{ entry.getName }}</td>
<td>{{ entry.getInfo }}</td>
</tr>
{% else %}
<tr>
<td colspan="4">No rows</td>
</tr>
{% endfor %}
</tbody>
</table>
I presume that would be the naming in your Entity class for the Entity StatuTask. Also, I think you need to use rows as specified in your controller.

Symfony2 how to filter query

UPDATE
Think I may have gone off course here, but I still get the same result with the whole page being displayed in the table.
So I am doing this for both the view and status pages. View is the default page which shows all active alerts. Status is the page that will display the filtered alerts. So each of these pages has a controller
public function viewAction()
{
$repository = $this
->getDoctrine()
->getManager()
->getRepository('NickAlertBundle:Alert');
$alerts = $repository->getAllActiveAlerts();
return $this->render('NickAlertBundle:Page:view.html.twig', array(
'alerts' => $alerts,
));
}
public function getActivatedAction(Request $request)
{
$alertStatus = $request->request->get('status', 'active');
$alerts = $this->getDoctrine()->getRepository('NickAlertBundle:Alert')->getAlertByStatus($alertStatus);
return $this->render('NickAlertBundle:Page:status.html.twig', array("alerts"=>$alerts));
}
Each of these pages then has a route
NickAlertBundle_view:
pattern: /view-alerts
defaults: { _controller: NickAlertBundle:Alert:view }
requirements:
_method: GET
NickAlertBundle_status:
pattern: /view-alerts
defaults: { _controller: NickAlertBundle:Alert:getActivated }
requirements:
_method: POST
NickAlertBundle_view calls the view action and renders the page with all active alerts. NickAlertBundle_status calls the getActivated action.
Both of these views are the same, their content is as follows
{% extends 'NickAlertBundle::layout.html.twig' %}
{% block main %}
<div class="col-md-12">
<section class="panel panel-default">
<header class="panel-heading">
<h3 class="panel-title">View Alerts</h3>
<select name="alerts" id="alerts" data-url="{{ path('NickAlertBundle_status') }}">
<option value="active">Active</option>
<option value="inactive">Inactive</option>
</select>
</header>
<div class="panel-body">
<div class="row" id="alert-container">
<table width="100%" cellpadding="0" cellspacing="0" border="0" id="datatable" class="table">
<thead>
<tr>
<th>Id</th>
<th>Search Command</th>
<th>Flight Number</th>
<th>Booking Class</th>
<th>Alert Pseudo</th>
<th>Alert Status</th>
</tr>
</thead>
<tbody>
{% for alert in alerts %}
<tr>
<td>{{ alert[0].id }}</td>
<td>{{ alert[0].searchCommand }}</td>
<td>{{ alert.flight_number }}</td>
<td>{{ alert.classes }}</td>
<td>{{ alert.pseudos }}</td>
<td>{{ alert[0].alertStatus }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</section>
</div>
{% endblock %}
So the data url should call the status route. Both of the views have this because they should always be able to change the select on either page.
And then the javascript is pretty much the same as you have shown me.
UPDATED
The problem is basicaly that you are embedding the html response from viewAction when you actually have to put the code for the alerts, for example:
public function getActivatedAction(Request $request)
{
$alertStatus = $request->request->get('status', 'active');
$alerts = $this->getDoctrine()->getRepository('NickAlertBundle:Alert')->findAllByStatus($alertStatus);
return $this->render('NickAlertBundle:Alerts:show.html.twig', array("alerts"=>$alerts));
}
on the NickAlertBundle:Alerts:show.html.twig
{# NickAlertBundle:Alerts:show.html.twig #}
{% for alert in alerts %}
<tr>
<td>{{ alert[0].id }}</td>
<td>{{ alert[0].searchCommand }}</td>
<td>{{ alert.flight_number }}</td>
<td>{{ alert.classes }}</td>
<td>{{ alert.pseudos }}</td>
<td>{{ alert[0].alertStatus }}</td>
</tr>
{% endfor %}
So then in your NickAlertBundle:Page:view.html.twig :
$('#alerts').change(function(){
$.ajax({
type: "POST",
url: $('#alerts').attr('data-url'), # getActivatedAction route
data:{ status: $(this).val() },
success: function(data){
$('#alert-container table tbody').html(data);
}
});
});
You can add a methond in your Enity Repository File:
# src/Package/AppBundle/Entity/AlertRepository.php
<?php
namespace Package\AppBundle\Entity;
use Doctrine\ORM\EntityRepository;
/**
* AlertRepository
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class AlertRepository extends EntityRepository
{
public function findAllByStatus($status = "active")
{
$qb = $this->createQueryBuilder('a');
$query = $qb
->where(
$qb->expr()->eq('a.alertStatus', $status)
)
->orderBy('a.id', 'DESC')
->getQuery();
return $query->getResult();
}
}
and then in your controller, you can pass a json with the data or html:
<?php
...
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
...
public function getActivatedAction(Request $request)
{
$alertStatus = $request->request->get('status', 'active');
$alerts = $this->getDoctrine()->getRepository('AppBundle:Alert')->findAllByStatus($alertStatus);
// With JSON
$json = alerts->toJson() // your own method
$response = new JsonResponse();
$response->setData($json);
// With HTML
return $this->render('AppBundle:Alerts:show.html.twig', array("alerts"=>$alerts));
}
Now in yor html file you can use ajax to request the alerts:
<select name="alerts" id="alerts">
<option value="active">Actives</option>
<option value="inactive">Inactive</option>
</select>
<div id="alertsList"></div>
<script>
$('#alerts').change(function(){
$.ajax({
type: "POST",
url: "{{ path('alerts_getActivated') }}",
data:{ status: $(this).val() },
success: function(data){
$('#alertsList').html(data); //Using the html response. With json you have to create the style and html here
}
});
});
</script>
If I didn't miss anything it should work.
If I get you wrong, please let me know, and I hope this will help you.
The $('#alert-container table tbody').html(data); line will set the contento of your tbody table from the response that the server return, so you have to have two different files
{% NickAlertBundle:Page:view.html.twig %}
{% extends 'NickAlertBundle::layout.html.twig' %}
{% block main %}
<div class="col-md-12">
<section class="panel panel-default">
<header class="panel-heading">
<h3 class="panel-title">View Alerts</h3>
<select name="alerts" id="alerts" data-url="{{ path('NickAlertBundle_status') }}">
<option value="active">Active</option>
<option value="inactive">Inactive</option>
</select>
</header>
<div class="panel-body">
<div class="row" id="alert-container">
<table width="100%" cellpadding="0" cellspacing="0" border="0" id="datatable" class="table">
<thead>
<tr>
<th>Id</th>
<th>Search Command</th>
<th>Flight Number</th>
<th>Booking Class</th>
<th>Alert Pseudo</th>
<th>Alert Status</th>
</tr>
</thead>
<tbody>
{% for alert in alerts %}
<tr>
<td>{{ alert[0].id }}</td>
<td>{{ alert[0].searchCommand }}</td>
<td>{{ alert.flight_number }}</td>
<td>{{ alert.classes }}</td>
<td>{{ alert.pseudos }}</td>
<td>{{ alert[0].alertStatus }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</section>
</div>
{% endblock %}
and
{# NickAlertBundle:Page:status.html.twig #}
{% for alert in alerts %}
<tr>
<td>{{ alert[0].id }}</td>
<td>{{ alert[0].searchCommand }}</td>
<td>{{ alert.flight_number }}</td>
<td>{{ alert.classes }}</td>
<td>{{ alert.pseudos }}</td>
<td>{{ alert[0].alertStatus }}</td>
</tr>
{% endfor %}
To solve the url problem you should put:
NickAlertBundle_view:
pattern: /view-alerts
defaults: { _controller: NickAlertBundle:Alert:view }
methods: [GET]
NickAlertBundle_status:
pattern: /view-alerts
defaults: { _controller: NickAlertBundle:Alert:getActivated }
methods: [POST]

An attribute is not displayed in twig

I have an attribute immobilier.ref that is not displayed with twig
this is the code
{% for immobilier in listImmobilier %}
<tr>
<td>{{ immobilier.id }}</td>
<td>{{ immobilier.ref }}</td>
<td>{{ immobilier.titre }}</td>
<td><span class="glyphicon glyphicon-eye-open" style="display:block; text-align:center"></span></td>
<td>Edit</td>
<td>Delete</td>
</tr>
{% endfor %}
this is a photo of the table
It(s fine now, it was because I have a function named ref in the entity
/**
* #ORM\PostPersist()
*/
public function ref()
{
$id = $this->getId();
$operation = $this->getOperation()->getRef();
$this->setRef($id.$operation);
}
I have changed her name and it work fine now.

Editing Twig templates in CKeditor

I'm trying to allow admin users to edit email templates. These templates are stored in the DB as Twig ones. So the variables in them are set as {{ purchase.number }} and there are loops like
{% if cart['shipping'] %}
{% for line in cart['shipping'] %}
<tr>
<td colspan="7">Shipping ({{ line['text'] }})</td>
<td>US${{ line['money'] }}</td>
</tr>
{% endfor %}
{% endif %}
Below is one of the templates where I can reproduce this issue:
<html>
<body>
<h3>Order #{{ purchase.number }} was cancelled</h3>
<p>Order content:</p>
<table>
<tr>
<th>Line</th>
<th>Item #</th>
<th>Product Name</th>
<th>Shipping</th>
<th>UOM</th>
<th>Unit Price</th>
<th>Quantity</th>
<th>Subtotal</th>
</tr>
{% for line in cart['cart'] %}
<tr>
<td>{{ line['LineNo'] }}</td>
<td>{{ line['ItemNo'] }}</td>
<td>{{ line['ProductName'] }}</td>
<td>{{ line['Shipping'] }}</td>
<td>{{ line['UOM'] }}</td>
<td>US${{ line['UnitPrice'] }}</td>
<td>{{ line['Quantity'] }}</td>
<td>US${{ line['Subtotal'] }}</td>
</tr>
{% endfor %}
{% if cart['shipping'] %}
{% for line in cart['shipping'] %}
<tr>
<td colspan="7">Shipping ({{ line['text'] }})</td>
<td>US${{ line['money'] }}</td>
</tr>
{% endfor %}
{% endif %}
<tr>
<td colspan="7"><b>Order Item Total:</b></td>
<td>US${{ cart['total'] }}</td>
</tr>
</table>
</body>
</html>
When I just open a page with CKEditor textarea with this template in it, I do no changes to the template and just click on "Source" button and here is how the above mentioned template looks after the click:
<h3>Order #{{ purchase.number }} was cancelled</h3>
<p>Order content:</p>
{% for line in cart['cart'] %} {% endfor %} {% if cart['shipping'] %} {% for line in cart['shipping'] %} {% endfor %} {% endif %}
<table>
<tbody>
<tr>
<th>Line</th>
<th>Item #</th>
<th>Product Name</th>
<th>Shipping</th>
<th>UOM</th>
<th>Unit Price</th>
<th>Quantity</th>
<th>Subtotal</th>
</tr>
<tr>
<td>{{ line['LineNo'] }}</td>
<td>{{ line['ItemNo'] }}</td>
<td>{{ line['ProductName'] }}</td>
<td>{{ line['Shipping'] }}</td>
<td>{{ line['UOM'] }}</td>
<td>US${{ line['UnitPrice'] }}</td>
<td>{{ line['Quantity'] }}</td>
<td>US${{ line['Subtotal'] }}</td>
</tr>
<tr>
<td colspan="7">Shipping ({{ line['text'] }})</td>
<td>US${{ line['money'] }}</td>
</tr>
<tr>
<td colspan="7"><b>Order Item Total:</b></td>
<td>US${{ cart['total'] }}</td>
</tr>
</tbody>
</table>
Notice that not only single quote changes to html code, but the main thing is that loops are moved, so it used to be:
{% if cart['shipping'] %}
{% for line in cart['shipping'] %}
<tr>
but becomes:
{% for line in cart['cart'] %} {% endfor %} {% if cart['shipping'] %} {% for line in cart['shipping'] %} {% endfor %} {% endif %}
Why does CKEditor change the source if these entities are NOT html and I don't do any changes, I don't even focus on the field.
I tried using these CKEditor config options:
CKEDITOR.config.enterMode = CKEDITOR.ENTER_BR;
CKEDITOR.config.entities = false;
CKEDITOR.config.forcePasteAsPlainText = false; // default so content won't be manipulated on load
CKEDITOR.config.basicEntities = true;
CKEDITOR.config.entities = true;
CKEDITOR.config.entities_latin = false;
CKEDITOR.config.entities_greek = false;
CKEDITOR.config.entities_processNumerical = false;
CKEDITOR.config.fillEmptyBlocks = function (element) {
return true; // DON'T DO ANYTHING!!!!!
};
But I still experience this. Can anyone advise on the config option or any other workaround, except for not using WYSIWYG. I tried to convince users to edit html/twig, but the just want WYSIWYG. Thanks
One possible workaround for me, was to add the Twig blocks to config.protectedSource:
CKEDITOR.config.protectedSource.push(/\{%\s.+\s%\}/g);
They will be ignored in the WYSIWYG editor, but will still be visible in the source code view.
Additionally you can install the plugin Show protected and there's still a visible hint.
working code is :
CKEDITOR.config.protectedSource.push(/{{[\s\S]?}}/g);
CKEDITOR.config.protectedSource.push(/{\%[\s\S]?%}/g);
CKEDITOR.config.protectedSource.push(/{#[\s\S]*?#}/g);
because we need allow {{ and {% tags for twig
CKEDITOR.config.protectedSource = [
/\{\{[\s\S]*?\}\}/g,
/\{\%[\s\S]*?%\}/g,
/\{\#[\s\S]*?#\}/g,
];
This is why I love Stack Overflow - no matter what you want to ask, someone's probably already asked it! In this case, the answers were close, but for me, adding them as protected source was no good - I wanted to create the twig templates in the string as we use them for Email Templates within our CRM. So, what I did was leave CKEditor to do its thing and then handle it before the template was saved (in our case into the DB, but it could as well be to file).
The function I added is pasted below - feel free to use & abuse as you wish.
This is from our custom Symfony controller onBeforePersist a hook that's called before the entity is persisted... Hopefully its all self explanatory from the code.
Note, the Regex may be a bit dodgy, but appears to work, I'm no Regex expert, so please feel free to suggest a more concise expression.
/**
* Before we persist the data, we need to clean up any twig tags in there as the editor encodes html entities...
*
* #param Request $request
* #param $form
* #param EmailTemplates $entity
*/
public function onBeforePersist(Request $request, $form, $entity)
{
$template = $entity->getView();
$re = '/\{(\{|%)([^{}]|(?R))*(\}|%)\}/';
preg_match_all($re, $template, $matches, PREG_SET_ORDER, 0);
// We only want the first element of each match - I don't like closures as a rule on readability grounds, but this is small enough to be ok.
array_walk($matches,function(&$value) {
if (array($value)) {
$value = $value[0];
}
});
// Now do a replace on them
foreach ($matches as $match) {
$decoded = html_entity_decode($match,ENT_QUOTES);
if ($match != $decoded) {
// Only replace if we have actually changed the string
$template = str_replace($match, $decoded, $template);
}
}
// Update the View...
$entity->setView($template);
}
Similar question CKEditor is escaping html elements
Quick question, the above is a list of config options you have tried one at a time? Having both like this
CKEDITOR.config.entities = false;
CKEDITOR.config.entities = true;
sets entities to true, which is not what you want as it forces html entities in output.
By the way, the other answers are OK but if you have more than one Twig block in the same sentence, are not.
So I definetly recommend to use this Regex instead that works with multiple Twig blocks too:
CKEDITOR.config.protectedSource.push(/\{\{[\s\S]*?\}\}/g);
CKEDITOR.config.protectedSource.push(/\{\%[\s\S]*?%\}/g);

Resources