代码之家  ›  专栏  ›  技术社区  ›  Nico Haase

限制访问条令实体的单一位置

  •  1
  • Nico Haase  · 技术社区  · 6 年前

    我刚开始使用教义,建立了一个简单的博客项目。我的要求之一是,在达到发布日期之前,任何人都不能看到博客文章(简单来说,跳过编辑界面)。

    据我所见,使用自定义存储库是显而易见的。让我们把 find 方法如下:

    public function find($id, $lockMode = null, $lockVersion = null)
    {
        /** @var Post $post */
        $post = parent::find($id, $lockMode, $lockVersion);
        if($post->getCreatedAt() > new \DateTime()) {
            return null;
        }
    
        return $post;
    }
    

    这将限制对显示单个网页的访问 Post 实体。对于概述页面,可以使用自定义方法进行相同操作:

    public function findForOverview()
    {
        $query = $this->createQueryBuilder('p')
            ->where('p.createdAt < CURRENT_TIMESTAMP()')
            ->orderBy('p.createdAt', 'DESC')
            ->getQuery();
    
        return $query->getResult();
    }
    

    所以,即使对于这个简单的需求,我已经编写了两个自定义方法。如果我继续在我的项目上工作,可能会出现其他限制,并且可能会出现加载该实体的其他方法。据我所见,对于每种情况,我都必须实现所有访问保护的逻辑。

    有没有更简单的方法?我在想一个注释或者“实体加载监听器”之类的东西,它使得为所有这些检查编写一个入口点变得简单——使得不可能忘记这些检查……

    1 回复  |  直到 6 年前
        1
  •  2
  •   Flying    6 年前

    这种限制通常通过使用 SQL filters 在学说中。这个过滤器的实现在较低的级别上工作,然后是DQL,它允许您为正在构造的SQL查询应用修改。在您的情况下,可能如下所示:

    namespace App\ORM\Filter;
    
    use App\Entity\Post;
    use Doctrine\ORM\Mapping\ClassMetadata;
    use Doctrine\ORM\Query\Filter\SQLFilter;
    
    class PostVisibilityFilter extends SQLFilter
    {
        /**
         * Gets the SQL query part to add to a query.
         *
         * @param ClassMetadata $targetEntity
         * @param string $targetTableAlias
         * @return string The constraint SQL if there is available, empty string otherwise
         */
        public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias): string
        {
            if ($targetEntity->name !== Post::class) {
                return '';
            }
            return sprintf('%s.%s >= now()', $targetTableAlias, $targetEntity->getColumnName('createdAt'));
        }
    }