我刚刚开始使用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();
}
因此,即使对于这个简单的要求,我已经编写了两个自定义方法。如果我继续从事我的项目,则可能会出现其他限制限制,并且可能会出现加载该实体的其他方式。据我所知,对于每种情况,我都必须为所有访问保护实现逻辑。
没有更简单的方法可以做到这一点吗?我在想像注解或“实体负载侦听器”之类的东西,它使为所有此类检查编写一个单一的入口点变得很简单-使得无法忘记此类检查...
答案 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'));
}
}