我最近刚开始使用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();
}
我在这里做错了什么?任何人都可以给我一个建议吗?非常感谢你提前!
答案 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();