无法从表单构建器中的存储库获取getEntityManager

时间:2014-07-11 16:01:43

标签: symfony doctrine dql formbuilder

在Symfony2中的表单类型中,我想包含一个带有查询构建器的实体字段,以便选择要显示的行。 我的查询很复杂,我无法找到一种方法来使用查询构建器,我想使用DQL。 不幸的是,我无法$repository->createQuery(...)$repository->getEntityManager()->createQuery()。只有$repository->createQueryBuilder(...)有效。 有办法解决这个问题吗?

顺便说一下,如果你碰巧找到一种更聪明的方式来执行我的SQL请求,那将非常有用(但这不是这个问题的主题!)

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $user = $this->user;
    $builder
        ->add('friend', 'entity',
            array(
                'class' => 'MyappUserBundle:User',
                'label' => 'User',
                'query_builder' => function(EntityRepository $repository) use ($user) {
                    $query = $repository->getEntityManager()->createQuery("
                        SELECT u
                            FROM MyappUserBundle:User u
                        WHERE
                            u.id NOT IN (SELECT friend FROM MyappUserBundle:Friendrequest WHERE user = :user)
                        AND 
                            u.id NOT IN (SELECT user FROM MyappUserBundle:Friendrequest WHERE friend = :user)
                        AND 
                            u.id != :user
                        ")
                        ->setParameter('user', $user)
                        ;

                    return $query;
                }
                )
            )
        ;
}

1 个答案:

答案 0 :(得分:5)

如何解决query_builder问题(以及一般问题)

我们知道我们可以访问您实体的EntityRepository类。因此,我们可以轻松找到哪些方法可公开访问。

因此,我们可以在Google上搜索“doctrine api entityrepository”,它会引导我们the EntityRepository class API documentation on the doctrine site

在该页面上,我们可以找到可公开访问的方法,您可以找到有关创建查询的3种方法,其中一种方法是createNativeNamedQuery

根据文档,此方法返回Doctrine\ORM\NativeQuery的实例,单击它会导致另一个页面包含其他方法。您可以看到NativeQuery具有setQuery方法,并从Doctrine\ORM\AbstractQuery继承了其他方法列表。

现在,我们可能拥有我们需要的所有信息,因此我们可以提出一个可能有效的解决方案(如果没有,那么我们可能真的非常接近)。

// The closure expects \Doctrine\ORM\QueryBuilder to be returned
// so we need to create a named query first then create a list of ids
// and pass it to a query builder.
'query_builder' => function(EntityRepository $repository) use ($user) {
    // Query for user ids with sub queries
    $results = $repository
        ->createNativeNamedQuery('u')
        ->setSQL("
            SELECT u.id
            FROM user AS u
            WHERE u.id NOT IN (
                SELECT friend FROM friend_request_table WHERE user = :user
            )
            AND u.id NOT IN (
                SELECT user FROM friend_request_table WHERE friend = :user
            )
            AND u.id != :user
        ")
        ->setParameter('user', $user->getId())
        ->getArrayResult();

    // Build an array of IDs
    $ids = array_map(function ($row) {
        return $row['id'];
    }, $results);

    // Returns a QueryBuilder
    return $repository->createQueryBuilder('u')
        ->where('u.id IN (:ids)')
        ->setParameter('ids', $ids);
}

缺点是执行了两个查询。闭包期望返回QueryBuilder,因此我们需要先创建一个原始查询,然后将结果传递给QueryBuilder

最重要的是,本机查询意味着原始SQL查询,因此您不能使用实体注释,并且不同数据库可能也不支持您的查询。

如果你喜欢我的观点,我认为你可以重构你的查询并删除子查询。删除子查询并将其结果作为参数传递将允许您使用DQL,因此支持更多类型的数据库。