У меня довольно сложный объект 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, которое было бы очень трудно прочитать?