如何以正确的方式处理复杂的Doctrine2 QuerBuilder中的可选比较?

时间:2019-04-18 11:43:47

标签: php doctrine-orm

我有一个相当复杂的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()不为null时,我将插入一个可选的$openBefore,但是此QueryBulder太复杂了,无法采用这种方式。

因此,就目前而言,我设定了一个很晚的日期(因为没有new \DateTime('eternity')

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

那感觉不对(或者只是假设一个遥远的未来,这变得古怪)。

所以我想要的基本上是,如果$qb->expr()->lte('beginAt', ':openBefore')为null,则$openBefore始终为true。但是实际上,它总是错误的,我认为这是正确的行为。

一种解决方案是编写处理$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表达式的多个变体的情况下,使比较成为可选的正确而又可靠的方法是什么?

0 个答案:

没有答案