Doctrine的多对多逻辑令我感到困惑。我有一个非常简单的多对多关系的食谱与类别的关系。我的基本实体类同样简单。
食谱实体类......
class Recipe
{
/**
* @ORM\ManyToMany(targetEntity="Category", inversedBy="categories")
* @ORM\JoinTable(name="recipe_category")
**/
private $categories;
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="title", type="string", length=255)
*/
private $title;
public function __construct() {
$this->categories = new \Doctrine\Common\Collections\ArrayCollection();
}
}
分类实体类......
class Category
{
/**
* @ORM\ManyToMany(targetEntity="Recipe")
**/
private $recipes;
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=255)
*/
private $name;
public function __construct() {
$this->recipes = new \Doctrine\Common\Collections\ArrayCollection();
}
}
看起来很漂亮,并且与Doctrine(和Symfony2)的文档示例相匹配。当我尝试通过Symfony控制台应用程序为这些类生成getter和setter时,会出现奇怪的行为。
关系设置者/获取者不正确。例如,在Recipe类中生成的Category setter ......
/**
* Add categories
*
* @param \Namespace\CookbookBundle\Entity\Category $categories
* @return Recipe
*/
public function addCategorie(\Namespace\CookbookBundle\Entity\Category $categories)
{
$this->categories[] = $categories;
return $this;
}
看起来方法名称的自动生成已关闭。它应该是“addCategory”,应该传递给“类别”。
虽然我可以手动纠正,但如果我重新运行实体生成器,它只会再次添加它们。
我这样做不正确还是这只是实体生成器的怪癖?我可以通过注释指定覆盖吗?
答案 0 :(得分:0)
你没有做任何错误,因为symfony是如何产生它们的。我通常不使用应用程序/控制台生成它们,因为目前它们没有做好。一个例子就像你提到的那样,你已经提到过多元化的单词。另一个显而易见的事实是,它使用的是[]
符号,它将ArrayCollection
对象作为PHP数组。您永远不应该将ArrayCollections视为数组。
这就是我自己实现它的方式:
public function addCategory(Category $category)
{
if (!$this->categories->contains($category)
$this->categories->add($category);
return $this;
}
如果已经添加了重复项,则不会向Array集合添加重复项。同样的事情与删除:
public function removeCategory(Category $category)
{
if ($this->categories->contains($category)
$this->categories->remove($category);
}
我遇到的很多次是让你说你有4个类别,然后添加和删除它们
$r = new Recipe();
$c1 = new Category();
$c2 = new Category();
$r->addCategory($c1);
$r->addCategory($c2);
// at this point $r->getCategories()->toArray()[0] contains $c1
// and $r->getCategories()->toArray()[1] contains $c2
$r->removeCategory($c1);
// now $r->getCategories()->toArray()[0] is empty and
// $r->getCategories()->toArray()[1] contains $c2 still
// so in order to get the first category you need to:
$r->getCategories()->first();
答案 1 :(得分:0)
你没有做错任何事。只是当集合属性有多个名称时,Doctrine会自动尝试单独化方法存根的名称。这是Doctrine在运行命令doctrine:generate:entities:
时调用的函数$methodName = Inflector::singularize($methodName);
在你的情况下,学说试图单一化。单词 categories 但无法正确识别单数形式,所以它只是删除了一个&#39> s'从最后返回类别。
此外,如您所见,Doctrine并未将传递给方法存根的参数单一化,而是保留$categories
而不是一致并将其修改为$categorie
。
如果你想避免这种情况,要么你不使用复数词来收集,要么使用复数词然后改变方法。正如@keyboardSmasher对你的帖子所做的评论,当使用命令doctrine:generate:entities时,doctrine不会覆盖你已经拥有的方法,如果只留在那里,错误的方法会受到很大的伤害。
最后一点:使用 ArrayCollections 作为数组非常好,所以这段代码是正确的:
$this->categories[] = $category;
ArrayCollection 对象实现 Collection ,后者又实现 ArrayAccess 。这样做是为了能够将 ArrayCollections 用作数组。