是否可以通过某种walker运行所有条令查询,以便我可以根据当前用户的凭据修改查询?理想情况下,我不必在每个查询上为自定义walker显式调用setHint,因为这会限制我将当前SecurityContext传递到walker的能力。
此外,我更喜欢不使用条令过滤器,因为我不能用过滤器修改连接条件,并且我将被迫使用"IN"子句,这将严重影响的性能
目前,我使用的是一种基于用户凭据修改QueryBuilder的服务,但这会变得乏味,因为每次创建新的QueryBuilder时我都需要调用该服务,当存储库发挥作用时(因为我需要将服务注入每个需要修改查询的存储库中),这会更加痛苦。
希望我已经解释清楚了。感谢您的反馈!
我想我已经解决了自己的问题。如果其他人有更优雅的方式来实现这些结果,请随意解释。为了修改我的所有查询,我创建了一个自定义EntityManager和自定义EntityRepository。
在我的自定义EntityManager中,我覆盖了2个方法。create()和getRepository()
public static function create($conn, Configuration $config, EventManager $eventManager = null)
{
if ( ! $config->getMetadataDriverImpl()) {
throw ORMException::missingMappingDriverImpl();
}
switch (true) {
case (is_array($conn)):
$conn = DoctrineDBALDriverManager::getConnection(
$conn, $config, ($eventManager ?: new EventManager())
);
break;
case ($conn instanceof Connection):
if ($eventManager !== null && $conn->getEventManager() !== $eventManager) {
throw ORMException::mismatchedEventManager();
}
break;
default:
throw new InvalidArgumentException("Invalid argument: " . $conn);
}
return new MyCustomEntityManager($conn, $config, $conn->getEventManager());
}
此方法中唯一更改的是,我将返回自己的EntityManger(MyCustomEntityManager)。然后,我将getRepository方法覆盖如下:
public function getRepository($entityName)
{
$entityName = ltrim($entityName, '\');
if (isset($this->repositories[$entityName])) {
return $this->repositories[$entityName];
}
$metadata = $this->getClassMetadata($entityName);
$repositoryClassName = $metadata->customRepositoryClassName;
if ($repositoryClassName === null) {
$repositoryClassName = "AcmeDemoBundleDoctrineORMMyCustomEntityRepository";
}
$repository = new $repositoryClassName($this, $metadata);
$this->repositories[$entityName] = $repository;
return $repository;
}
在这里,我也只修改了一行。我没有依赖DBAL配置来检索默认的$repositoryClassName,而是指定了自己的默认存储库Acme\DemoBundle\Doctrine\ORM\MyCustomEntityRepository。
一旦您创建了自己的自定义EntityRepository,天空就是极限。您可以将服务注入存储库(我目前使用JMSDi注释,如下所述),或者在createQueryBuilder方法中对QueryBuilder执行自定义操作,如下所示:
use JMSDiExtraBundleAnnotation as DI;
class MyCustomEntityRepository extends EntityRepository
{
private $myService;
public function createQueryBuilder($alias)
{
$queryBuilder = parent::createQueryBuilder($alias);
/** INSERT CUSTOM CODE HERE **/
return $queryBuilder;
}
/**
* @DIInjectParams({
* "myService" = @DIInject("my_service_id")
* })
*/
public function setMyService(MyServiceInterface $myService)
{
$this->myService = $myService;
}
}
一旦创建了自己的EntityRepository,就应该让所有需要此自定义功能的存储库扩展MyCustomEntityRepository。您甚至可以更进一步,创建自己的QueryBuilder来进一步扩展它。
您可以编写一个自定义的AST Walker,并通过defaultQueryHint
(Doctrine 2.5新功能)配置选项将您的应用程序设置为使用该Walker进行所有查询:
<?php
/** @var DoctrineORMEntityManager $em */
$em->getConfiguration()->setDefaultQueryHint(
Query::HINT_CUSTOM_TREE_WALKERS,
['YourWalkerFQClassName']
)