symfony2 multidelte records delete - symfony

i have a file called index which shows list of customer inquiry.
i want to put multiple delete in the that.
the code of my index file list is bellow.
{% block body -%}
<h1>Enquiry list</h1>
<table class="records_list" id="rounded-corner">
<thead>
<tr>
<th>Option</th>
<th>Id</th>
<th>Name</th>
<th>Email</th>
<th>Subject</th>
<th>Body</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for entity in entities %}
<tr>
<td><input type="checkbox" name="multiSelect" id="multiSelect[]" value="{{ entity.id }}"></td>
<td>{{ entity.id }}</td>
<td>{{ entity.name }}</td>
<td>{{ entity.email }}</td>
<td>{{ entity.subject }}</td>
<td>{{ entity.body }}</td>
<td>
<img src="http://test//bundles/blogger/image/view.png" style="width:30px; height:30px">
<img src="http://test//bundles/blogger/image/edit.png" style="width:30px; height:30px" >
</td>
</tr>
{% endfor %}
</tbody>
<tfooter>
</tfooter>
</table>
<ul>
<li>
<a href="{{ path('enquiry_new') }}">
Create a new entry
</a>
</li>
</ul>
{% endblock %}
I have put the checkbox inside it.
and what i want is the array value of the "multiSelect[]" which store all id.
and i am passing this to my controller.
i donot know how to pass this array value as my controller argument. so please help me
i want to pass it here.
<tfooter>
MultiDelete
</tfooter>

You need to use a form for that. Using input fields without a form is always a sloppy way.

I got the answer.
I have created the form and pass the request to the controller deleteAction .
in deleteAction method
i get the request parameters using $request->get('multiSelect'); "multiSelect" the name of the input box.
and using the repositoryclass object i have completed the task.
Thanks for your response.

I think the most secure way to do this is with a link that onclick generates a form and send it by post. For example:
<a href="{{ path('your_delete_action', { 'id': object.id }) }}"
token="{{ token }}"
data-method="POST"
object-id ="{{ object.id }}">
<span class="red"><i class="icon-remove"></i></span>
</a>
And onClick on this links you generate a form and send it to your deleteAction
// Every link with an attribute data-method
$("#container").on("click", "a[data-method]", function(event){
event.preventDefault();
var target = $(event.currentTarget);
var method = target.attr('data-method');
var action = target.attr('href');
var token = target.attr('token');
var objectId = target.attr('object-id');
// Create a form on click
var formulario = $('<form/>', {
style: 'display:none;',
method: method,
action: action
});
formulario.appendTo(target);
formulario.append("<input name='token' value='" + token + "' type='hidden'/>");
formulario.append("<input name='id' value='" + objectId + "' type='hidden'/>");
// Do submit
formulario.submit();
});

Related

Vue: [Vue warn]: Error in render: "TypeError: product.data is not a function"

