具有X个关系属性的动态过滤器查询 - Doctrine Symfony2

时间:2015-03-10 08:18:35

标签: php mysql symfony doctrine query-builder

我现在被困了12个小时。我的问题是根据XY参数构建过滤查询。

背景:

档案: 项目可以具有许多属性,每个属性仅与一个项目相关。

属性[id,type_id,value_id,item_id]:

  1. type(与AttributeType [id,name]的关系)ex。:operating.system(column" name" AttributeType)
  2. value(与AttributeValue [id,value]的关系)例如:Windows Phone 8(列"值"属性值)
  3. 情景:

    在我列出项目的页面上,有属性过滤器

    • 操作系统

      • {checkbox name =" a [type.id] [0]" value =" [value.id]"} Windows Phone 8
      • {checkbox name =" a [type.id] [1]" value =" [value.id]"} Android
    • Cpu Frequncy

      • {select with options name =" a [type.id] [0]"} {option value =" a [type.id] [value.id]" } {/选择}

    当用户提交搜索表单时,我循环throug属性,并动态添加andWhere()。查询看起来像:

    select .... from items i left join attributes a on i.id = a.item_id WHERE
    a.type_id=typeid and a.value_id=valueid
    

    当我这样做时只有1个参数,但是有2个参数

    a.type_id=typeid AND a.value_id=valueid AND a.type_id=typeid AND a.value_id=valueid.....
    

    结果为0

        a.type_id=typeid AND a.value_id=valueid OR a.type_id=typeid AND a.value_id=valueid....
    

    返回至少1个参数匹配的每个项目

    我需要的是构建查询,以获得所有参数匹配的项目。像子查询循环一样,匹配第一个搜索属性而不是匹配结果匹配第二个,第三个,......最后得到项目的结果。

    谢谢

    -----编辑------

    我继续,我正在创建像

    这样的子查询
    $sAttrTypes = (isset($_GET["a"]) ? $_GET["a"] : array());
    
            $qb = $this->em()->createQueryBuilder("p");
            $qb->select(array("i", "a"))->from("ErikOfferBundle:Item", "i")->leftJoin("i.attributes", "a");
    
            $i = 0;
            $subquery_0 = false;
            foreach ($sAttrTypes as $aTypeId => $aValues) {
                if (!$aValues) {
                    continue;
                }
    
                $ids = false;
    
                foreach ($aValues as $value) {
                    $ids[] = $value[0];
                }
    
                $query = $this->em()->createQueryBuilder("p_" . $i);
                ${"subquery_" . $i} = $query->select(array("i$i", "a$i"))
                        ->from("ErikOfferBundle:Item", "i$i")
                        ->leftJoin("i$i.attributes", "a$i");
    
                if (count($ids) < 2) {
                    ${"subquery_" . $i}->where($qb->expr()->eq("a$i.value", $ids[0]));
                } else {
                    ${"subquery_" . $i}->where($qb->expr()->in("a$i.value", $ids));
                }
    
                if ($i > 0) {
                    ${"subquery_" . ($i - 1)}->andWhere($qb->expr()->in("i" . ($i - 1) . ".id", ${"subquery_" . $i}->getDql()));
                }
    
                echo "subquery_" . $i. ": " .${"subquery_" . $i}."<br/>";
                $i++;
            }
    
            $qb->where($qb->expr()->in("i.id", ${"subquery_0"}->getDql()));
            echo "Final query: " . $qb->getDql();
            $items = $qb->getQuery()->getResult();
    

    创建查询:

    subquery_0: SELECT i0, a0 FROM ErikOfferBundle:Item i0 LEFT JOIN i0.attributes a0 WHERE a0.value = 1
    subquery_1: SELECT i1, a1 FROM ErikOfferBundle:Item i1 LEFT JOIN i1.attributes a1 WHERE a1.value = 4
    Final query: SELECT i, a FROM ErikOfferBundle:Item i LEFT JOIN i.attributes a WHERE i.id IN(SELECT i0, a0 FROM ErikOfferBundle:Item i0 LEFT JOIN i0.attributes a0 WHERE a0.value = 1 AND i0.id IN(SELECT i1, a1 FROM ErikOfferBundle:Item i1 LEFT JOIN i1.attributes a1 WHERE a1.value = 4)) 
    

    它得到异常&#34; [语法错误]第0行,第88栏:错误:预期的Doctrine \ ORM \ Query \ Lexer :: T_FROM,得到了&#39;&#39;&#34; < / p>

    col 88是&#34; i0,a0&#34;在第一个子查询中

1 个答案:

答案 0 :(得分:1)

通过在子查询中仅选择1个表来解决

最终草案代码:

$sAttrTypes = (isset($_GET["a"]) ? $_GET["a"] : array());

$i = 0;
$subquery_0 = false;
    foreach ($sAttrTypes as $aValues) {

        if (!$aValues[1]) {
            continue;
        }

        if (count($aValues) == 1 && ($aValues[1] == 0 || $aValues[1] == "")) {
            continue;
        }

        $query = $this->em()->createQueryBuilder();
        ${"subquery_" . $i} = $query->select(array("i$i"))
                ->from("ErikOfferBundle:Item", "i$i")
                ->leftJoin("i$i.attributes", "a$i")
                ->where((count($aValues) == 1 ?
                        $query->expr()->eq("a$i.value", $aValues[1]) :
                        $query->expr()->in("a$i.value", $aValues)));
        if ($i > 0) {
            ${"subquery_" . (0)}->andWhere($query->expr()->in("i0.id", ${"subquery_" . $i}->getDQL()));
        }
        $i++;
    }


$qb = $this->em()->createQueryBuilder();
$qb->select(array("i", "a"))->from("ErikOfferBundle:Item", "i")->leftJoin("i.attributes", "a");
    if ($subquery_0) {
        $qb->andWhere($qb->expr()->in("i.id", $subquery_0->getDQL()));
    }
$items = $qb->getQuery()->getResult();