Symfony 实体存储库中的 Doctrine QueryBuilder 摘要函数?

Doctrine QueryBuilder summary functions in Symfony entity repositories?

有什么方法可以让我在 Doctrine 的 QueryBuilder 中使用 min()(或等效的)?

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

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

为了在发票级别访问它,我一直在尝试通过我的 InvoiceRepository 来完成它,但我不清楚 if/how 这可以使用 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());

我的查询生成器:

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();
}

我不知道为什么这个问题还没有得到解答,但你应该能够很好地使用这些聚合函数。

The following aggregate functions are allowed in SELECT and GROUP BY clauses: 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() OK。

我会将您的函数重写为:

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 方法来循环支付,但我个人会在发票完全支付时将其设置为布尔值或日期时间。

然后在 twig 中你可以做这样的事情:

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

这应该可以很容易地获得您想要的布局。