Question

I'm using Symfony 1.4/Doctrine's admin generator.

There's a list of questions and I'd like to be able perform a custom object_action on each of them.

What I'm looking for is to mimic the _delete object action but doing some calculation before that.

So I created a new action :

  public function executeListDeleteAndRecalculate(sfWebrequest $request)
  {
    // Do the calculation

    // Then delete the question
  }

And I'm adding it to my generator.yml:

object_actions:
    delete_and_recalculate: ~

the new action shows in the admin generator but the delete part doesn't work.

I tried a bunch of thing to make it work:

  • Once all the calculation was done, I first tried to redirect to the questionActions/delete action.
  • I also tried to copy the executeDelete code to my new action.

But everytime I get the infamous

500 | Internal Server Error | sfValidatorErrorSchema _csrf_token [Required.]

So I'm guessing Symfony is doing some magic before actually deleting an object.

Do you know what I'm missing and what's the best way to implement a deleteAndRecalculate kind of action?

Edit:

Of course if I remove the $request->checkCSRFProtection(); everything works just fine. But I assume it's pretty important so I'd like to find a prettier solution.

Was it helpful?

Solution

This is because the delete link from the admin generator uses a token to prevent CSRF attacks.

Basically, it sets a token into your session and into an hidden field of a form then checks them one against another on the request. This is possible because the delete link in the admin generator is actually a (javascript generated) form (this is done to add a sf_method hidden field to simulate REST behavior).

For more information on how CSRF works and can be prevented, you can read further on Wikipedia: http://en.wikipedia.org/wiki/Cross-site_request_forgery

What you can do is use the same kind of link, you just have to pass a method parameter to link_to for it to generate a form, have a look at lib/generator/sfModelGeneratorHelper.class.php line 32 to see how it's done in the admin-gen.

You would then execute $request->checkCSRFProtection() in your executeDeleteAndRecalculate method, and proceed with whatever you want to do, including deleting the object by hand.

To properly generate the link, you would add a linkToDeleteAndRecalculate method in the Helper class of your module (that should lie in the lib/${YourModule}GeneratorHelper.class.php file of your module directory) and add the following code (directly taken and adapted from sfModelGeneratorHelper):

public function linkToDeleteAndRecalculate($object, $params)
{
  if ($object->isNew())
  {
    return '';
  }

  return '<li class="sf_admin_action_delete">'.link_to(__($params['label'], array(), 'sf_admin'), 'delete_and_recalculate', $object, array('method' => 'delete', 'confirm' => !empty($params['confirm']) ? __($params['confirm'], array(), 'sf_admin') : $params['confirm'])).'</li>';
}

Please note that you have to change the route (I've put delete_and_recalculate by default but you might want to prefix it with your module's name) from the link_to call.

You can then use your delete_and_recalculate nearly like a builtin method from the admin generator (and pass it a label from the generator.yml for example)

Now that was the hard-way.

The easy way would be to subscribe to the admin.delete_object event, from your module's pre-execute for example, and to your job there :-)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top