将字段聚合到Doctrine2中的Fetched Objects

时间:2014-12-16 18:25:35

标签: php mysql symfony doctrine-orm

修改

  • 进一步研究:看起来答案取决于changin默认Hydrator的定制化。 Doctrine2允许您通过将其名称作为参数发送来更改它:

    $查询 - >的getResult( 'CustomHydrator');

别忘了先在config.yml文件中注册它:

doctrine:
      orm:
         hydrators:
                 CustomHydrator: \your\bundle\Hydrators\CustomHydrator
  • Blog和Comment实体之间的关系是一对多的。 1博客有N评论

在研究了如何在Doctrine 2中为获取的对象添加额外字段后,我找到了Aggregate Fields,这是一篇很好的文章,但只是谈论从一个帐户中获得平衡,它从不说出我们应该做什么在使用一系列帐户时,它可能听起来很傻但让我解释一下我的情况。

在我的情况下,不是关于帐户和条目,而是关于博客和评论。

我要做的是列出一些博客,只显示它有多少评论而不加载任何评论信息,换句话说我想将此查询翻译成Doctrine2世界。

'SELECT b.*, COUNT( b.id ) AS totalComments FROM  `blogs` b LEFT JOIN comments c ON b.id = c.blog_id GROUP BY b.id LIMIT 8'

我期望的结果是博客对象数组,其中totalComments属性设置正确,如下所示:

array (size=8)
  0 => 
    object Blog
      'id' => int 330
      'title' => string 'title blog'

      // Added field, not visible in table DB. Came through query COUNT() statement
      'totalComments' => int 5 
      // ... more attributes

  1 => ...
  //more object blogs
  );

我无法实现这一点,我能做的最好的就是:

创建和获取查询:

$qb = $this->createQueryBuilder('b')
        ->select('b, c')
        ->addSelect('count(b.id) as nComments')
        ->leftJoin('b.comments', 'c')
        ->groupBy('b.id')

        return $qb->getQuery()->getResult();

我得到的结果是一个数组数组,其中位置0有博客对象和位置“totalComments”

// var_dump($result)
array (size=8)
  0 => 
    array(2) =>
      0 =>  
          object Blog
          'id' => int 330
          'title' => string 'title blog'
          // ... more attributes

      "totalComments" => int 5

  1 => ...
  );

我也尝试制作自己的Hydrator,但我刚开始使用Doctrine2,发现自己有点迷失。

我希望已经足够清楚了。如果需要,我可以提供任何其他信息。

提前致谢!

2 个答案:

答案 0 :(得分:1)

您必须为所需的字段命名,或者具有混合结果(如第二个示例)。所以对于平面阵列:

$qb = $this->createQueryBuilder('b')
    ->select('b.title, b.author')
    ->addSelect('count(c.id) as nComments')
    ->leftJoin('b.comments', 'c')
    ->groupBy('b.id')

return $qb->getQuery()->getArrayResult();

或混合结果:

$qb = $this->createQueryBuilder('b')
    ->select('b')
    ->addSelect('count(c.id) as nComments')
    ->leftJoin('b.comments', 'c')
    ->groupBy('b.id')

return $qb->getQuery()->getResult();

答案 1 :(得分:0)

几天后我想出了这个解决方案。

我必须在我的博客实体类及其get / set方法中添加totalComments属性,并调整一下我的getLatestBlogs函数:

function getLatestBlogs(){
    $qb = $this->createQueryBuilder('b')
        ->select('b, c')
        ->addSelect('count(b.id) as totalComments')
        ->leftJoin('b.comments', 'c')
        ->groupBy('b.id');
    $result = $qb->getQuery()->getResult();

    //tweaking original result
    foreach($result as $row){ 
        $row[0]->setTotalComments($row['totalComments']);
        $blogList[] = $row[0];
    }
    return $blogList;
}

这样做我终于得到了一个简单的博客对象数组,它只需要额外的循环。

在此之后,我意识到拥有一个可以使用任何实体的通用函数会很好,所以我创建了下一个函数:

function fixResult($qResult){ //Receives $qb->getQuery()->getResult();
    if(is_array($qResult)){
        $list = array();
        $keys = array_keys($qResult[0]); //Getting all array positions from first row
        $object = $qResult[0][0]; //Getting the actual object fetched
        foreach($keys as $key){ //Searching for existing set methods in the Object
            $method = "set".ucfirst($key);
            if(method_exists($object,$method))
                $methods[$key] = $method;
        }
        foreach($qResult as $row){ //Calling set methods for every row fetched and storing into a new array
            foreach($methods as $key => $met){
                $row[0]->$met($row[$key]);
                $list[] = $row[0];
            }
        }
        return $list;
    }
    else return false;
}

我希望别人觉得它很有用。