Doctrine2 ORM OneToOne无法正常工作UPDATE已更改为ManyToMany但未完全正常工作

时间:2015-09-24 11:05:43

标签: php doctrine-orm

我有2个名为Advert and User的表。用户ID将写入广告表。我现在创建了一个名为Bookmark的第三个表。该表有2列,advert_id和user_id。当我看到我喜欢的广告时,我可以添加一个书签,以便能够在我的私人部分找到它。当我在我的私人部门看到我的书签时,我希望立即看到广告详细信息,因此在我的存储库中,我想创建一个Join来读取广告表中的信息。我认为这将是OneToOne关系。我还必须确保如果广告被删除,那么所有书签都需要删除,所以我认为它是双向关系。所以我有以下内容:

实体/ Bookmark.php

 /**
 * Bookmark
 *
 * @ORM\Table(name="bookmark")
 * @ORM\Entity(repositoryClass="Advert\Repository\BookmarkRepository")
 */
class Bookmark
{
 /**
 * @var integer
 * @ORM\Id
 * @ORM\Column(name="advert_id", type="integer", nullable=false)
 * @ORM\OneToOne(targetEntity="Advert", mappedBy="bookmark")
 * @ORM\JoinColumn(name="advert_id", referencedColumnName="id")
 */
 private $advertId;

/**
 * @var integer
 * @ORM\Id
 * @ORM\Column(name="user_id", type="integer", nullable=false)
 * @ORM\OneToOne(targetEntity="User")
 * @ORM\JoinColumn(name="user_id", referencedColumnName="id")
 */
 private $userId;


 public function setAdvertId($advertId)
 {
    $this->advertId = $advertId;
    return $this;
 }


 public function getAdvertId()
 {
    return $this->advertId;
 }


 public function setUserId($userId)
 {
    $this->userId = $userId;
    return $this;
 }


 public function getUserId()
 {
    return $this->userId;
 }

实体\ Advert.php

/** Advert
 * 
 * @ORM\Table(name="advert")
 * @ORM\Entity(repositoryClass="Advert\Repository\AdvertRepository")
 */

class Advert
{
  /**
   * @var integer
   *
   * @ORM\Column(name="id", type="integer", nullable=false)
   * @ORM\Id
   * @ORM\GeneratedValue(strategy="IDENTITY")
   */
    private $id;

 /**
   * @ORM\OneToOne(targetEntity="Bookmark", inversedBy="advert")
   * @ORM\JoinColumn(name="id", referencedColumnName="advert_id")
   **/
    private $bookmark;

public function setBookmark($bookmark)
{
    $this->bookmark = $bookmark;
    return $this;
}


public function getBookmark()
{
    return $this->bookmark;
}



public function addBookmark($bookmark)
{
    $this->bookmark->add($bookmark);
}


public function removeBookmark($bookmark)
{
    $this->bookmark->removeElement($bookmark);   
}

广告\库\广告\ Repository.php

class BookmarkRepository extends EntityRepository
{
  public function getBookmarksByUserIds($userId)
  {
    $query =$this->_em->getRepository($this->getEntityName())->createQueryBuilder('b')
                            ->join('b.advertId', 'a')
                            ->andWhere('a.userId=:userid')
                            ->setParameter('userid',$userId)       
            ;
    return $query->getQuery()->getResult();
  }

我做错了什么或我的误解在哪里?我收到错误信息:

Advert \ Entity \ Bookmark没有名为advertId的关联

正如我所说,当我点击“添加广告到书签”时,表格Bookmark才会被填充。当我点击“显示我的书签”时,我需要加入才能显示广告详细信息,如果广告或用户被删除,则需要从书签表中删除所有书签。这是一个OneToOne双向关系,有什么问题?

更新1以下不工作

我已更新下面的2个文件,但我没有显示任何书签。相反,我应该看到已添加书签的广告列表以及广告详细信息。我甚至还没有尝试将我的服务转到“书签广告”或检查广告是否已添加书签的方法。我以前工作过,但我想我现在真的很困惑。

AdvertController.php

public function watchlistAction()
{
    $user_id = $this->zfcUserAuthentication()->getIdentity()->getId();
    $adverts = $this->getEntityManager()->getRepository('Advert\Entity\User')->findBookmarksByUserId($user_id);
        return new ViewModel(array(
            'adverts' => $adverts,
        ));
}

库\ UserRepository.php

class UserRepository extends EntityRepository
{

