I'm using the doctrine softdeleteable extension on a project and have my controller action set up as such.
/**
* @Route("address/{id}/")
* @Method("GET")
* @ParamConverter("address", class="MyBundle:Address")
* @Security("is_granted('view', address)")
*/
public function getAddressAction(Address $address)
{
This works great as it returns NotFound if the object is deleted, however I want to grant access to users with ROLE_ADMIN to be able to see soft deleted content.
Does there already exist a way to get the param converter to disable the filter or am I going to have to create my own custom param converter?
There are no existing ways to do it, but I've solved this problem by creating my own annotation, that disables softdeleteable
filter before ParamConverter
does its job.
AcmeBundle/Annotation/IgnoreSoftDelete.php:
namespace AcmeBundle\Annotation;
use Doctrine\Common\Annotations\Annotation;
/**
* @Annotation
* @Target({"CLASS", "METHOD"})
*/
class IgnoreSoftDelete extends Annotation { }
AcmeBundle/EventListener/AnnotationListener.php:
namespace AcmeBundle\EventListener;
use Doctrine\Common\Util\ClassUtils;
use Doctrine\Common\Annotations\Reader;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
class AnnotationListener {
protected $reader;
public function __construct(Reader $reader) {
$this->reader = $reader;
}
public function onKernelController(FilterControllerEvent $event) {
if (!is_array($controller = $event->getController())) {
return;
}
list($controller, $method, ) = $controller;
$this->ignoreSoftDeleteAnnotation($controller, $method);
}
private function readAnnotation($controller, $method, $annotation) {
$classReflection = new \ReflectionClass(ClassUtils::getClass($controller));
$classAnnotation = $this->reader->getClassAnnotation($classReflection, $annotation);
$objectReflection = new \ReflectionObject($controller);
$methodReflection = $objectReflection->getMethod($method);
$methodAnnotation = $this->reader->getMethodAnnotation($methodReflection, $annotation);
if (!$classAnnotation && !$methodAnnotation) {
return false;
}
return [$classAnnotation, $classReflection, $methodAnnotation, $methodReflection];
}
private function ignoreSoftDeleteAnnotation($controller, $method) {
static $class = 'AcmeBundle\Annotation\IgnoreSoftDelete';
if ($this->readAnnotation($controller, $method, $class)) {
$em = $controller->get('doctrine.orm.entity_manager');
$em->getFilters()->disable('softdeleteable');
}
}
}
AcmeBundle/Resources/config/services.yml:
services:
acme.annotation_listener:
class: AcmeBundle\EventListener\AnnotationListener
arguments: [@annotation_reader]
tags:
- { name: kernel.event_listener, event: kernel.controller }
AcmeBundle/Controller/DefaultController.php:
namespace AcmeBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use AcmeBundle\Annotation\IgnoreSoftDelete;
use AcmeBundle\Entity\User;
class DefaultController extends Controller {
/**
* @Route("/{id}")
* @IgnoreSoftDelete
* @Template
*/
public function indexAction(User $user) {
return ['user' => $user];
}
}
Annotation can be applied to individual action methods and to entire controller classes.