Symfony2 / Doctrine:如何只加载当前登录用户的相关对象?

时间:2014-02-28 03:33:01

标签: php symfony doctrine-orm doctrine

我的Symfony2应用程序显示歌曲并让用户对它们进行评分。用户管理使用FOSUserBundle完成。 我已经定义了两个对象(歌曲和评级)之间的一对多关系,定义如下:

实体/ Song.php

/**
 * Song
 *
 * @ORM\Table()
 * @ORM\Entity(repositoryClass="[...]\[...]Bundle\Entity\SongRepository")
 */
class Song
{
[...]
    /**
     * @ORM\OneToMany(targetEntity="Rating", mappedBy="song")
     */
    protected $ratings;
[...]
}

实体/ Rating.php

/**
 * Rating
 *
 * @ORM\Table()
 * @ORM\Entity
 */
class Rating
{
[...]
    /**
     * @var float
     *
     * @ORM\Column(name="rating", type="float")
     */
    private $rating;

    /**
     * @ORM\ManyToOne(targetEntity="[...]\UserBundle\Entity\User", inversedBy="ratings")
     * @ORM\JoinColumn(name="user_id", referencedColumnName="id")
     */
    protected $user;

    /**
     * @ORM\ManyToOne(targetEntity="Song", inversedBy="ratings")
     * @ORM\JoinColumn(name="song_id", referencedColumnName="id", onDelete="CASCADE")
     */
    protected $song;
[...]

在我的应用程序中加载所有歌曲(~40)时,我可以在控制器中访问它们,如下所示:

SongsController.php:

$songs = $em->getRepository('[...]Bundle:Song')->findAll();

现在,我怎样才能有效地确保我只获得当前登录用户的评分,而无需遍历所有评分并验证用户?

index.html.twig

{% for rating in song.ratings %}
  {% if rating.user == app.user%}
    {{ rating.rating }}
  {% endif %}
{% endfor %}

修改

我现在有这个:

public function getAllSongsWithRatings($user)
{
    $qb = $this->getEntityManager()->createQueryBuilder()
       ->select('s')
       ->from('[...]Bundle:Song','s')
       ->join('s.ratings','r')
       ->where('r.user = :user')
       ->setParameter('user', $user);

    return $qb->getQuery()->getResult();

}

但是当我看到学说产生的时候:

SELECT s0_.id AS id0, s0_.number [...] FROM Song s0_ LEFT JOIN Rating [...] WHERE r1_.user_id = ? AND [...]
SELECT t0.id AS id1, t0.rating AS [...] FROM Rating t0 WHERE t0.song_id = ?

它没有查询评级,包括user_id ......我认为这可能是不完整的......

1 个答案:

答案 0 :(得分:3)

您将需要使用存储库功能:

http://symfony.com/doc/current/book/doctrine.html#custom-repository-classes

然后我们必须得到一些主要的运行本机MySQL查询:

public function getSongsWithUserRatings($userid)
{
    $stmt = $this->_em->getConnection()->executeQuery(
        'SELECT * FROM Song s LEFT JOIN Rating r ON r.song = s.song_id AND r.user = :userid',
        array('userid'=>$userid),
        array('userid'=>'integer')
    );
    return $stmt->fetchAll();

注意leftJoin部分。使用WITH参数将为您提供所有歌曲,并加入评级,如果它们仅存在于该用户。

然后在你的控制器中你要求这个并将它传递给树枝:

//Controller

$userRatedSongs = $em->getRepository('Bundle:Songs')->getSongsWithUserRatings($this->getUser()->getUserId())

然后你的树枝模板:

{% for song in songs %}
<h3>{{song.name}}</h3>
    {% if song.rating != null %}
    <p> Rating: {{song.rating}}</p>
    {% endif %}
{% endfor %}
song.ratings仍然是一个阵列但是如果你对你的收视率有限制,那么用户只能评价一首歌曲,那么第一个评级将是用户评分。