0

I would like to use voters to enhence the security in my code. I want only some users to be able to delete collection of items.

Here my exemple:
I have an Article and Tags associated to the Article. I want an author of the Article to be able to delete Tags associated with that Article (only author of the article can do this)

I was thinking of using voters (to check that a user is the author of the article), but every single exemple I found on the internet show voters that are called either from twig or from the controller... while with collection option "allow-delete" symfony call the method removeTag($tag) from entity Article. Also I do not see how/where I can call the voters.

Wouter J
  • 41,455
  • 15
  • 107
  • 112
Alexis_D
  • 1,908
  • 3
  • 16
  • 35
  • Premising that I don't know your use case and I think that this check type must be applied always before accessing to the action from which you can `delete` the tag (in the controller), but to try to answer your specific question, what do you think about adding a custom validator inside the `Article` entity and then call inside it the related voter? Or you may call the voter in the controller and then pass the result to the form builder to set `allow_delete => false`. In any case you can add an appropriate error message to the user. – gp_sflover Apr 15 '15 at 11:26
  • @gp_sflover thks for you help. how can I add a custom validator inside the article entity and then call inside the related voter? validator cannot be implemented to method other than get or is... while I want my check to be made on removeTag or something like that... – Alexis_D Apr 22 '15 at 10:08

1 Answers1

2

the answer can be just this:

yes you can, inject service.container where you want and call $this->securityContext->isGranted('delete', $tag);

but this means that you need to inject a service in your entities and it's totally wrong.

Another way is to do that inside a doctrine listener on preRemove or onFlush events, it's cool but almost wrong, what you do if voter fails? if you throw an exception this will break doctrine. Also what happens if there are no users? reason is that in a listener you can't easily return a feedback to the user.

Block an entity deletion on higher level of abstraction is wrong because you can do in a better and more manageable place whitout risk to create errors in other remote places of your codebase.

instead try this:

  • if you are using symfony forms you can do one of these two things:
    • use a form constraint as a service, inject here security context and do your validation, if wrong add a form error
    • create a custom formtype as a service with collection as parent, inject security.context and finally use a form listener on PRE_SET_DATA to check if something is removed and check if the current user is allowed with isGranted, if the check fails add a form error
  • if you're doing that in a single action (for example an api) you just need to check with isGranted directly in your action or in your twig
Marino Di Clemente
  • 3,120
  • 1
  • 23
  • 24
  • thks Marino for your answer. Could you please give me more detail about your first solution. **form constraint as a service, inject security context...** that would help me a lot. – Alexis_D Apr 15 '15 at 12:26
  • unfortunately today I do not have time to write you a complete solution http://symfony.com/doc/current/cookbook/validation/custom_constraint.html go with this, there are an explanation of how to do a constraint as a service. The hard part is after you do that, you need to be able to know the deleted elements of the collection, the easiest way is to set the original collection inside the validator using a form event http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html – Marino Di Clemente Apr 15 '15 at 16:38
  • another way is to compute the entity changeset with doctrine or more easily to store the deleted items somewhere in the entity (moving in an array when removeTag is called) – Marino Di Clemente Apr 15 '15 at 16:40
  • I choose to use a constraint as a service. So far I wanted to use a validation deletetag associated to the methode deleteTag() but symfony say it can only use validator with method starting with get or is. can you please help me on this. I did everything else just this part haven't succeed yet. – Alexis_D Apr 21 '15 at 21:13
  • you should validate "tags" keeping track of initial tags in some other way – Marino Di Clemente Apr 27 '15 at 08:15