🎻

[Doctrine] QueryBuilderでIN句に配列を渡す/配列プロパティが目的の値を含んでいるかどうかで絞り込む

2020/06/20に公開

備忘録です。

QueryBuilderでIN句に配列を渡す

一見普通っぽいけどバギーなやり方(お勧めしない)

use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Types\Types;

$ids = [1,2,3,4,5];

$qb = $fooRepository->createQueryBuilder('f');
$qb
    ->andWhere('f.id IN (:ids)')
    ->setParameter('ids', $ids, Types::ARRAY)
    // または
    ->setParameter('ids', $ids, Connection::PARAM_INT_ARRAY)
    ->getQuery()
    ->getResult()
;

参考:

パラメータが配列じゃないときと同じ書き方なのでこれが標準的なやり方のような気もするのですが、Doctrineの公式ドキュメント で言及されておらず、標準のやり方が不明です😓

実際に使ってみるとなんか正常に動かない感じがしているので、個人的にはお勧めしません🙄

https://twitter.com/ttskch/status/1276032724403273729

バギーじゃないやり方(お勧め)

$ids = [1,2,3,4,5];

$qb = $fooRepository->createQueryBuilder('f');
$qb
    ->andWhere($qb->expr()->in('f.id', $ids))
    ->getQuery()
    ->getResult()
;

または

$ids = [1,2,3,4,5];

$expr = $this->getEntityManager()->getExpressionBuilder();

$fooRepository->createQueryBuilder('f')
    ->andWhere($expr->in('f.id', $ids))
    ->getQuery()
    ->getResult()
;

参考:DoctrineでIN句に配列渡す方法。 - Qiita

この方法は、個人的な感覚として特に何も心配しなくても常に正常に動いてくれています。

なお、1つ注意点があって、 $ids が空の配列だとSQLレベルのエラーになります。

参考:$query->expr()->in and notIn function does not support empty array · Issue #8033 · doctrine/orm

なので、渡す配列が空になり得る場合は、ちょっと強引ですが以下のように対処しておくとよいです。

->andWhere($ids ? $expr->in('f.id', $ids) : '1=0')

配列が空の場合には '1=0' という必ず false になる式を andWhere() に渡している、というものです。(もっといい方法ご存知の方は DM ください🙏)

プロパティの中身が配列のときに、その配列が目的の値を含んでいるかどうかで絞り込む

一瞬、IN句を使って右左辺を入れ替えればいいのかな?とか思ってしまいそうですが、この場合は普通に like を使えばいいだけです✋

$postRepository->createQueryBuilder('p')
    ->andWhere('p.tags like :targetTag')
    ->setParameter('targetTag', sprintf('%%%s%%', $targetTag))
    ->getQuery()
    ->getResult()
;

参考:php - Is there a way to query if array field contains a certain value in Doctrine2? - Stack Overflow

GitHubで編集を提案

Discussion