我在两个实体之间有一个oneToMany-ManyToOne关系。
在“部门”编辑页面(所有者,ManyToOne)上进行编辑时,更改将保存到部门表中,
但是从Utilisateur编辑页面(反面,OneToMany)进行编辑,所做的更改将不会保存到“部门”表中。
有人可以举例说明为什么它不起作用吗?
src / AppBundle / Entity / Utilisateur.php
class Utilisateur implements UserInterface, \Serializable {
/**
* @ORM\OneToMany(targetEntity="AppBundle\Entity\Departement", mappedBy="commercial")
*/
private $departements;
/**
* Constructor
*/
public function __construct() {
$this->departements=new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* @param \AppBundle\Entity\Departement $departement
* @return Utilisateur
*/
public function addDepartement(\AppBundle\Entity\Departement $departement)
{
$this->departements[] = $departement;
return $this;
}
/**
* @param \AppBundle\Entity\Departement $departement
*/
public function removeDepartement(\AppBundle\Entity\Departement $departement)
{
$this->departements->removeElement($departement);
}
/**
* @return \Doctrine\Common\Collections\Collection
*/
public function getDepartements()
{
return $this->departements;
}
}
src / AppBundle / Entity / Departement.php
class Departement {
/**
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\Utilisateur", inversedBy="departements")
*/
private $commercial;
/**
* @param \AppBundle\Entity\Utilisateur $commercial
* @return Departement
*/
public function setCommercial(\AppBundle\Entity\Utilisateur $commercial=null) {
$this->commercial=$commercial;
return $this;
}
/**
* @return \AppBundle\Entity\Utilisateur
*/
public function getCommercial() {
return $this->commercial;
}
}
src / AppBundle / Form / Utilisateur / Edit3dhType.php
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('departements', EntityType::class, array(
'class'=>Departement::class,
'expanded'=>true,
'multiple'=>true
));
}
src / AppBundle / Controller / UtilisateurController.php
/**
* @Route("/dashboard/utilisateurs/edit-{id}", name="security_edit_user")
* @Method({"GET", "POST"})
*
* @param Request $request
* @param Utilisateur $utilisateur
* @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
*/
public function editAction(Request $request, Utilisateur $utilisateur) {
$logo=$utilisateur->getLogo();
if($utilisateur->getLogo() !== null) {
$utilisateur->setLogo(new File($this->getParameter('dir_picto').$logo));
}
$form=$this->createForm(Edit3dhType::class, $utilisateur, array(
'action'=>$this->generateUrl('security_edit_user', array('id'=>$utilisateur->getId())),
'method'=>'POST',
));
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()) {
if($utilisateur->getLogo() !== null) {
$utilisateur->setLogo($this->container->get('service.upload')->uploadPicto($utilisateur->getLogo()));
} else {
$utilisateur->setLogo($logo);
}
$em=$this->getDoctrine()->getManager();
$em->flush();
}
return $this->render('security/edit.html.twig', array(
'user'=>$this->getUser(),
'utilisateur'=>$utilisateur,
'form'=>$form->createView(),
));
}
答案 0 :(得分:0)
您需要确保该实体由Doctrine管理。您可以通过将对象作为参数(persist
来调用$em->persist($utilisateur)
方法来实现此目的。
虽然您通过Doctrine检索了对象,但该对象已经被管理,因此Doctrine可能不知道它也应该通过OneToMany关系持久化对象。如@Dirk所述,设置级联操作肯定会有所作为。您可以像这样将其添加到Utilisateur
类中:
@ORM\OneToMany(targetEntity="AppBundle\Entity\Departement", mappedBy="commercial", cascade={"persist"})
当您试图(通过关系)持久保存一个不受教义管理的实体时,您应该收到一个异常。所以很奇怪你没有一个...
检查表单是否实际上在创建Department
实例并将其添加到Utilisateur
类中(在将“部门”字段添加到表单时,您没有指定类型)。
答案 1 :(得分:0)
您需要使用cascade={"persist"}
定义级联操作,如下所示:
class Departement {
/**
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\Utilisateur", inversedBy="departements", cascade={"persist"} )
*/
private $commercial;
}
答案 2 :(得分:0)
在FormType中,您需要执行以下操作。
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('departements', CollectionType::class, array(
'entry_type'=> DepartmentType::class,
'allow_add' => true,
'allow_delete' => true,
'allow_extra_fields' => true,
'by_reference' => false // calls addDepartement / removeDepartement on parent(Utilisateur) automatically
));}
有关信息,请参阅:https://symfony.com/doc/current/form/form_collections.html
答案 3 :(得分:0)
所以...感谢TEDx在经过数小时的搜索和阅读,大量的转储以及与熊的小聊天之后向我提示了一些文档,...我才了解了以下内容。
首先,Doctrine似乎只检查关系拥有方的数据。这意味着如果从反面完成,它将无法处理任何事情。
第二,与第一个问题有关,当我试图做相反的事情时,Doctrine不会在表单数组集合中设置departement.commercial
。因此,与表中的数据没有区别,它不会进行任何查询。
最后,Doctrine不会检测到该格式中的任何未经检查的条目(因此将departement.commercial
设置为NULL
)。
在我想到的解决方案下面。它适用于OneToMany / ManyToOne关系的反面。并进行一些调整也可以用于ManyToMany关系。
src / AppBundle / Controller / UtilisateurController.php
public function editAction(Request $request, Utilisateur $utilisateur) {
//Save pre submit data
$preSubmitDepartement=$utilisateur->getDepartements()->toArray();
$form=$this->createForm(UtilisateurType::class, $utilisateur, array(
'action'=>$this->generateUrl('security_edit_user', array('id'=>$utilisateur->getId())),
'method'=>'POST',
'utilisateur'=>$utilisateur,
));
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()) {
$em=$this->getDoctrine()->getManager();
//Get post submit data
$postSubmitDepartement=$utilisateur->getDepartements()->toArray();
//Keep only IDs for pre and post submit data
/** @var Departement $v */
foreach($preSubmitDepartement as $k=>$v) {
$preSubmitDepartement[$k]=$v->getId();
}
/** @var Departement $v */
foreach($postSubmitDepartement as $k=>$v) {
$postSubmitDepartement[$k]=$v->getId();
}
//Find removed IDs
$prePostSubmitDifference=array_map('unserialize', array_diff(array_map('serialize',$preSubmitDepartement), array_map('serialize',$postSubmitDepartement)));
//Fetch related Departement entries
$departements=$em->getRepository(Departement::class)->findBy(array('id'=>array_merge($postSubmitDepartement, $prePostSubmitDifference)));
//setCommercial to $utilisateur or null
/** @var Departement $departement */
foreach($departements as $departement) {
if(in_array($departement->getId(), $postSubmitDepartement)) {
$departement->setCommercial($utilisateur);
} else if(in_array($departement->getId(), $prePostSubmitDifference)) {
$departement->setCommercial(null);
}
}
$em->flush();
}
return $this->render('security/edit.html.twig', array(
'user'=>$user,
'utilisateur'=>$utilisateur,
'form'=>$form->createView(),
));
}
现在我可以从反面设置departement.conseiller
。