我有一个来自数据库的条目列表。我希望在每一行的末尾都有一个“删除按钮”,这样用户就不必先转到编辑/显示页面来删除条目。
我尝试使用 csrf 令牌创建一个隐藏的输入字段,如下所示:
return $this->createFormBuilder()
->getForm()
;
这将输出:
<div id="form">
<input type="hidden" id="form__token" name="form[_token]" value="6c98ebfa9df07.....">
</div>
我将表单的其余部分放在树枝模板中,以便每个表单根据条目的 id 都有自己的操作路径。
不幸的是,在树枝模板中只有第一个
{{ form_widget(delete_form) }}
将会被渲染。
如何更频繁地使用这个隐藏字段? 或者有什么方法可以以不同的方式做这件事吗?
感谢您的帮助
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$deleteForm = $this->createDeleteForms();
$entities = $em->getRepository('IntranetServicesBundle:Laender')->findAll();
return $this->render('IntranetServicesBundle:Laender:index.html.twig', array(
'entities' => $entities,
'delete_form' => $deleteForm->createView(),
));
}
private function createDeleteForms()
{
return $this->createFormBuilder()
->add('id', 'hidden')
->getForm()
;
}
您可以使用以下方式呈现单个令牌:
{{ form_widget(form._token) }}
或专门针对您的情况:
{{ form_widget(delete_form._token) }}
但是,我认为你最好制作一系列表格并充分渲染每个表格:
在您的控制器中:
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$rep= $em->getRepository('IntranetServicesBundle:Laender')
->createQueryBuilder('l');
var_dump($rep->getQuery()->getDql());
$entities=$rep->getQuery()->getResult();
$delete_forms = array_map(
function($element){
return $this->createDeleteForm($element->getId());}
,$entities->toArray()
);
return $this->render('IntranetServicesBundle:Laender:index.html.twig'
, array(
'entities' => $entities,
'delete_forms' => $delete_forms
));
}
private function createDeleteForms($id)
{
return $this->createFormBuilder(array('id' => $id)))
->add('id', 'hidden')
->getForm()
;
}
public function deleteAction(Request $request, $id)
{
$form = $this->createDeleteForm($id);
$form->bind($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('IntranetServicesBundle:Laender')
->find($id);
// this line might need to be changed to point to the proper repository
if (!$entity) {
throw $this->createNotFoundException('Unable to find Laender entity.');
}
$em->remove($entity);
$em->flush();
}
return $this->redirect($this->generateUrl('laender_index'));
// this line might need to be changed to point to the proper
// post-delete route
}
在你的树枝上做一些类似的事情:
{% for form in delete_forms %}{{form_widget(form)}}{% endfor %}
@Lighthart 的回答让我找到了正确答案:
在控制器中生成表单视图数组并将其传递给视图:
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('AppBundle:Entity')->findAll();
$delete_forms = array_map(
function ($element) {
return $this->createDeleteForm($element->getId())->createView();
}
, $entities
);
return $this->render('AppBundle:Entity:index.html.twig', array(
'entities' => $entities,
'delete_forms' => $delete_forms
));
}
现在您必须在您的视图中访问它。因此,您可以使用表单函数和特殊循环变量:
{% extends '::base.html.twig' %}
{% block body %}
{% for entity in entities %}
{# Access the delete form for this entity using the loop index ... #}
{% set delete_form = delete_forms[loop.index0] %}
{# ... and display the form using the form tags. #}
{{ form_start(delete_form) }}
<input type="submit" value="Delete" />
{{ form_end(delete_form) }}
{% endfor %}
{% endblock %}
就是这样。
我遇到过类似的情况,我想在使用 csrf 保护时删除产品。我还想使用 ajax 发出 DELETE 请求。
因此,要做到这一点,这就是我的 view,index.html,看起来像:
// html for displaying a products table with delete btn for each row
// ...
// Retrieve csrf token and store it somewhere in DOM (preferably outside table),
// We do this so that we can send the token via ajax later
<span id="csrf_token" data-token="{{ csrf_token('form') }}"></span>
<script>
// Make an ajax request on the on-click handler of our delete btn
$.ajax({
url: localhost/admin/product/4545, // generated dynamically, the last segment being the ID of the item to be deleted.
type: 'POST',
data: {
"_method": "DELETE",
"form[_token]": $("#csrf_token").data("token") // passed csrf token here
},
success: function(result) {
// Do something with the result
}
});
</script>
如上所示,
{{ csrf_token('form') }}
实际上是在twig中为您提供csrf令牌。
我的控制器:
/**
* Deletes a product entity.
* @Route("/{id}", name="admin_product_delete")
* @Method("DELETE")
*/
public function deleteAction(Request $request, product $product)
{
$form = $this->createDeleteForm($product);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->remove($product);
$em->flush($product);
// you can return a json response here to your ajax callback if you'd like.
return new JsonResponse(array('status' => 'deleted'));
}
// return new JsonResponse(array('status' => 'failed'));
}
/**
* Creates a form to delete a product entity.
* @param product $product The product entity
* @return \Symfony\Component\Form\Form The form
*/
private function createDeleteForm(product $product)
{
return $this->createFormBuilder()
->setAction($this->generateUrl('admin/product/{id}', array('id' => $product->getId())))
->setMethod('DELETE')
->getForm()
;
}
这应该会按预期删除所需的行!
@Phidelux 的回答让我找到了以下解决方案:
在 twig 中我创建了删除表单:
<form method="post" action="{{ path('page_delete', {'id': page.id}) }}" onsubmit="return confirm('Are you sure you want to delete this item?');">
<input type="hidden" name="_method" value="DELETE">
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ page.id) }}">
<button type="submit" class="btn btn-icon">
<i class="far fa-trash-alt"></i>
</button>
</form>
创建列表视图的代码是:
/**
* @Route("/", name="page-list", methods={"GET"})
*/
public function index(PageRepository $pageRepository): Response
{
$pages = $pageRepository->findAll();
$delete_forms = array_map(
function ($element) {
return $this->render('admin/page/_delete_form.html.twig', [
'page' => $element,
]);
}
, $pages
);
return $this->render('admin/page/index.html.twig', [
'pages' => $pages,
'delete_forms' => $delete_forms
]);
}
然后在我的列表视图中添加了删除按钮:
{% for key, page in pages %}
...
{{ delete_forms[key].content | raw }}
{% endfor %}
在我的编辑页面表单中我可以使用:
{{ include('admin/sjabloon/_delete_form.html.twig') }}
这解决了删除时不允许消息的方法