在学说2中的许多关系

时间:2014-08-01 07:36:15

标签: php doctrine-orm zend-framework2

我最近刚开始使用Zend Framework 2,现在正在进入Doctrine 2,我现在想要整合到我的第一个项目中。

我现在遇到以下情况,即使在几天之后,我找不到解决方案。

我有3张桌子:

广告

advert_id
advert_title
etc

分类

category_id
name
label
etc

advert2category

advert2category_category_id
advert2category_advert_id

广告可以在不同的类别中,不同的类别具有不同的广告,因此表格为Advert2ategory(ManytoMany)。

阅读完www后,我决定它应该是一个ManytoMany双向,拥有"拥有的一面"在广告实体。

不要问我为什么决定这一点,我仍然完全不理解主义。无论如何,我创建了3个实体,但我猜我只需要广告和类别实体。

我现在希望发生以下情况。

我点击了一个类别,想要查看此类别中的文章列表。这意味着我必须读出表格advert2category。我创建了实体,这里是我的广告实体:

所以这是我的广告实体:

namespace Advert\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;

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

class Advert
{

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


    /**
     * @var string
     *
     * @ORM\Column(name="advert_title", type="string", length=255, nullable=true)
     */
     private $advertTitle;


    /**
    * @ORM\ManyToMany(targetEntity="Category", inversedBy="advertCategory", cascade={"persist"})
    * @ORM\JoinTable(name="advert2category",
    * joinColumns={@ORM\JoinColumn(name="advert2category_category_id", referencedColumnName="category_id")},
    * inverseJoinColumns={@ORM\JoinColumn(name="advert2category_advert_id", referencedColumnName="advert_id")}
    * )
    */

    protected $category;

    public function __construct()
    {
        $this->category = new ArrayCollection();
    }


    /**
     * Get advertId
     *
     * @return integer 
     */
    public function getAdvertId()
    {
        return $this->advertId;
    }


    /**
     * Set advertTitle
     *
     * @param string $advertTitle
     * @return Advert
     */
    public function setAdvertTitle($advertTitle)
    {
        $this->advertTitle = $advertTitle;

        return $this;
    }

    /**
     * Get advertTitle
     *
     * @return string 
     */
    public function getAdvertTitle()
    {
        return $this->advertTitle;
    }


    /**
     * Set category
     *
     * @param \Advert\Entity\User $category
     * @return Advert
     */
    public function setCategory(\Advert\Entity\Category $category = null)
    {
        $this->category = $category;

        return $this;
    }

    /**
     * Get category
     *
     * @return \Advert\Entity\Category
     */
    public function getCategory()
    {
        return $this->category;
    }
}  

我的类别实体:

namespace Advert\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;

/**
 * Category
 *
 * @ORM\Table(name="category")
 * @ORM\Entity
 */

class Category
{

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

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255, nullable=false)
     */
    private $name;



    /**
     * @ORM\ManyToMany(targetEntity="Advert", mappedBy="category")
     **/
    private $advertCategory;

    public function __construct()
    {
        $this->advertCategory = new ArrayCollection();
    }


    /**
     * Get categoryId
     *
     * @return integer 
     */
    public function getCategoryId()
    {
        return $this->categoryId;
    }


    /**
     * Set name
     *
     * @param string $name
     * @return Category
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string 
     */
    public function getName()
    {
        return $this->name;
    }
}  

正如第一次测试一样,我现在在我的控制器中尝试了以下内容:

// Controller下面现在用于回显类ArrayCollection

$data = $this->getEntityManager()->getRepository('Advert\Entity\Advert')->findAll();

foreach($data as $key=>$row)
{

  echo $row->getAdvertTitle();
  echo $row->getUser()->getUsername();
  $categories = $row->getCategory();

  foreach($categories as $row2) {
    echo $row2->getName();
 }

我在这里做错了什么?任何人都可以给我一个建议吗?非常感谢你提前!

1 个答案:

答案 0 :(得分:1)

老实说,这是一个非常诚实和美好的事情,这会使你想要做的事情过于复杂,但仅限于特定领域。

如果您使用Composer包含Doctrine(推荐方式),还包括symfony/console,您将获得一大堆非常棒的工具来帮助您完成任务。有一个非常具体的命令会让你坐在座位上,看看它有多棒:$ doctrine orm:schema-tool:update --force --dump-sql。这将使Doctrine在您的实体中运行(您只需要两个)并生成您的表,甚至为您设置*To*关联。在ManyToOne的情况下,它将生成适当的外键模式。在ManyToMany的情况下,它将自动创建,并管理它自己的关联表,您只需要担心在实体中为表提供名称。

我不是在开玩笑,请这样做。它会让你的生活变得有价值。

至于您的实体设置,这就是您所需要的:

<?php 

namespace Advert\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;

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

class Advert
{

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


    /**
     * @var string
     *
     * @ORM\Column(name="advert_title", type="string", length=255, nullable=true)
     */
     private $advertTitle;


    /**
    * @ORM\ManyToMany(targetEntity="Category", cascade={"persist"})
    * @JoinTable(name="advert_categories")
    */
    protected $category;


    public function __construct()
    {
        $this->category = new ArrayCollection();
    }


    /**
     * Get advertId
     *
     * @return integer 
     */
    public function getAdvertId()
    {
        return $this->advertId;
    }


    /**
     * Set advertTitle
     *
     * @param string $advertTitle
     * @return Advert
     */
    public function setAdvertTitle($advertTitle)
    {
        $this->advertTitle = $advertTitle;

        return $this;
    }

    /**
     * Get advertTitle
     *
     * @return string 
     */
    public function getAdvertTitle()
    {
        return $this->advertTitle;
    }


    /**
     * Set category
     *
     * @param ArrayCollection $category
     * @return Advert
     */
    public function setCategory(ArrayCollection $category)
    {
        $this->category = $category;

        return $this;
    }

    /**
     * Get category
     *
     * @return ArrayCollection
     */
    public function getCategory()
    {
        return $this->category;
    }
}  

请注意,getter和setter是Documented to Set and Return ArrayCollection,这对于阅读PHPDoc和Annotations的IDE和工具来说非常重要,以了解深入的PHP类映射的工作原理。

另外,请注意ManyToMany声明的简单程度是多少? @JoinTable注释用于为教条生成和管理的表提供名称。这就是你所需要的!

但是现在,您可能应该从类别实体中删除$advertCategory属性。 Doctrine将使用Entity Association Mappings在属性中自动保存嵌入的实体。

这也有潜在危险,因为它可能导致无限递归。基本上,如果您要求的所有广告都是ID为1的广告,它会进入并查找与广告1相关联的所有类别实体,但在这些类别中,它会重新引用广告1,该主题将对其进行子查询和注入,它将包含一个类别关联,然后将抓取这些类别,依此类推,直到PHP因缺乏内存而杀死自己。

一旦一切顺利,并且您获得了与广告关联的一些类别,在广告实体中使用Getter作为您的类别将返回一个类别实体数组。只需迭代它们:

foreach($category as $advert->getCategories()) {
   echo $category->getName();
}

echo current($advert->getCategories())->getName();