Как правильно обрабатывать необязательные сравнения в сложном Doctrine2 QuerBuilder? - PullRequest
0 голосов
/ 18 апреля 2019

У меня довольно сложный объект Doctrine QueryBuilder - это хранилище, подобное этому (на самом деле это еще более сложная, это упрощенная версия):

/** @var \DateTimeInterface $openAfter */
/** @var \DateTimeInterface $openBefore */
$qb->where(
  $qb->expr()->andX(
    $qb->expr()->isNotNull('beginAt'),
    $qb->expr()->orX(
      $qb->expr()->andX(
        $qb->expr()->gte('beginAt', ':openAfter'),
        $qb->expr()->lte('beginAt', ':openBefore')
      ),
      $qb->expr()->andX(
        $qb->expr()->lt('beginAt', ':openAfter'),
        $qb->expr()->orX(
          $qb->expr()->isNull('finishedAt'),
          $qb->expr()->gte('finishedAt', ':openAfter')
        )
      )
    )
  )
);
$qb->setParameter('openAfter', $openAfter);
$qb->setParameter('openBefore', $openBefore);

Но теперь я хочу разрешить $openBefore необязательно, поэтому интервал может быть открыт с правой стороны.В простых объектах QueryBuilder я бы вставил необязательный andWhere(), когда $openBefore не равен нулю, но этот QueryBulder слишком сложен, чтобы идти по этому пути.

Итак, сейчас я установил очень позднюю датудостичь этого (поскольку нет new \DateTime('eternity'):

if (null === $openBefore) {
  $openBefore = new \DateTime('9999-12-31 23:59:59');
}

Это не кажется правильным (или просто предположить, что будущее далеко-далеко, где это становится странным).

Так чтоЯ хочу, в основном, чтобы $qb->expr()->lte('beginAt', ':openBefore') всегда было истинным, если $openBefore равно нулю. Но на самом деле это всегда ложное значение, которое я принимаю за правильное поведение.

Решением было бы написание вариантоввыражения, имеющего дело с $openBefore, и сохраните его в переменной, подобной этой:

/** @var \DateTimeInterface $openAfter */
/** @var \DateTimeInterface|null $openBefore */

if (null === $openBefore) {
  $beginAtIntervalExpr = $qb->expr()->gte('beginAt', ':openAfter');
}
else {
  $beginAtIntervalExpr = $qb->expr()->andX(
    $qb->expr()->gte('beginAt', ':openAfter'),
    $qb->expr()->lte('beginAt', ':openBefore')
  );
}

$qb->where(
  $qb->expr()->andX(
    $qb->expr()->isNotNull('beginAt'),
    $qb->expr()->orX(
      $beginAtIntervalExpr,
      $qb->expr()->andX(
        $qb->expr()->lt('beginAt', ':openAfter'),
        $qb->expr()->orX(
          $qb->expr()->isNull('finishedAt'),
          $qb->expr()->gte('finishedAt', ':openAfter')
        )
      )
    )
  )
);
$qb->setParameter('openAfter', $openAfter);
if (null !== $openBefore) {
  $qb->setParameter('openBefore', $openBefore);
}

Это довольно нелегко и трудно читать, и ухудшается с большим количеством этих необязательных параметров. Так что, если также $openAfter должно быть необязательным, что имеет место в моем приложении (и причина для решения этого с этими острыми объектами DateTime.

Так что вопрос: каков правильный и неудачный способ сделать сравнение необязательным безнаписать несколько вариантов одного и того же выражения QueryBuilder, которое было бы очень трудно прочитать?

...