Я строю простую систему обмена сообщениями. Пользователи связаны с MessageThreads в отношении ManyToMany. MessageThreads может иметь много пользователей (например, групповые чаты или каналы) или только двух пользователей (например, личные сообщения).
class User extends BaseUser
{
/**
* HAS MANY: MessageThreads
* @ORM\ManyToMany(targetEntity="MessageThread", inversedBy="users", fetch="EXTRA_LAZY", cascade={"persist"})
* @ORM\JoinTable(
* name="user_message_thread",
* joinColumns={
* @ORM\JoinColumn(name="user_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* @ORM\JoinColumn(name="mthread_id", referencedColumnName="id")
* }
* )
*/
private $messageThreads;
...
}
class MessageThread
{
/**
* HAS MANY: Users
* @ORM\ManyToMany(targetEntity="User", mappedBy="messageThreads", cascade={"persist"})
*/
private $users;
...
}
Теперь, учитывая, что у пользователя есть способ открыть приватный чат с определенным другим пользователем, я хочу иметь возможность определить, существует ли между ними MessageThread (и только для них), или я должен создать новый
public function newPrivAction(Request $request, string $slug)
{
...
// try locating a thread with ONLY current and $friend user
if($thread = $em->getRepository('AppBundle:MessageThread')->findOnePrivFor($this->getUser(), $friend)) {
// ** dbg
print "Old priv found #" . $thread->getId();
die();
}
// or create a brand new thread
else {
$thread = new MessageThread();
$thread
->addUser($this->getUser())
->addUser($friend)
;
$em->persist($thread);
$em->flush();
// ** dbg
print "New priv created #" . $thread->getId();
die();
}
...
}
Моя проблема в том, что я не могу понять, как структурировать метод репозитория findOnePrivFor(...)
. В идеале мне нужен метод, который просто находит поток с ТОЛЬКО ЭТИМИ пользователями, но после нескольких часов поисков в Google, я отказался от этого. Мой второй подход (или, скорее, обходной путь) заключался в том, чтобы найти пользователей, которые принадлежат к данному потоку, и ограничить количество пользователей до 2. Этот подход довольно близко подошел ко мне - кроме подсчета, которая, похоже, не работает.
class MessageThreadRepository extends \Doctrine\ORM\EntityRepository
{
public function findOnePrivFor(User $user1, User $user2)
{
$qb = $this->createQueryBuilder('mt');
$qb
->where(':user1 MEMBER OF mt.users')
->andWhere(':user2 MEMBER OF mt.users')
//->andWhere('count(mt.users) = 2') // ** fails
//->andWhere($qb->expr()->eq($qb->expr()->count('mt.users'), 2)) // ** fails
->setMaxResults(1)
->setParameters([
'user1' => $user1,
'user2' => $user2
])
;
return $qb->getQuery()->getOneOrNullResult();
}
}
Любая помощь будет высоко ценится.