基于多对多相关实体的Symfony主义查询

时间:2019-03-16 06:45:03

标签: symfony doctrine-orm

我正在构建一个简单的消息传递系统。用户与ManyToMany关系中的MessageThreads相关。 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(...)存储库方法。理想情况下,我想要一个只能找到只有该用户的线程的方法,但是经过几个小时的搜索后,我放弃了。我的第二种方法(或更确切地说,解决方法)是找到属于给定线程的用户,并将用户数限制为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();
    }
}

任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:-1)

在查询生成器中添加一个having子句:

$qb->join('mt.users', 'u')
   ->having('count(u.id) = 2'))