2015-09-29 2 views
2

Я создал набор Symfony 2, который поддерживает личные сообщения между пользователями. Я дал им возможность отправлять сообщения из своей папки inbox или sent на номер trash. Сообщения будут помечены как мусор через поля isRTrash и isSTrash, отмеченные получателем и отправителем соответственно. Это потому, что, будучи одним и тем же сообщением в моей базе данных, если бы у меня было одно единственное поле здесь, один пользователь, отмечающий его как мусор, отметит его и для другого.Обновление определенных полей на основе условия в Doctrine

Теперь, я хочу дать им возможность также 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 зарегистрированного пользователя и массив идентификаторов сообщения. Затем я проверяю сообщения, которые находятся в корзине, не помечены как удаленные и не имеют текущего пользователя в качестве получателя или отправителя и хотят пометить их как удаленные.

Проблема заключается в том, что оба условия выполнены, и вызываются как SET, маркируя isRDeleted сообщения, так и isSDeleted истинным, независимо.

Я очень близко, но не знаю, как это сделать, чтобы поля отмечены отдельно, только если их условие выполнено.

Между тем, я использую цикл Еогеасп, но я думаю, что это можно сделать быстрее с помощью запроса

$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(); 
    } 

ответ

2

Я думаю, что вам нужно CASE .. WHEN конструкцию, но доктрина не имеет, что в DQL (см Grammar). Таким образом, вы должны либо использовать необработанный запрос, то вдоль этих линий (это псевдо 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, как тот, который вы уже сделал. Честно говоря, я думаю, что это довольно простое решение в вашем случае, и выглядит более удобным для использования :, если вам понадобится прочитать свой код за шесть месяцев.

NB: на стороне записки, то ->set() или ->when() функции в доктрине (и все остальные, на самом деле) не следуют в определенном порядке; они просто добавляют свойства к объекту запроса Doctrine, а при вызове getQuery() выполняется SQL-запрос. Это означает, что следующая конструкция:

->when()->set() 
->orwhen()->set() 

эквивалентно:

->set()->set() 
->when()->orWhen() 

именно поэтому ваше решение не может работать.Там нет условия должны быть выполнены, прежде чем set() называется (, если я не ясно, скажите мне)

+0

Да, я понял, что порядок не имеет значения в запросе. Я также искал инструкции CASE..WHEN, но не могу найти никаких рабочих решений для UPDATE, только для INSERT. –

+0

Не должны ли вы оставить значения isR/SDeleted без изменений, если условия не выполняются? Похоже, вы можете воскрешать сообщения по ошибке;). Не понимаю, почему вам нужно проверить, являются ли значения ложными, поскольку вы все равно установите их в true, какое влияние на производительность? –

+0

@GeorgeIrimiciuc вам просто нужно использовать собственный SQL-запрос в Doctrine: 'return $ this-> getEntityManager() -> getConnection() -> executeQuery ($ sql, $ params);' с '$ sql' ваш запрос и' $ params' параметры. – tchap

Смежные вопросы