In Symfony 2, which is the best way to create a link to delete a record?
I can define a route to /entity/delete
accepting only a DELETE
method, but I don't know how to create a DELETE
link from a template. The same goes for creating PUT
links.
So, what do you do? Accept GET
petition to delete a record? Is there any way to create a DELETE
link?
Symfony2 _method
functionality description can be found in How to Define Route Requirements. Below is the solution I use.
Link
<a
href="{{ path('my_delete_route_name', {'id': some_entity.id}) }}"
class="as-form"
data-method="delete"
data-csrf="_token:{{ csrf }}"
>{{ 'delete'|trans({}, 'button') }}</a>
Re-Format the above link to inline after copy-paste
Attach onClick event listener:
JS
$('.as-form').on('click',function(){
var $form = $('<form/>').hide();
//form options
$form.attr({
'action' : $(this).attr('href'),
'method':'post'
})
//adding the _method hidden field
$form.append($('<input/>',{
type:'hidden',
name:'_method'
}).val($(this).data('method')));
//adding a CSRF if needs
if ($(this).data('csrf'))
{
var csrf = $(this).data('csrf').split(':');
$form.append($('<input/>',{
type:'hidden',
name:csrf[0]
}).val(csrf[1]));
}
//add form to parent node
$(this).parent().append($form);
$form.submit();
return false;
});
Controller
class MyCustomController extends Controller
{
/**
* @Route("/delete/{id}",name="my_delete_route_name")
* @Method("DELETE")
* @ParamConverter("entity", class="MyEntityClass")
* @CsrfProtector(intention="my_csrf_intention", name="_token")
*/
public function deleteAction(Request $request, $entity)
{
// do whatever you need
}
}
Note
@CsrfProtector
is my custom annotation that is used to validate the CSRF token passed in request before running the controller method.
Anchors can fire only GET requests. And since GET requests can be cached and in some future (when you implement serious caching) might not reach your app code at all, it's a bad practice to use GET for changing anything that modifies state of your App. Here is what I do in my projects. With these two, you will be able to just do the following in your templates:
<a href="{{ path('my_entity_destroy') }}" {{ delete_link(myEntity) }}>Delete</a>
Assuming your entity delete path is: /my_entity
, methods: [DELETE]
Principle is really simple. delete_link
extension method will create data-attribute
on anchor, so compiled anchor will look like this:
<a href="/my_entity" data-delete-link="3964">Delete</a>
Then, when somebody clicks on that link, javascript will catch that click, create a form and fire a DELETE request with id provided in data-delete-link
attribute.
Here is what makes it possible, a LinkHelper
Twig extension:
<?php
namespace Me\MyBundle\Twig;
class LinkHelperExtension extends \Twig_Extension
{
public function getFunctions()
{
return [
new \Twig_SimpleFunction('delete_link', [$this, 'fnDeleteLink'], ['is_safe' => ['all']]),
];
}
public function fnDeleteLink($target)
{
if (is_object($target)) {
$target = $target->getId();
}
return "data-delete-link='$target'";
}
public function getName()
{
return 'link_helper';
}
}
And I a JavaScript in my base template:
$(function () {
var createForm = function (action, data) {
var $form = $('<form action="' + action + '" method="POST"></form>');
for (input in data) {
if (data.hasOwnProperty(input)) {
$form.append('<input name="' + input + '" value="' + data[input] + '">');
}
}
return $form;
};
$(document).on('click', 'a[data-delete-link]', function (e) {
e.preventDefault();
var $this = $(this);
var $form = createForm($this.attr('href'), {
id: $this.attr('data-delete-link'),
_method: 'DELETE'
}).hide();
$('body').append($form); // Firefox requires form to be on the page to allow submission
$form.submit();
});
});
It only works for entities that have primary key named id
. However, you can pretty easy modify this to suit your needs and support composite primary keys etc.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With