Symfony2/条令-修改所有查询

Symfony2/条令-修改所有查询,symfony,doctrine-orm,Symfony,Doctrine Orm,是否可以通过某种walker运行所有条令查询,以便根据当前用户的凭据修改查询?理想情况下,我不必在每个查询上显式调用自定义walker的setHint,因为这会限制我将当前SecurityContext传递到walker的能力 另外,我不希望使用条令过滤器,因为我不能用过滤器修改连接条件,而且我将被迫使用“IN”子句,这将严重影响性能 目前,我正在使用一个基于用户凭据修改QueryBuilder的服务,但这会变得很乏味,因为每次创建新的QueryBuilder时我都需要调用该服务,而且当存储库发

是否可以通过某种walker运行所有条令查询,以便根据当前用户的凭据修改查询?理想情况下,我不必在每个查询上显式调用自定义walker的setHint,因为这会限制我将当前SecurityContext传递到walker的能力

另外,我不希望使用条令过滤器,因为我不能用过滤器修改连接条件,而且我将被迫使用“IN”子句,这将严重影响性能

目前,我正在使用一个基于用户凭据修改QueryBuilder的服务,但这会变得很乏味,因为每次创建新的QueryBuilder时我都需要调用该服务,而且当存储库发挥作用时(因为我需要将该服务注入到需要修改查询的每个存储库中),这会让我更加痛苦


希望我已经解释得足够清楚。感谢您的反馈!

我想我已经解决了自己的问题。如果其他人有更优雅的方法来实现这些结果,请随意解释。为了修改我的所有查询,我创建了自定义EntityManager和自定义EntityRepository

在我的自定义EntityManager中,我覆盖了2个方法。create()和getRepository()

此方法中唯一改变的是,我返回自己的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 = "Acme\DemoBundle\Doctrine\ORM\MyCustomEntityRepository";
    }

    $repository = new $repositoryClassName($this, $metadata);

    $this->repositories[$entityName] = $repository;

    return $repository;
}
这里,我也只修改了一行。我没有依赖DBAL配置来检索默认的$repositoryClassName,而是指定了自己的默认存储库Acme\DemoBundle\doctor\ORM\MyCustomEntityRepository

一旦您创建了自己的自定义EntityRepository,天空就是极限。您可以将服务注入存储库(我目前使用JMS Di注释,如下所述),或者在createQueryBuilder方法中对QueryBuilder执行自定义操作,如下所示:

use JMS\DiExtraBundle\Annotation as DI;

class MyCustomEntityRepository extends EntityRepository
{
    private $myService;

    public function createQueryBuilder($alias)
    {
         $queryBuilder = parent::createQueryBuilder($alias);

          /** INSERT CUSTOM CODE HERE **/

          return $queryBuilder;
    }

    /**
    * @DI\InjectParams({
    *     "myService" = @DI\Inject("my_service_id")
    * })
    */
    public function setMyService(MyServiceInterface $myService)
    {
        $this->myService = $myService;
    }
}
一旦您创建了自己的EntityRepository,您应该让所有需要此自定义功能的存储库扩展MyCustomEntityRepository。您甚至可以更进一步,创建自己的QueryBuilder以进一步扩展此功能。

您可以编写一个应用程序,并将应用程序设置为使用此walker进行所有查询
defaultQueryHint
(原则2.5新功能)配置选项:

<?php
/** @var \Doctrine\ORM\EntityManager $em */
$em->getConfiguration()->setDefaultQueryHint(
    Query::HINT_CUSTOM_TREE_WALKERS,
    ['YourWalkerFQClassName']
)

用我能想到的最简单的术语来说:walker(在条令中)遍历使用DQL构建的查询的每个节点,并为该节点生成适当的SQL。自定义walker允许您修改查询(在查询中添加/编辑select、from、join、where子句)…这是否像条令过滤器一样具有包容性(如果您能够加入它们的话)?我看到的唯一缺点(除了有点不雅)将是未命中,是否所有内容都通过createQueryBuilder?所有生成的查询都会-但findBy方法或createQuery是否也会触及这些内容,除非您改变它们的工作方式?我对另一个类似问题采取的一种方法是创建一个“基本”管理器类,并让我所有其他实体的管理器类扩展该类,只要当您相对虔诚地使用管理器方法(应该鼓励使用这种模式)时,您可以对重用的方法进行重大的全局更改,而无需定义自定义实体管理器。
<?php
/** @var \Doctrine\ORM\EntityManager $em */
$em->getConfiguration()->setDefaultQueryHint(
    Query::HINT_CUSTOM_TREE_WALKERS,
    ['YourWalkerFQClassName']
)