单一职位以限制对某项原则实体的访问

时间:2019-01-09 08:54:24

标签: symfony doctrine-orm

我刚刚开始使用Doctrine,并建立了一个简单的博客项目。我的要求之一是,在到达发布日期之前,任何人都不得看到博客帖子(为简单起见,请跳过编辑者的界面)。

据我所知,使用自定义存储库显然是这样做的。让我们通过以下方式扩展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 个答案:

答案 0 :(得分:2)

此类限制通常是通过使用教义中的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'));
    }
}