Как сделать правильный построитель запросов с помощью подзапросов - PullRequest
1 голос
/ 24 марта 2020

У меня есть таблица с платежами, и мне нужно получить все столбцы таблицы и четыре пользовательских столбца. Мой текущий рабочий запрос:

$this->createQueryBuilder('payments')
            ->select('DATE_FORMAT(payments.createdAt, \'%Y-%m\') as date_ym, payments')
            ->addSelect('(SELECT SUM(ps1.summ) FROM App\Entity\Payments ps1 WHERE ps1.isPayed = 1 AND ps1.type = 1 AND ps1.user = :user AND DATE_FORMAT(ps1.createdAt, \'%Y-%m\') = date_ym) as pay_in')
            ->addSelect('(SELECT COUNT(ps3.id) FROM App\Entity\Payments ps3 WHERE ps3.isPayed = 1 AND ps3.type = 1 AND ps3.user = :user AND DATE_FORMAT(ps3.createdAt, \'%Y-%m\') = date_ym) as pay_in_count')
            ->addSelect('(SELECT SUM(ps2.summ) FROM App\Entity\Payments ps2 WHERE ps2.isPayed = 1 AND ps2.type != 1 AND ps2.user = :user AND DATE_FORMAT(ps2.createdAt, \'%Y-%m\') = date_ym) as pay_out')
            ->addSelect('(SELECT COUNT(ps4.id) FROM App\Entity\Payments ps4 WHERE ps4.isPayed = 1 AND ps4.type != 1 AND ps4.user = :user AND DATE_FORMAT(ps4.createdAt, \'%Y-%m\') = date_ym) as pay_out_count')
            ->where('payments.user = :user')
            ->setParameter('user', $user)
            ->andWhere('payments.isPayed = 1')
            ->andWhere('payments.createdAt >= :days')
            ->setParameter('days', $days->format('Y-m-d'))
            ->orderBy('date_ym', 'DESC')
            ->getQuery()->getResult();

В контроллере я делаю:

$payments = $em->getRepository(Payments::class)->myFunc($user, 180);
$paymentsTable = [];
foreach ($payments as $payment) {
    $date = $payment['date_ym'];
    /** @var PaySchet $pay */
    $pay = $payment[0];
    $paymentsTable[$date]['pay_in'] = $payment['pay_in'];
    $paymentsTable[$date]['pay_in_count'] = $payment['pay_in_count'];
    $paymentsTable[$date]['pay_out'] = $payment['pay_out'];
    $paymentsTable[$date]['pay_out_count'] = $payment['pay_out_count'];
    $paymentsTable[$date]['data'][$pay->getType()][] = $pay;
}

Я получаю следующий результат:

array:3 [▼
  "2020-03" => array:5 [▼
    "pay_in" => "15"
    "pay_in_count" => "1"
    "pay_out" => "230"
    "pay_out_count" => "1"
    "data" => array:1 [▼
      0 => App\Entity\Payments {#2288 ▶}
    ]
  ]
  "2020-01" => array:5 [▼
    "pay_in" => "2620"
    "pay_in_count" => "5"
    "pay_out" => "13732"
    "pay_out_count" => "3"
    "data" => array:3 [▼
      0 => App\Entity\Payments {#2267 ▶}
      1 => App\Entity\Payments {#2257 ▶}
      2 => App\Entity\Payments {#2251 ▶}
    ]
  ]
  "2019-12" => array:5 [▶]
]

Это правильный вывод, но как можно Я улучшаю свой DQL-запрос? Мне не нравится, как это выглядит сейчас.

1 Ответ

0 голосов
/ 24 марта 2020

Вы можете создать несколько построителей запросов и использовать их в основном. Просто знайте, что вы должны использовать уникальные псевдонимы сущностей во всех них. Вы можете использовать эти псевдонимы для ссылки на сущности из других построителей запросов.

/** @val $em EntityManager */

$query1 = $em->createQueryBuilder()->from(Payments::class, 'ps1')->select('')->getDql();
$query2 = $em->createQueryBuilder()->from(Payments::class, 'ps2')->select('')->getDql();
$query3 = $em->createQueryBuilder()->from(Payments::class, 'ps3')->select('')->getDql();
$query4 = $em->createQueryBuilder()->from(Payments::class, 'ps4')->select('')->getDql();

// All value binds need to be on the main query builder
$query = $qb->select('DATE_FORMAT(payments.createdAt, \'%Y-%m\') as date_ym, payments')
    ->addSelect($query1)
    ->addSelect($query2)
    ->addSelect($query3)
    ->addSelect($query4)
    ->from(Payments::class, 'payments')
    ->where('payments.user = :user')
    ->setParameter('user', $user)
    ->andWhere('payments.isPayed = 1')
    ->andWhere('payments.createdAt >= :days')
    ->setParameter('days', $days->format('Y-m-d'))
    ->orderBy('date_ym', 'DESC')
    ->getQuery()
    ->getResult();
...