【问题标题】:How to disable a doctrine filter in a param converter如何在参数转换器中禁用学说过滤器
【发布时间】:2015-07-31 18:34:16
【问题描述】:

我正在一个项目中使用原则 softdeleteable 扩展,并将我的控制器操作设置为这样。

/**
 * @Route("address/{id}/")
 * @Method("GET")
 * @ParamConverter("address", class="MyBundle:Address")
 * @Security("is_granted('view', address)")
 */
public function getAddressAction(Address $address)
{

这很有效,因为如果对象被删除,它会返回 NotFound,但是我想授予具有 ROLE_ADMIN 的用户访问权限,以便能够查看软删除的内容。

是否已经存在让参数转换器禁用过滤器的方法,还是我必须创建自己的自定义参数转换器?

【问题讨论】:

    标签: symfony doctrine-orm doctrine-extensions


    【解决方案1】:

    没有现成的方法可以做到这一点,但我通过创建自己的注释解决了这个问题,在ParamConverter 工作之前禁用softdeleteable 过滤器。

    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];
        }
    
    }
    

    注解可以应用于单个动作方法和整个控制器类。

    【讨论】:

    • 仅供参考:在最近的 symfony 版本中,控制器的 get 方法受到保护,不能在侦听器的 ignoreSoftDeleteAnnotation 方法中调用。您可以在构造函数中传递 EntityManager,就像 Reader 并依赖依赖注入一样。自 symfony 4.3 以来,FilterControllerEvent 也已被弃用,应该使用 ControllerEvent 代替。
    【解决方案2】:

    您可以为此使用@Entity,自定义存储库方法,如下所示:

        use Symfony\Component\Routing\Annotation\Route;
        use Sensio\Bundle\FrameworkExtraBundle\Configuration\Entity;
    
        /**
         * @Route("/{id}")
         * @Entity("post", expr="repository.findDisableFilter(id)")
         */
         public function disable(Post $post): JsonResponse
        {
            ...
        }
    

    然后在您的存储库类中:

        public function findDisableFilter(mixed $id): mixed
        {
            $filterName = 'your-filter-name';
            $filters = $this->getEntityManager()->getFilters();
            if ($filters->has($filterName) && $filters->isEnabled($filterName)) {
                $filters->disable($filterName);
            }
    
            return $this->find($id);
        }
    
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-04
      • 2020-09-19
      • 1970-01-01
      • 2011-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多