Doctrine createQueryBuilder有多个条件,其中语句有点笨拙

时间:2013-09-10 11:20:02

标签: php mysql symfony doctrine

我的itemid和类别ID都是有条件的。如果没有给出,则所有项目都显示为最新的拳头。如果给出itemid,则仅显示id低于给定id的项目(用于分页)。如果给出类别ID,则仅显示特定类别中的项目,并且如果两者都被给出,则仅给出项目ID小于itemid的特定类别中的项目(按类别下一页的项目)。

因为参数是有条件的,所以在构建SQL字符串时会得到很多if语句,这取决于params(伪代码我用PHP填充了我的美元符号):

if itemid ' where i.iid < :itemid '
if catid 
  if itemid
     ' and c.id = :catid'
  else
     ' where c.id = :catid'  
  end if
end if

如果给出更多可选参数,这将变得非常混乱,所以我想我会尝试使用createQueryBuilder。希望有这样的事情:

    if($itemId!==false){
        $qb->where("i.id < :id");
    }
    if($categoryId!==false){
        $qb->where("c.id = :catID");
    }

遗憾的是,情况并非如此,最后的地方overwrite the first one

我想出的是(在Symfony2中):

private function getItems($itemId,$categoryId){
    $qb=$this->getDoctrine()->getRepository('mrBundle:Item')
      ->createQueryBuilder('i');
    $arr=array();
    $qb->innerJoin('i.categories', 'c', null, null);
    $itemIdWhere=null;
    $categoryIdWhere=null;
    if($itemId!==false){
        $itemIdWhere=("i.id < :id");
    }
    if($categoryId!==false){
        $categoryIdWhere=("c.id = :catID");
    }
    if($itemId!==false||$categoryId!==false){
        $qb->where($itemIdWhere,$categoryIdWhere);
    }
    if($itemId!==false){
        $qb->setParameter(':id', $itemId);
    }
    if($categoryId!==false){
        $arr[]=("c.id = :catID");
            $qb->setParameter(':catID', $categoryId);
    }
    $qb->add("orderBy", "i.id DESC")
        ->setFirstResult( 0 )
        ->setMaxResults( 31 );

我并不完全信任$qb->where(null,null),尽管它目前没有创建错误或意外结果。看起来这些参数被忽略了。无法在文档中找到任何内容,但空字符串会生成错误$qb->where('','')

我仍然看起来有点笨拙,如果我可以使用多个$qb->where(condition)那么每个可选项只需要一个if语句$qb->where(condition)->setParameter(':name', $val);

所以问题是:有更好的方法吗?

我想如果doctrine有一个函数来逃避字符串我可以摆脱第二个if语句轮次(不确定恶意用户是否可以在允许sql注入的不同字符集中发布一些东西):

private function getItems($itemId,$categoryId){
    $qb=$this->getDoctrine()->getRepository('mrBundle:Item')
      ->createQueryBuilder('i');
    $arr=array();
    $qb->innerJoin('i.categories', 'c', null, null);
    $itemIdWhere=null;
    $categoryIdWhere=null;
    if($itemId!==false){
        $itemIdWhere=("i.id < ".
           someDoctrineEscapeFunction($id));
    }

感谢您阅读本文,希望您能够启发我。

[UPDATE]

我目前正在使用虚拟where语句,因此可以使用andWhere添加任何其他条件语句:

    $qb->where('1=1');// adding a dummy where
    if($itemId!==false){
        $qb->andWhere("i.id < :id")
          ->setParameter(':id',$itemId);
    }
    if($categoryId!==false){
        $qb->andWhere("c.id = :catID")
          ->setParameter(':catID',$categoryId);
    }

1 个答案:

答案 0 :(得分:1)

如果要使用更通用的方法来处理此问题,可以创建过滤器。 Doctrine 2.2提供了一个过滤系统,允许开发人员将SQL添加到查询的条件子句中

了解有关filters的更多信息,但我正以与您展示的方式类似的方式处理此问题