Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony 2 - Delete Forms and CSRF Token

I have a List of entries coming from a database. I would like to have a "Delete-Button" at the end of every row, so that the user won't have to first go to the edit/show page to delete the entry.

I tried creating a hidden input field with the csrf token like so:

return $this->createFormBuilder()
   ->getForm()
;

this will output:

<div id="form">
   <input type="hidden" id="form__token" name="form[_token]" value="6c98ebfa9df07.....">
</div>

The rest of the Form i put around in the twig template so that every form has its own action path according the the id of the entry.

unfortunately in the twig template only the first

{{ form_widget(delete_form) }}

will get rendered.

How can i use this hidden field more often? OR is there any way to do this whole thing differently?

Thanks for any help

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()
    ;
}
like image 210
ldrocks Avatar asked Apr 19 '13 13:04

ldrocks


2 Answers

You may render individual tokens with:

{{ form_widget(form._token) }}

or specifically for your case:

{{ form_widget(delete_form._token) }}

But, I think you are better served making an array of forms and fully rendering each one:

In your controller:

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
}

In your twig do something along the lines of:

{% for form in delete_forms %}{{form_widget(form)}}{% endfor %}
like image 81
Lighthart Avatar answered Sep 24 '22 06:09

Lighthart


The answer of @Lighthart led me to the correct answer:

In your controller generate an array of form views and had it over to the view:

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
    ));
}

Now you have to access this in your view. Therefore you can use the form functions and the special loop variables:

{% 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 %}

That's it.

like image 35
Phidelux Avatar answered Sep 24 '22 06:09

Phidelux