views:

1324

answers:

1

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.

+2  A: 

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 :-)

Geoffrey Bachelet
Thanks for your answer.However, even if I try to copy the way linkToDelete creates a link, I can't generate the onclick javascript event that is creating the form. And I can't find where it's done for the _delete object action either.About the "easy way": I don't think that would work since I want to keep the default "Delete" action too.
Guillaume Flandre
Ok, I have edited my answer with directions on how to generate the link, does that help?
Geoffrey Bachelet
I'm almost there, everything seems to be ok until i click on the link. i don't know what's wrong about the route i wrote (see here: http://pastie.org/798862 ) in backend/config/routing.yml. But I get a 404 "Action "supprimer_et_recalculer/33" does not exist."
Guillaume Flandre
Do you have the default /:module/:action route still in your routing.yml?If yes, and if it is before your custom route, then symfony will match it in priority.If not, well, the complete trace could help, as well as your complete routing.yml I guess :-)
Geoffrey Bachelet
Nevermind, I worked around it. It now works, thanks!
Guillaume Flandre