Querybuilder na filtrovanie pomocou AND podmienky

Br0visT
Člen | 17
+
0
-

Zdravím, mám problém s Querybuilderom v Doctrine. Potrebujem filtrovať články podľa zaškrtnutých tagov. Mám tam také zaklikávatko ktoré rozoznáva filtrovanie medzi AND a OR, teda uvediem príklad.
Mám zaškrtnuté OR filtrovanie. Zaškrtnem tagy: korona, auta, peniaze. Článok môže mať samozrejme viac tagov. Avšak OR filter vyselektuje všetky články, ktoré majú aspoň jeden (alebo viacero z týchto tagov).

A teraz by som potreboval AND filtrovanie. Zaškrtnem tagy korona, auta, peniaze a vyselektuje mi len tie články, ktoré obsahujú všetky 3 tagy.

Aby som trošku popísal entity, tak:
Článok je vlastná entita, ktorá ale patrí pod entitu Produkt (je childom Produktu).
Produkt má id a parent_id, keďže články môžu byť aktualizované a je treba ukladať každú jednu aktualizáciu.
Na stránke sa zobrazujú vždy iba najnovšie aktualizácie článkov (pre usera).
Produkt má ManyToMany relation s entitou Tag.

Keďže OR filtrovanie mi funguje, najprv tu napíšem querybuilder na to:

private function addFilterOr(QueryBuilder $qb, array $tags)
    {
        return $qb->leftJoin('a.tags', 't')
            ->leftJoin('a.parent', 'p')
            ->addSelect('p')
            ->leftJoin('p.tags', 'pt')
            ->addSelect('pt')
            ->andWhere('t IN(:tags) OR pt IN (:tags)')
            ->setParameter('tags', $tags);
    }

Samotne getovanie článkov podľa tohto filtra alebo filtra AND je nepodstatné, to je vyriešené dobre.
Ak sa vam nieco nezda na tomto filtri, skuste ma opravit, ale momentalne je to funkcne.

A kedže vo filtri AND potrebujem foreachovať podmienky (kedže tam musí byť kvázi jeden stlpec rovný viacerým hodnotám), tak som to skúsil riešiť takto:

public function addFilterAnd(QueryBuilder $qb, array $tags)
    {
        $qbAnd = $qb->leftJoin('a.tags', 't')
            ->leftJoin('a.parent', 'p')
            ->addSelect('p')
            ->leftJoin('p.tags', 'pt')
            ->addSelect('pt')
            ->andWhere('t IN(:tags) OR pt IN (:tags)')
            ->setParameter('tags', $tags);
        foreach ($tags as $k => $t) {
            $qbAnd->andWhere('pt IN(:tagNew'.$k.')')
                ->setParameter('tagNew'.$k, $t);
        }
        return $qbAnd;
    }

Kvázi tá prvá časť po foreach, je OR filter, takže nájde mi články, kde je aspoň jeden z tagov. Avšak ja potrebujem aby tam boli všetky zaškrtnuté, preto ich loopujem pomocou všetkych tagov.
Nebudem moc vysvetľovať, čo to robí, pretože to jednoducho robí blbosti – filtruje si to kvázi jak chce == jak ja nechcem :D. Neviem čo robím zle, najlepšie by mi to bolo vysvetliť opravením kódu, keďže na terminológiu nie som moc frajer :D

Ďakujem za každú pomoc.

David Matějka
Moderator | 6445
+
0
-

https://stackoverflow.com/…s-al/3267635#…

do doctrine qb uz to snad prepises :)

Br0visT
Člen | 17
+
0
-

David Matějka napsal(a):

https://stackoverflow.com/…s-al/3267635#…

do doctrine qb uz to snad prepises :)

Tak moc nerozumiem, aky je rozdiel oproti mojmu kodu kedze on dava rovno do zatvorky viacero stringov a ja to selektujem dynamicky, teda loopujem prvky arrayu ktore vkladam do andWhere. Radsej by som to teda videl spravne v qb.

David Matějka
Moderator | 6445
+
+2
-

dulezita je ta cast

GROUP BY o.id
  HAVING COUNT(DISTINCT t.name) = 2

jelikoz zadny radek nevyhovuje podmince, ze ma vsechny tagy – dojde totiz dle spojovaci tabulky k roznasobeni radku. ty pak vyfiltrujes ty, ktery splnujou tagy, zgroupujes dle clanku a pres having vyfiltrujes groupy, ktere maji tolik polozek, jako je pocet tagu, ktery potrebujes