Symfony实体存储库中的Doctrine QueryBuilder汇总函数?

时间:2016-05-31 08:28:06

标签: doctrine-orm doctrine symfony query-builder

我可以在Doctrine的QueryBuilder中使用min()(或等效的)吗?

我正在处理的页面显示了当前(或模拟)用户的发票表。它的每张发票都有一行,并且嵌套了任何关联付款的可折叠行(见下图)

我的问题是,在我的树枝模板中,如果任何付款尚未获得批准,我需要能够在发票级别进行识别。如果任何付款未获批准,那么我需要标记付款和与之相关的发票行。例如,在下面的示例中," Invoice#1"是黄色的,因为它有一个嵌套的#34;付款#2"记录为黄色(未批准):

Invoice/Payment image

要在发票级别访问此内容,我一直在尝试通过我的InvoiceRepository进行访问,但我不清楚是否/如何使用QueryBuilder完成此操作。我不知何故需要anyToBeApproved(这不是我的发票实体的属性),并且还包含付款信息:

select a.*, min(b.approved) as anyToBeApproved
from Invoice a
left join Payment b
on a.invoice_id=b.id
where a.member_id=$Uid
group by a.id

我的控制器:

$invoices = $em->getRepository('AppBundle:Invoice')->OutstandingForUser($this->getUser()->getId());

我的QueryBuilder:

public function OutstandingForUser($Uid)
{
    return $this->createQueryBuilder('i')
        ->select('i')
        ->leftJoin('i.member_id','m')
        ->leftJoin('i.payment_ids','p')
        ->andwhere('m.member_id = :MemberId' )
        ->setParameter('MemberId',$Uid)
        ->getQuery()
        ->getResult();
}

1 个答案:

答案 0 :(得分:0)

我不知道为什么这还没有得到解答,但你应该可以正常使用这些聚合函数。

  

SELECT和GROUP BY中允许使用以下聚合函数   子句:AVG,COUNT,MIN,MAX,SUM

请参阅文档:http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html#aggregate-functions

您可以在querybuilder中使用聚合函数 - > select()确定。

我将您的功能重写为:

public function OutstandingForUser($Uid)
{
    return $this->createQueryBuilder('i')
        ->select('i, min(p.approved) as anyToBeApproved')
        ->leftJoin('i.member','m', 'WITH', 'm.member_id = :MemberId') // this works better with not actually constraining your left join, otherwise you might as well just use innerJoin
        ->leftJoin('i.payment','p') 
        ->groupBy('i.id')
        ->setParameter('MemberId',$Uid)
        ->getQuery()
        ->getResult();
}

这是另一种方法,因为您似乎还想要所有发票行。

将您的获取功能更改为:

public function OutstandingForUser($Uid)
{
    return $this->createQueryBuilder('i')
        ->select('i, p, m') // may as well pre-fetch all entities
        ->join('i.member','m') // member is surely mandatory? so no left join required
        ->leftJoin('i.payment','p') // payments may not be present, so left join
        ->where('m.member_id = :MemberId')
        ->setParameter('MemberId',$Uid)
        ->getQuery()
        ->getResult();
}

然后在您的发票实体中执行类似

的操作
    public function hasUnapprovedPayments () {

        foreach ($this->getPayments() as $payment) {

            if (!$payment->approved()) {

                return true;
            }
        }

        return false;
    }

    public function hasPayments () {

        return !$this->getPayments()->isEmpty(); // assuming doctrine collection
    }

这些功能非常快,因为你已经在上面的函数中对实体进行了水合。

您还可以添加一个循环付款的类似isFullyPaid方法,但我个人会在发票完全支付时设置的发票上设置一个bool或datetime。

然后在树枝上你可以做类似的事情:

    {% for invoice in invoices %}
      {% if invoice.hasUnapprovedPayments %} do something {% endif %}
      {% if invoice.hasPayments %} do something {% endif %}
      {# loop through all your payments etc #}
    {% endfor %}

这样可以很容易地获得所需的布局。