3

I have implemented the clone action just like in the documentation. How can I limit the access to the clone action to the user who created the object?

I have already an access denied exception check in my action, but how can I now hide the button in the list view if the user is not the author of that object. The user should still be able to list the order and display it.

This is my route:

protected function configureRoutes(RouteCollection $collection)
{
    $collection->add('clone', $this->getRouterIdParameter().'/clone'); 
}

And my list fields:

protected function configureListFields(ListMapper $listMapper)
{
    $listMapper
        ->add('_action', 'actions', array(
            'actions' => array(
                'show' => array(),
                'edit' => array(),
                'clone' => array(
                    'template' => 'AppBundle:Sonata/Button:clone_button.html.twig'
                ),
            ), 'label' => 'Actions'
        ))
    ;
}

and my clone action:

public function cloneAction($id = null)
{
    $object = $this->admin->getSubject();
    if (!$object) {
        throw new NotFoundHttpException(sprintf('Unable to find the object with id : %s', $id));
    }

    If (!$object->isAuthor($this->getUser())) {
        throw new AccessDeniedException();
    }

    $clonedObject = clone $object;

    $this->admin->create($clonedObject);
    $this->addFlash('sonata_flash_success', 'Cloned successfully');
    return new RedirectResponse($this->admin->generateUrl('edit', array('id' => $clonedObject->getId())));
}

As you can see in my clone action, I have a check to see if the user is the author of the order. But how can I remove the button in the list completely by check my isAuthor function?

Because now the user can see the button but if he is unauthorized to clone the order and he clicks the button he get an access denied exception. So I don't want to show the button at all. The same counts for the edit button.

I have thought of something like this:

protected function configureRoutes(RouteCollection $collection)
{
    $user = $this->getConfigurationPool()->getContainer()->get('security.token_storage')
            ->getToken()->getUser();

    If (!$object->isAuthor($user)) {
        $collection->remove('edit');
        $collection->remove('clone');
    }
}

But apparently this can't be done.

Does anybody have an idea how to do this?

Jack Coolen
  • 229
  • 1
  • 13

1 Answers1

2

I would create a Symfony Voter and remove the check from the action. The check would be done, in the voter outside the action, and could be done from anywhere, including the template. You should check the template, it probably already does the check.

Also, off-topic pro-tip, always provide a message inside your exceptions.

throw new AccessDeniedException('Not an author of this object');
greg0ire
  • 22,714
  • 16
  • 72
  • 101
  • OK, that will make some things I have to do indeed easier. But now the question remains, how can I hide the route if the user doesn't have access? The button will remain there and if someone click it an exception will be thrown. I only want the button to be shown if the user may use it. It is easy to do that if I work with pure Symfony. But now I use Sonata with it. – Jack Coolen Nov 29 '16 at 09:14
  • 1
    Check the template, but as I said, there probably already is a check in it? Or maybe did you write the template yourself? It should use `is_granted()` with the route and the object, and this will call the voter. – greg0ire Nov 29 '16 at 14:03
  • So step 0 if you want to solve this is find and show us the template for the button – greg0ire Nov 29 '16 at 14:04
  • 1
    I checked the templates for the edit and create buttons and I saw that they indeed have a `is_granted()`, so I added that check to my clone action as well and changed it to my preference. It's all good know. I understand now how that works as well. Thanks. – Jack Coolen Nov 29 '16 at 16:08
  • Glad to learn you did it. Consider contributing something to the docs if you feel this should appear somewhere. – greg0ire Nov 29 '16 at 16:10