我创建了一个Symfony 2 Bundle,支持用户之间的私人消息。我让他们能够将inbox
或sent
文件夹中的邮件发送到trash
个文件夹。邮件将分别通过isRTrash
和isSTrash
字段标记为垃圾邮件,分别由收件人和发件人标记。这是因为,在我的数据库中是相同的消息,如果我在这里有一个单独的字段,一个用户将其标记为垃圾,也会将其标记为另一个字段。
现在,我想让他们从他们的垃圾文件夹中delete
给他们一些可能性。邮件不会被删除,但标记为垃圾邮件,只是它们永远不会从标准用户视图中删除。我有这样的标记问题,因为我必须标记用户发送和接收的两条消息。
我在实体的存储库中进行了以下查询:
public function delete($user, $msg)
{
$qb = $this->createQueryBuilder('a')
->update('PrivateMessageBundle:Message', 'a')
->where('a IN(:msg)')
->andwhere('a.receiver = :user AND a.isRTrash IS NOT null AND a.isRDeleted = false')->set('a.isRDeleted', true)
->orWhere('a.sender = :user AND a.isSTrash IS NOT null AND a.isSDeleted = false')->set('a.isSDeleted', true)
->setParameters(
array('user' => $user, 'msg' => $msg)
);
echo '<pre>';
\Doctrine\Common\Util\Debug::dump($qb->getQuery()->getSQL()); exit;
echo '</pre>';
return $qb->getQuery();
}
输出查询为string(196) "UPDATE message SET isRDeleted = 1, isSDeleted = 1 WHERE (id IN (?) AND (receiver_id = ? AND isRTrash IS NOT NULL AND isRDeleted = 0)) OR (sender_id = ? AND isSTrash IS NOT NULL AND isSDeleted = 0)"
我输入了登录用户的curent和一个消息ID数组。然后,我检查垃圾邮件中的邮件,未标记为已删除邮件,并将当前用户作为收件人或发件人,并希望将其标记为已删除。
问题是这两个条件都已得到满足,并且正在调用SET
,无论如何都将消息标记为isRDeleted
和isSDeleted
为真。
我非常接近,但不知道如何制作它以便字段被单独标记,只要它们的条件得到满足。
与此同时,我使用了foreach循环,但我认为可以通过查询更快地完成
$em = $this->getDoctrine()->getManager();
foreach ($msgs as $msgid) {
$msg = $messages->findOneBy(array('id' => $msgid));
if ($msg->getSender() == $this->getUser() && $msg->getIsSTrash() && $msg->getIsSDeleted() == false) {
$msg->setIsSDeleted(true);
$changedno++;
} else if ($msg->getReceiver() == $this->getUser() && $msg->getIsRTrash() && $msg->getIsRDeleted() == false) {
$msg->setIsRDeleted(true);
$changedno++;
}
$em->flush();
}
答案 0 :(得分:2)
我认为你需要一个CASE .. WHEN
构造但是Doctrine在DQL中没有这个构造(参见Grammar)。所以你要么必须使用原始查询,要么就是这些行( it&#39;伪MySQL ):
UPDATE PrivateMessageBundle:Message a
SET a.isRDeleted = CASE
WHEN a.receiver = :user AND a.isRTrash IS NOT null THEN TRUE
ELSE a.isRDeleted = FALSE
END,
SET a.isSSDeleted = CASE
WHEN a.receiver = :user AND a.isRTrash IS NOT null THEN TRUE
ELSE a.isSDeleted = FALSE
END
...或使用两个标准查询,一个用于isRDeleted
,另一个用于isSDeleted
,就像您已经执行的那样。老实说,我认为这是一个非常简单的解决方案,如果您需要在六个月内再次阅读代码,它看起来更像维护友好型。
注意:在旁注中,Doctrine中的
->set()
或->when()
函数(实际上所有其他函数)都不遵循特定的顺序;它们只是向Doctrine查询对象添加属性,当您调用getQuery()
时,会进行SQL查询。这意味着以下结构:->when()->set() ->orwhen()->set()
相当于:
->set()->set() ->when()->orWhen()
这就是您的解决方案无法运行的原因。调用
set()
之前没有条件可以满足(如果我不清楚,请告诉我)