两个doctrine2实体,Photo和Tag,通过多对多关系链接,并相应地进行映射。
每个标记都有一个键和一个值,因此示例键为“photo-type”,示例值为“people”。
我创建了一个自定义存储库PhotoRepository.php,以便于使用标记对的数组(或逗号分隔列表*)轻松搜索照片,如下所示:
public function getQueryByTags($tags = null, $limit =0, $start =-1, $boolean ="and")
{
...
$qb->select('p')
->from('MyBundle\Entity\Photo', 'p')
->join('p.tags','t');
# ->join('a.tags','t')
if ($boolean == "and") { $qb->where('1 = 1'); }
$i = 1;
foreach ($tags as $tag) {
if ($boolean == "and") {
$qb->andWhere('t.key = ?'.$i.' AND t.value = ?'.($i+1));
} elseif ($boolean == "or") {
$qb->orWhere('t.key = ?'.$i.' AND t.value = ?'.($i+1));
}
$qb->setParameter($i, $tag['key'])->setParameter(($i+1), $tag['value']);
$i += 2;
}
...
return $qb->getQuery();
}
这适用于单个标签。但是,一旦标记为多个(例如,搜索'photo-type'=>'people','person'=>'Bob'),布尔逻辑就会崩溃并且不会返回任何结果。
我怀疑这与将加入的Tag实体与Doctrine2 queryBuilder()放在一起的Where /(或Where)子句有关。 (因为相同的标签不能同时'照片类型'=>'人'和'人'=>'鲍勃',尽管相同的照片应该是)。
$photos = $em->getRepository('MyBundle:Photo')->
findByTags(array(
array('key' => 'context','value' => $context),
array('key' => 'photo-type','value' => 'field'),
));
我尝试构建一个JOIN WITH查询,但这似乎需要一个非常复杂的构造来创建表达式,我无法弄清楚: -
public function getQueryByTags($tags = null, $limit =0, $start =-1, $boolean ="and")
{
...
$qb->select('p')
->from('MyBundle\Entity\Photo', 'p');
$i = 1;
$expr = $qb->expr();
foreach ($tags as $tag) {
if ($boolean == "and") {
$expr = $expr->andX($qb->expr()->eq('t.key', '?'.$i),$qb->expr()->eq('t.value', '?'.($i+1)));
} elseif ($boolean == "or") {
}
$qb->setParameter($i, $tag['key'])->setParameter(($i+1), $tag['value']);
$i += 2;
}
$qb->join('p.tags','t',Doctrine\ORM\Query\Expr\Join::WITH,$expr);
# ->join('a.tags','t')
...
return $qb->getQuery();
}
编辑:最终我想要的结果是:
“和”搜索:SELECT all Photos which have (Tag with key(A) AND value(B) ) AND (another Tag with key(C) AND value(D))
“或”搜索:SELECT all Photos which have (Tag with key(A) AND value(B) ) OR (another Tag with key(C) AND value(D))
其中:A,B是第一个唯一标签'对'(例如'photo-type'='people'或'photo-type'='animal')而C,D是另一个唯一标签'pair'(例如'person'='Bob','person'='Tiddles'或理论上'animal'='Tiddles')
任何人都可以帮我弄清楚如何构建这个复杂的JOIN WITH表达式吗?
或者,如果看起来我正在咆哮错误的树,那么有人可以提出另一种更优雅的做法吗?
*注意:如果以逗号分隔的字符串收到$ tag(例如$ tags =“photo-type = people,person = Bob”),则首先将其转换为数组。
编辑#2:Tag实体,应@Wilt请求:
Tag.yml
MyBundle\Entity\Tag:
type: entity
table: tag
fields:
id:
id: true
type: integer
unsigned: true
nullable: false
generator:
strategy: IDENTITY
key:
type: string
length: 20
fixed: false
nullable: true
value:
type: string
length: 50
fixed: false
nullable: true
manyToMany:
photos:
targetEntity: Tag
mappedBy: tags
lifecycleCallbacks: { }
Photo.yml(仅限提取物)
MyBundle\Entity\Photo:
type: entity
repositoryClass: MyBundle\Entity\PhotoRepository
table: photo
fields:
sha1:
....
manyToMany:
tags:
targetEntity: Tag
inversedBy: photos
joinTable:
name: x_photo_tag
joinColumns:
photo_sha1:
referencedColumnName: sha1
inverseJoinColumns:
tag_id:
referencedColumnName: id
答案 0 :(得分:1)
对于像这样的事情,你的代码看起来太复杂了。 您可以使用本机doctrine解决方案来使用in array解决方案检查标记类型:
$array = [];
foreach ($tags as $i => $tag) {
$array[] = $tag['value'];
}
$qb = $this->createQueryBuilder('p')
->innerJoin('p.tags','t')
->where('t.type IN(:array)')
或者我误解了你的情况?然后尝试更清楚一下你真正想要的结果集。
我认为你可以这样做:
// Main query
$qb = $this->createQueryBuilder('p')
->innerJoin('p.tags','t');
// Get tag repository to make tag query (you can also use FROM instead)
$tagRepository = $this->getEntityManager()->getRepository('MyBundle\Entity\Tag');
// Choose your where
$where = 'orWhere'; //`OR` query:
$where = 'andWhere'; //`AND` query:
// Add a in sub query expression for each tag
foreach ($tags as $i => $tag){
$alias = 't' . $i;
$sub = $tagRepository->createQueryBuilder($alias);
$sub->where($alias . '.key = :key' . $i);
$sub->andWhere($alias . '.value = :value' . $i);
$qb->setParameter('key' . $i, $tag['key']);
$qb->setParameter('value' . $i, $tag['value']);
$qb->$where($qb->expr()->in('t.id', $sub->getDQL()));
}
// get your resultset
return $qb->getQuery();