  public function findBookmarksByUserId($userId)
  {
      $query =$this->_em->getRepository($this->getEntityName())->createQueryBuilder('b')
                            ->join('b.bookmarks', 'a')
                            ->join('b.adverts', 'c')
                ->andWhere('a.user=:userid')
                ->setParameter('userid',$userId)       
            ;
      return $query->getQuery()->getResult();
  }

更新2以下工作

你是对的,我不需要UserRepository Query查看Bookmarked Adverts列表。我只需要改变

AdvertController.php

public function watchlistAction()
{
        $user_id = $this->zfcUserAuthentication()->getIdentity()->getId();
        // get User by reference (no queries executed)
        $user = $this->getEntityManager()->getReference('Advert\Entity\User' , $user_id);
        $adverts = $user->getBookmarks();

        return new ViewModel(array(
            'adverts' => $adverts,
        ));
}

好消息是,在我删除广告时,书签会自动删除在书签数据库表中。现在我只需要找出如何添加书签,所以我将不得不改变我的服务。一旦我开始工作,我将更新这篇文章供其他人查看。

更新3以下不工作

不幸的是,我的服务工作中没有得到以下3种方法。我显然必须现在选择1条记录,要么检查状态(已经加书签),删除书签(由advertId定义)或添加书签(由advertId定义)

public function checkAdvertBookmarkStatus($advertId)
{
    $userId = $this->getUserEntity()->getId();  
    // get User by reference (no queries executed)
    $user = $this->getEntityManager()->getReference('Advert\Entity\User' , $userId);

    $bookmarkStatus = $this->getEntityManager()->getRepository('Advert\Entity\User')
                                         ->findOneBy(array('advert' => $advertId, 'userId' => $userId));

    return $bookmarkStatus;
}  

   public function saveAdvertBookmark($advertId)
{
    $bookmark = new UserEntity();
    $userId = $this->getUserEntity()->getId();

 //   $bookmark->addBookmark($advertId);
    $bookmark->setAdvertId($advertId);
    $bookmark->setUserId($userId);

    # write new bookmmark to database tbl bookmark
    $this->getEntityManager()->persist($bookmark);
    $this->getEntityManager()->flush();
}


public function removeAdvertBookmark($advertId)
{
    $bookmark = new UserEntity();
    $userId = $this->getUserEntity()->getId();
    $bookmark = $this->getEntityManager()->getRepository('Advert\Entity\Bookmark')
                                         ->findOneBy(array('advertId' => $advertId, 'userId' => $userId));

    # remove bookmmark from tbl bookmark
    $this->getEntityManager()->remove($bookmark);
    $this->getEntityManager()->flush();

}

我想答案是在我继续阅读的教程中,但我并不完全理解。之前,当我使用BookmarkEntity时,我能够添加书签,但我不知道如何通过UserEntity来实现它

1 个答案:

答案 0 :(得分:2)

OneToOne关系在这里是错误的选择,这意味着用户只能为一个广告添加书签,并且广告只能由一个用户加入书签。由于用户应该能够为多个广告添加书签,并且广告应该被许多用户添加为书签,因此您需要具有ManyToMany关系。

如果您使用数据库,您想创建映射表书签并没有错。但是,您不需要在Doctrine中将其创建为实体。您可以在“用户”中的“书签”关联中添加广告,以显示已添加书签的广告,反之亦然:

用户实体:

/**
 * @var integer
 *
 * @ORM\Column(name="id", type="integer", nullable=false)
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="IDENTITY")
 */
private $id;

/**
 * @ORM\ManyToMany(targetEntity="Application\Entity\Advert", inversedBy="bookmarks", cascade={"persist"})
 * @ORM\JoinTable(name="bookmarks",
 *      joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
 *      inverseJoinColumns={@ORM\JoinColumn(name="advert_id", referencedColumnName="id")}
 *      )
 */
private $bookmarks;

广告实体

/**
 * @var integer
 *
 * @ORM\Column(name="id", type="integer", nullable=false)
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="IDENTITY")
 */
private $id;

/**
 * @ORM\ManyToMany(targetEntity="Application\Entity\User", mappedBy="bookmarks", cascade={"persist"})
 * @ORM\JoinTable(name="bookmarks",
 *      joinColumns={@ORM\JoinColumn(name="advert_id", referencedColumnName="id")},
 *      inverseJoinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")}
 *      )
 */
private $bookmarks;

您可能也想阅读本文: http://doctrine-orm.readthedocs.org/en/latest/reference/working-with-associations.html

修改:如何添加和删除书签

Doctrine中的关联与字段完全不同,尽管两者都是您实体中的属性。要处理书签,您可以直接在用户实体中添加或删除广告实体。例如:

$bookmarks = $user->getBookmarks();
$bookmarks[] = $advert;

这会向用户添加书签,并会在persistflush后立即存储。为了更加轻松,您可以定义removeradder

使用陈述:

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;

和代码:

/**
 * @param Collection $bookmarks
 */
public function addBookmarks(Collection $bookmarks)
{
    foreach ($bookmarks as $bookmark) {
        $this->bookmarks->add($bookmark);
    }
}

/**
 * @param Collection $bookmarks
 */
public function removeBookmarks(Collection $bookmarks)
{
    foreach ($bookmarks as $bookmark) {
        $this->bookmarks->removeElement($bookmark);
    }
}

您现在可以删除和添加收藏中的广告,如下所示:

$user->addBookmarks(new ArrayCollection(array($advert)));

始终建议在toMany关系中定义adderremover,因为许多Doctrine组件都需要它们,例如非常有用的DoctrineObject,DoctrineModule用于Zend 2的水化器