9

My application shows a list of projects, project detail pages and forms to edit these projects. These are the routes:

  • / - list of projects
  • /project/42 - view project (project detail page)
  • /project/42/edit - edit project

Only its owner may edit a project.

I have implemented a Voter to prevent access to /project/42/edit for non-owners.

Now, I also want to hide the link "edit project" from the project detail page. What would be the way to do this? Ideally, in Twig, I would like to do something like

{% if may_access(path('project_edit', { 'id': project.id })) %}
  <a href="{{ path('project_edit', { 'id': project.id }) }}">edit project</a>
{% endif %}

I can implement this function as a Twig extension, but maybe a similar functionality already exists.

Olav
  • 1,602
  • 2
  • 16
  • 21

1 Answers1

11

The function is_granted() actually has a second parameter that allows me to do just what I need:

{% if is_granted("MAY_EDIT", project) %}
  <a href="{{ path('project_edit', { 'id': project.id }) }}">edit project</a>
{% endif %}

I use this in combination with a check in the controller action:

public function editAction(Project $project)
{
    if (!$this->get('security.context')->isGranted('MAY_EDIT', $project)) {
        $this->flash('You are not allowed to edit this project');
        return $this->show($project);
    }
    // ...
}

This is actually very similar to the approach that nifr used in his answer to Sonata User - Security on custom field. I was hoping to find a way to have the voter be called automatically and avoid the call to isGranted().

If you want to have a look at the complete code, it is in the tutorial project I have published in github.

Community
  • 1
  • 1
Olav
  • 1,602
  • 2
  • 16
  • 21
  • 2
    Please be advised, anyone can url hack. Make sure your controller has the appropriate redirects as well. – Lighthart Jun 14 '13 at 04:46
  • Nice work. One thing to note, if `$this->show($project);` is just returning the same view as the project page (/project/42). It would probably be best to use a 302 redirect to that route. – Paul Jun 14 '13 at 20:26
  • Ah, sorry, my $this->show($project) is actually just a small helper that does return $this->redirect($this->generateUrl('project_show', array('id' => $project->getId()))); – Olav Jun 14 '13 at 20:34
  • Excellent :) Btw, if you want to reply to someone in a comment on Stackoverflow you can write in their username like `@Paulpro` and then they receive a notification that you've replied to them :) – Paul Jun 14 '13 at 20:54