I am trying to retrieve the data from cloud firestore database.
But I got an error,
[Vue warn]: Error in render: "TypeError: product.data is not a
function"
I want to show the each product name and price in my table.
But I have no idea why this issue comes up.
So I hope somebody can help me out.
If I don't use data() in the vue template, I can see all the data as I expected.
<template>
<h3>Product List</h3>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Price</th>
<th>Modify</th>
</tr>
</thead>
<tbody>
<tr v-for="(product, index) in products" :key="index">
<td>{{ product.data().name }}</td>
<td>{{ product.data().price }}</td>
<td>
<button #click="editProduct(product)" class="btn btn-primary">Edit</button>
<button #click="deleteProduct(product.id)" class="btn btn-danger">Delete</button>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import { fb, db } from '../firebase'
export default {
name: 'Products',
props: {
msg: String
},
data () {
return {
products: [],
product: {//object
name: null,
price: null
}
}
},
methods: {
editProduct(product) {
$('#edit').modal('show')
},
readData() {
db.collection("products").get().then((querySnapshot) => {
querySnapshot.forEach((doc) => {
this.products.push(doc.data());
});
});
},
saveData() {
// Add a new document with a generated id.
db.collection("products").add(this.product)
.then((docRef) => {
console.log("Document written with ID: ", docRef.id);
this.product.name = "",
this.product.price = ""
this.readData()
})
.catch(function(error) {
console.error("Error adding document: ", error);
});
}
},
created() {
this.readData();
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
</style>
I will have to agree with #Mostafa, the naming convention is not very readable. Your error is telling you that you are trying to invoke a function that is not a function or does not exist in your data.
Change:
<td>{{ product.data().name }}</td>
<td>{{ product.data().price }}</td>
To:
<td>{{ product.name }}</td>
<td>{{ product.price }}</td>
This should fix it, as you are iterating over the products list (of which isn't clear), so i advise you should change:
<tr v-for="(product, index) in products" :key="index">
<td>{{ product.name }}</td>
<td>{{ product.price }}</td>
<td>
<button #click="editProduct(product)" class="btn btn-primary">Edit</button>
<button #click="deleteProduct(product.id)" class="btn btn-danger">Delete</button>
To:
<tr v-for="(productItem, index) in products" :key="index">
<td>{{ productItem.name }}</td>
<td>{{ productItem.price }}</td>
<td>
<button #click="editProduct(productItem)" class="btn btn-primary">Edit</button>
<button #click="deleteProduct(productItem.id)" class="btn btn-danger">Delete</button>
Your code is very confusing.
I don't understand why you are calling data method on product and why you have product and products in your data when you just need one.
So i'm assuming Vue is mixing product in your for loop and the product object in your data.
So either change the product name in your for loop to something else:
v-for="(item,index) in products"
or change product in your data (just remove it if you can) cause it doesn't have any data method in it.

Update only a single property of a given object

I have an entity called worker and each worker has a property called active which is boolean.
My twig is an index that shows the list of workers with active=true.
I have a button in front of each worker, when I press this button I want it to change that worker's active property to false.
The problem: I couldn't figure out how to change that value in the controller without making a form since I'm still an amateur when it comes to Symfony
Here's my twig:
<table id="file_export" class="table table-striped table-bordered">
<thead>
<tr>
<th>ID</th>
<th>First Name</th>
<th>Last name</th>
<th>Active</th>
<th>edit</th>
</tr>
</thead>
<tbody>
{% for worker in workers %}
<tr>
<td>{{ worker.id }}</td>
<td>{{ worker.Firstname }}</td>
<td>{{ woker.Lastname }}</td>
<td>{{ worker.active ? 'active' : 'inactive' }}</td>
<td>
<i class="fa fa-pencil"></i>
</td>
</tr>
{% endfor %}
</tbody>
</table>
and my controller (which doesn't work):
/**
* #Route("/{id}/edit", name="worker_edit", methods={"GET","POST"})
*/
public function edit(Request $request, Worker $worker): Response
{
if ($this->isCsrfTokenValid('edit'.$worker->getId(), $request->request->get('_token'))) {
$worker->setActive(false);
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($worker);
$entityManager->flush();
}
return $this->redirectToRoute('index');
}
you actually have to add a csrf token to your path call:
path('worker_edit', {'id': worker.id, '_token': csrf_token('worker'~worker.id)})
or otherwise your check for the csrf token obviously cannot succeed.
however, since a link will trigger a GET request, you have to look into
$request->query->get('_token')
in the isCsrfTokenValid call.
As a hint: give your routes and actions semantically better names. Like ... "worker_deactivate", if it is used to deactivate a worker (which it apparently is). it's also quite common, to call the routed methods of a controller actionAction, so that would be deactivateAction.
If you want to make HTTP requests without reloading the web page, then you've to go for AJAX calls. A very simple implementation using fetch that doesn't require any additional packages (like jQuery) would look like this:
<script>
(function() {
document.getElementById({{worker.id}}).addEventListener('click', function(e) {
e.preventDefault();
fetch({{path('worker_edit', {'id': worker.id})}}, {method: 'POST'})
.then(function(response) {
// you can catch eventual errors here, and of course refresh your button or display a nice message..
});
});
})()
</script>
<table id="file_export" class="table table-striped table-bordered">
<thead>
<tr>
<th>ID</th>
<th>First Name</th>
<th>Last name</th>
<th>Active</th>
<th>edit</th>
</tr>
</thead>
<tbody>
{% for worker in workers %}
<tr>
<td>{{ worker.id }}</td>
<td>{{ worker.Firstname }}</td>
<td>{{ woker.Lastname }}</td>
<td>{{ worker.active ? 'active' : 'inactive' }}</td>
<td>
<i class="fa fa-pencil"></i>
</td>
</tr>
{% endfor %}
</tbody>
</table>
p.s: The javascript code above is not tested as I have to reproduce the twig and controller, but it could give you an idea on how to achieve the task.

How do I create reports in Symfony2?

Im creating an application un Symfony2.7 and I want to start creating reports, I have been reading for a couple of days and cant find a solution.
Ive tried ps pdfbundle, but I cant generate reports. Cant find more Documentation.
Please help
My Code:
public function formatoOcAction($id)
{
$facade = $this->get('ps_pdf.facade');
$response = new Response();
$em = $this->getDoctrine()->getManager();
$InOc = $em->getRepository('NivalInventarioBundle:InOrdenCompra')->findById($id);
$InOcDet = $em->getRepository('NivalInventarioBundle:InOrdenCompraDetalle')->findBy(array(
'idOrdenCompra' => $id));
$stylesheetXml = $this->renderView('NivalInventarioBundle:InOrdenCompra:ordencompra.xml.twig', array());
$this->render('NivalInventarioBundle:InOrdenCompra:ordencompra.pdf.twig', array(
"entities1" => $InOc,
"entities2" => $InOcDet,
"id" => $id),
$response);
$xml = $response->getContent();
$content = $facade->render($xml, $stylesheetXml);
$filename = $this->getParameter('upload_directory').'orden_compra_'.$id.'.pdf';
file_put_contents($filename, $content);
return new Response($content, 200, array('content-type' => 'application/pdf'));
}
Where $id is the Id of the purchase order.
This renders a xml file to PDF but without sylesheet.
This is the twig:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE pdf SYSTEM "%resources%/dtd/doctype.dtd">
{% set empresa = app.session.get('empresa') %}
<pdf>
<page>
<div>
<div>
<table>
<tr>
<td>
<h3>{{ empresa }}</h3>
</td>
<td id="s1">
<h2>Número: <b>{{ id }}</b></h2>
</td>
</tr>
<tr>
<td></td>
<td>
<h3>Orden de compra</h3>
</td>
</tr>
<tr>
<td></td>
<td>
Departamento de Finanzas
</td>
</tr>
</table>
</div>
<div>
{% for entity1 in entities1 %}
Fecha: {{ entity1.fecha|date('d-m-Y') }}
{% endfor %}
</div>
</div>
<div>
<div>
<table width="100%">
<tr>
<td width="60%">Producto</td>
<td width="20%">Unidad</td>
<td>Cantidad</td>
<td>Precio</td>
<td>Total</td>
</tr>
{% set gran_total = 0 %}
{% for entity2 in entities2 %}
<tr>
<td>{{ entity2.productoOc.nombre }}</td>
<td>{{ entity2.productoOc.unidadMedida.nombre }}</td>
<td class="text-right">{{ entity2.cantidad }}</td>
<td class="text-right">{{ entity2.precioCompra }}</td>
<td class="text-right">{{ entity2.total }}</td>
</tr>
{% set gran_total = gran_total + entity2.total %}
{% endfor %}
<tr>
<td></td><td></td><td></td><td></td>
<td class="text-right" >{{ gran_total|number_format(2) }}</td>
</tr>
</table>
</div>
</div>
</page>
</pdf>
Maybe look at the KnpSnappyBundle which allow you to generate PDF file from many sources, including twig templates : http://knpbundles.com/KnpLabs/KnpSnappyBundle
You have at least two options to choose from. I found easiest to work with:
Github KnpLabs/snappy as mentioned by Cyrille Hejl
PDF creator from html content, but in your report controller you would have to do all the work of creating:
header html from twig template
footer html from twig template
cover page html from twig template
toc XML from twig template
base document html from twig template
adding all mentioned html docs to object $pdf = $this->get('knp_snappy.pdf');
PROS:
easy to work with Twig html
no memory exhaust if entity object with relations is supplied to Twig (on longer documents)
CONS:
have to supply html files from Twig template for each joined page (cover, toc, header, footer, base doc)
needed tinkering with right wkhtmltopdf binary version
Github mbence/OpenTBSBundle
This is template merger. In your report controller you will have to supply office template and all the variables, that are replaced with TBS at e.g. word template:
it supports OpenOffice and MSOffice templates
PROS:
customer supplies template, you just replace dynamic content with variables (customer takes care of document design)
CONS:
it could run to memory exhaust problems, since PHP script holds all input variables or arrays in memory.
harder to understand than Twig html (longer learning curve)
I recommend to use: WhiteOctoberTCPDFBundle, it's a bundle to facilitate using TCPDF for PDF generation in Symfony2 applications, great to make the reports we need. Please go to: https://github.com/whiteoctober/WhiteOctoberTCPDFBundle

Symfony2 Doctrine+Twig query taking too long

I'm currently building a query to return a set of records between desired dates as it follows:
public function findBetweenDates(\Datetime $date1,\Datetime $date2)
{
$date1=$date1->setTime(07,00,00);
date_modify($date2,'+1 day');
$date2->setTime(06,59,00);
$qb = $this->getEntityManager()->createQueryBuilder()
->select('e')
->from("AppBundle:Movimento","e")
->andWhere('e.pesagem1 BETWEEN :from AND :to')
->setParameter('from', $date1 )
->setParameter('to', $date2)
->orderBy('e.id','DESC')
;
$result = $qb->getQuery()->getResult();
return $result;
}
the class Movimento has some ManyToOne connections as shown below:
class Movimento
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Service")
* #ORM\JoinColumn(name="service", referencedColumnName="id")
**/
private $service;
When i get the records and render them in twig:
{% for item in items %}
<tr>
<td>{{ item.id }} </td>
<td>{{ item.service.name }}</td>
//#MORE CODE BELOW //
by calling servico.name from another entity i get tons of non wanted queries as a result to display the name of the service instead of its id.
We are talking about something in the 6k range of records in every response.
I would like some help, if it's possible to optimize this query using the my query builder or should i remake the whole query more of a "SQL" example:
Select a.name, b.id
From service as a, movimento as b
Between bla bla bla
Any Help/suggestions are greatly appreciated.
EDIT 1
i changed my query builder after reading this post Symfony 2/Doctrine: How to lower the num of queries without losing the benefit of ORM?
I did reduce 175 queries to a single one
$qb = $this->createQueryBuilder('e')
->addSelect('service')->join('e.service','service')
->addSelect('motorista')->join('e.motorista','motorista')
->addSelect('residuo')->join('e.residuo','residuo')
// ->from("AppBundle:Movimento","e")
->andWhere('e.pesagem1 BETWEEN :from AND :to')
->setParameter('from', $date1 )
->setParameter('to', $date2)
->orderBy('e.id','DESC')
But still the page is taking around 8 seconds to load (its 6900 records) and after checking performance the response time for my new query is 177.79 ms, but my twig+ controller is taking the remaining 7.x seconds as it shows the pic
my controller is something really simple
public function getMovimentosAction(Request $request)
{
$startDate = $request->request->get('startDate');
$endDate = $request->request->get('endDate');
if (empty($startDate))
$startDate = date("Y-m-d") ;
if (empty($endDate))
$endDate = date("Y-m-d");
$em=$this->getDoctrine()->getRepository('AppBundle:Movimento');
$dados=$em->findBetweenDates(new \DateTime($startDate),new \DateTime($endDate));
return $this->render('AppBundle:Movimentos:logtable-movimento.html.twig', array(
'items' => $dados
));
}
and my twig just iterates over the rows and displays them on a table as i gave a partial example above.
Any help/suggestions would be greatly appreciated.
EDIT2
My view that is passed by ajax to be rendered as datatable.js
<table id="example" class="table table-striped table-bordered table-hover" cellspacing="0" width="100%">
<thead class="dataTableHeader">
<tr>
<th>Talão</th>
<th>Nº Talão</th>
<th>Motorista</th>
<th>Residuo</th>
<th>Serviço</th>
<th>Matricula</th>
<th>1º Pesagem</th>
<th>Peso Liquido</th>
<th>Fluxo</th>
<th>Circuito</th>
<th>Verificado</th>
<th></th>
</tr>
</thead>
<tfoot class="dataTableHeader">
<tr>
<th>Talão</th>
<th>Nº Talão</th>
<th>Motorista</th>
<th>Residuo</th>
<th>Serviço</th>
<th>Matricula</th>
<th>1º Pesagem</th>
<th>Liquido</th>
<th>Fluxo</th>
<th>Circuito</th>
<th>Verificado</th>
<th></th>
</tr>
</tfoot>
<tbody>
{% for item in items %}
<tr>
<td align="center"><a href="{{ path("_movimento_generate_pdf",{ id: item.id }) }}"> <i class="fa fa-print fa-2x" aria-hidden="true"></i>
</a></td>
<td>{{ item.id }} <a><i class="fa fa-eye" title="Visualizar Movimento" aria-hidden="true"></i></a>
</td>
<td>{{ item.motorista.idFuncionario }} - {{ item.motorista.nome }}</td>
<td>{{ item.residuo.nome }}</td>
<td>{{ item.servico.nome }}</td>
<td>{{ item.matricula }}</td>
<td>{{ item.pesagem1|date('Y-m-d h:m') }}</td>
<td>{{ item.liquido }} kg</td>
<td>{% if item.tipoMovimento == 1 %} Entrada {% else %} Saida {% endif %}</td>
<td>{{ item.circuito.code | default(" ") }}</td>
<td class="text-center">{% if item.enable==1 %}
<span style="color: transparent"> </span>
<i class="fa fa-circle" aria-hidden="true" style="color: green"></i>
{% else %}
<i class="fa fa-times" aria-hidden="true" style="color: red;"></i>
{% endif %}
</td>
<td class="text-center">
<a class="btn btn-default" href="{{ path('_movimentos_edit',{ 'id' : item.id}) }}">
<i class="fa fa-cog" title="Editar" aria-hidden="true"></i>
<span class="sr-only">Settings</span>
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
and in my html
$("#submitButtonQuery").click(function(event){
event.preventDefault();
var l = Ladda.create(this);
l.toggle();
$.post( "/movimentos/getList",
$( "#formAjaxify" ).serialize())
.done(function(data)
{
$('#example').remove();
$("#tabelaLog").html(data);
oTable=$('#example').DataTable(
{
"scrollX": true,
responsive: true,
"language": {
"url": "http://cdn.datatables.net/plug-ins/1.10.11/i18n/Portuguese.json"
}
}
);
oTable.order( [ 0, 'desc' ] )
.draw();
})
.always(function(){
l.toggle()})
;
});
As long as you have a connection between 'Movimento' and 'Service' then for each 'movimento' that you get as a result a 'service' will be serialized together. This means that if you have a query that returns 100 'movimento' then together with it all 'service' objects (100) will be required to be fetched.
If you don't want to have the Service as an object in each item (AKA item.service.blahblah) then you need to have a more direct query.
if you do it with query builder then you will need something like:
$repository = $this->getDoctrine()
->getRepository('YourownBundle:Movimento'); //the main repo from which to get data
$query = $repository->createQueryBuilder('m') // query builder on repo
->join('m.service', 's') // join the second object to select from
->select('m.id') // select everything from m objet
->addSelect('s.name') // select everything from service (s) object
->where('e.pesagem1 BETWEEN :from AND :to')
->setParameter('from', $date1 )
->setParameter('to', $date2)
->orderBy('e.id','DESC')
the rest of your code should be as you have it... but then you don't have a serialized object but only the selects that you make (eg. m.id, s.name)

Binding two-way in Vuejs not working on display

I have a project in Laravel for backend and VueJs for Front end.
I fetch data with my vueJs object using Api programmed in Laravel. My data is Fetched. In my example i get Article data.
fetchFamily: function(level , id){
this.$http.get('/api/family/' + id, function (data) {
var select_zone = 'options' + level
this.$set(select_zone, data);
})
//Fetch Article
this.$http.get('/api/family/' + id +'/material', function (data) {
this.$set('materials', data);
})
},
onSelectArticle: function(id){
var self = this;
jQuery.each(this.materials,function(idx,dta){
if(dta.id == id){
dta.qte = 0
self.items.push(dta);
return false;
}
});
$('#myModalArticle').modal('hide');
}
But when i want to initialize the quantity data to 0.
dta.qte = 0
I have a problem that in my table i have a input binding to this data.
<tr v-for="item in items">
<td class="hidden-sm"> #{{ item.code }}</td>
<td width="20%"> #{{ item.textes[0].texte }}</td>
<td>18.00</td>
<td><input type="text" v-model="item.qte" ></td>
<td>#{{ item.code }}</td>
<td>Colis</td>
<td>10%</td>
<td>16.20</td>
<td>#{{ item.qte * item.prices[0].price }}</td>
<td>{{ 18 * 40 * 1.17 }}</td>
</tr>
And when i am trying to change this value, in my screen the value doesn't change. And in my console when i check the value the value was changed.!!
vmApp.items[0].qte
Thank you for your Help!

Resources