这是一种情况,我有一个表单,其中需要一个实体字段类型。在BenefitGroup实体内部,我有一个BenefitGroupCategory选择。
我的构建形式是:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('BenefitGroupCategories', 'entity', array(
'class' => 'AppBundle:BenefitGroupCategory',
'property' => 'name',
'label' => false,
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('c')
->orderBy('c.name', 'ASC');
},))
->add('benefitsubitems', 'collection', array('type' => new BenefitSubItemFormType(), 'allow_add' => true, 'label' => false,));
}
这几乎是一种典型的产品类别关系。一个BenefitGroup只能有一个类别,一个类别可以属于许多BenefitGroups(唯一的复杂性,尚未实现,但这就是我需要查询生成器的原因,因为所有这些都将取决于另一个参数(项目),因此一些类别将是默认类别(始终可用),其他项目将仅适用于特定项目(见下文BenefitGroupCategory实体中的项目参考)。
您会注意到另一个字段benefitsitems,它与手头的问题无关。
据我所知,从条令的角度来看,我必须建立一个一对多、单向的联接表。
这两个实体是:
<?php
// src/AppBundle/Entity/BenefitGroup.php
namespace AppBundleEntity;
use DoctrineCommonCollectionsArrayCollection;
use DoctrineORMMapping as ORM;
/**
* @ORMEntity(repositoryClass="AppBundleEntityBenefitGroupRepository")
* @ORMTable(name="benefit_groups")
*/
class BenefitGroup
{
/**
* @ORMColumn(type="integer")
* @ORMId
* @ORMGeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORMManyToOne(targetEntity="BenefitItem", cascade={"persist"}, inversedBy="BenefitGroups")
*/
protected $benefitItem;
/**
* @ORMoneToMany(targetEntity="BenefitSubItem", mappedBy="benefitGroup")
*/
protected $BenefitSubItems;
/**
* @ORMManyToMany(targetEntity="BenefitGroupCategory")
* @ORMJoinTable(name="BenefitGroup_BenefitGroupCategory", joinColumns={@ORMJoinColumn(name="BenefitGroup_id", referencedColumnName="id")}, inverseJoinColumns={@ORMJoinColumn(name="BenefitGroupCategory_id", referencedColumnName="id", unique=true)})
*/
protected $BenefitGroupCategories;
// HERE I HAVE SOME IRRELEVANT GETTERS AND SETTERS
/**
* Constructor
*/
public function __construct()
{
$this->BenefitSubItems = new ArrayCollection();
$this->BenefitGroupCategories = new ArrayCollection();
}
/**
* Add BenefitGroupCategories
*
* @param AppBundleEntityBenefitGroupCategory $benefitGroupCategories
* @return BenefitGroup
*/
public function addBenefitGroupCategory(AppBundleEntityBenefitGroupCategory $benefitGroupCategories)
{
$this->BenefitGroupCategories[] = $benefitGroupCategories;
return $this;
}
/**
* Remove BenefitGroupCategories
*
* @param AppBundleEntityBenefitGroupCategory $benefitGroupCategories
*/
public function removeBenefitGroupCategory(AppBundleEntityBenefitGroupCategory $benefitGroupCategories)
{
$this->BenefitGroupCategories->removeElement($benefitGroupCategories);
}
/**
* Get BenefitGroupCategories
*
* @return DoctrineCommonCollectionsCollection
*/
public function getBenefitGroupCategories()
{
return $this->BenefitGroupCategories;
}
}
您还会注意到另一个实体BenefitItem,它是BenefitGroup的"父亲"。
和
<?php
// src/AppBundle/Entity/BenefitGroupCategory.php
namespace AppBundleEntity;
use DoctrineORMMapping as ORM;
use SymfonyBridgeDoctrineValidatorConstraintsUniqueEntity;
/**
* @ORMEntity()
* @ORMTable(name="benefit_group_category")
* @UniqueEntity(fields={"name", "project"}, ignoreNull=false, message="Duplicated group category for this project")
*/
class BenefitGroupCategory
{
/**
* @ORMColumn(type="integer")
* @ORMId
* @ORMGeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORMColumn(type="string", length=50)
*/
protected $name;
/**
* @ORMManyToOne(targetEntity="Project")
*/
protected $project;
// HERE I HAVE SOME IRRELEVANT GETTERS AND SETTERS
}
在控制器中(你会看到几个嵌入的集合,它们工作正常)我有:
/**
* @Route("/benefit/show/{projectID}", name="benefit_show")
*/
public function showAction(Request $request, $projectID)
{
$id=4; //the Id of the CVC to look for
$storedCVC = $this->getDoctrine()
->getRepository('AppBundle:CVC')
->find($id);
$form = $this->createForm(new CVCFormType(), clone $storedCVC);
$form->handleRequest($request);
if ($form->isValid())
{
$em = $this->getDoctrine()->getManager();
//$benefitGroupCategoryRepository = $this->getDoctrine()->getRepository('AppBundle:BenefitGroupCategory');
$formCVC = $form->getData();
$em->persist($formCVC);
foreach ($formCVC->getBenefitItems() as $formBI)
{
$newBI = new BenefitItem();
$newBI->setCVC($formCVC);
$newBI->setComment($formBI->getComment());
$em->persist($newBI);
foreach ($formBI->getBenefitGroups() as $formBG)
{
$newBG = new BenefitGroup();
$newBG->setBenefitItem($newBI);
$newBG->setBenefitGroupCategories($formBG->getBenefitGroupCategories());
$em->persist($newBG);
foreach ($formBG->getBenefitSubItems() as $formSI)
{
$newSI = new BenefitSubItem();
$newSI->setBenefitGroup($newBG);
$newSI->setComment($formSI->getComment());
$em->persist($newSI);
}
}
}
$em->flush();
}
return $this->render('benefit/show.html.twig', array(
'form' => $form->createView(),
));
}
问题是:在可视化中,它可以正确地可视化表单(即使它没有正确检索类别。我可以选择类别,这是可以的,但它没有检索到正确的类别。我必须在表单中设置默认值吗?
问题变得更糟当我汇总表单时,它应该创建一个带有所有嵌套实体的新实体(注意克隆)。问题是它崩溃了,说:
Neither the property "BenefitGroupCategories" nor one of the methods
"addBenefitGroupCategory()"/"removeBenefitGroupCategory()",
"setBenefitGroupCategories()", "benefitGroupCategories()", "__set()" or
"__call()" exist and have public access in class
"AppBundleEntityBenefitGroup".
"美妙之处"在于,即使我完整地评论了"isValid"中的(讨厌的)部分,它的行为也完全相同。
我迷路了:(
关于克隆,您必须取消设置克隆实体的id,请查看此处:https://stackoverflow.com/a/14158815/4723525
编辑:
是的,但PHP只是做浅层复制,你必须克隆其他对象。查看示例#1在中克隆对象http://php.net/manual/en/language.oop5.cloning.php.你必须通过定义__clone方法来克隆你的对象(对于低于2.0.2的Doctrine,你必须在克隆后调用自己的方法来克隆,因为代理定义了它自己的__clone方式)。例如:
function __clone() {
$oldCollection = $this->collection;
$this->collection = new ArrayCollection();
foreach ($oldCollection as $oldElement) {
$newElement = clone $oldElement;
// additional actions for example setting this object to owning side
$newElement->setParent($this);
$this->collection->add($newElement);
}
}