Details:
Wanted result:
I created two entities (with the recent make:entity command), Acme and AcmeParent. Acme has a ManyToOne relation to AcmeParent, and AcmeParent has a OneToMany relation to Acme.
When I go on EasyAdmin, on an AcmeParent entity edition, I see the field (fieldPB = field p b) with the OneToMany relation. It's a multiple selector and I can add Acme entities.
Error:
When I add two Acme entities (with or without an AcmeParent related already, it doesn't mater), and try to save, the related Acme entities aren't updated with their new relation (but the save function does work for AcmeParent as the first string field is updated).
I'm not sure it's a bug, maybe I miss something in the config file to allow edition (but then, it's weird the field is there and not working), or I forgot to add the required function in the entities (but I didn't find any indication in the documentation about that).
Code samples:
EasyAdmin config
easy_admin:
entities:
- App\Entity\Acme
- App\Entity\AcmeParent
Acme entity
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass="App\Repository\AcmeRepository")
*/
class Acme
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="integer", nullable=true)
*/
private $fieldA;
/**
* @ORM\Column(type="string", length=255)
*/
private $fieldB;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\AcmeParent", inversedBy="fieldPB")
*/
private $acmeParent;
public function getId()
{
return $this->id;
}
public function getFieldA(): ?int
{
return $this->fieldA;
}
public function setFieldA(?int $fieldA): self
{
$this->fieldA = $fieldA;
return $this;
}
public function getFieldB(): ?string
{
return $this->fieldB;
}
public function setFieldB(string $fieldB): self
{
$this->fieldB = $fieldB;
return $this;
}
public function getAcmeParent(): ?AcmeParent
{
return $this->acmeParent;
}
public function setAcmeParent(?AcmeParent $acmeParent): self
{
$this->acmeParent = $acmeParent;
return $this;
}
public function __toString(): string
{
return $this->getFieldB();
}
}
AcmeParent entity
<?php
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass="App\Repository\AcmeParentRepository")
*/
class AcmeParent
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $fieldPA;
/**
* @ORM\OneToMany(targetEntity="App\Entity\Acme", mappedBy="acmeParent")
*/
private $fieldPB;
public function __construct()
{
$this->fieldPB = new ArrayCollection();
}
public function getId()
{
return $this->id;
}
public function getFieldPA(): ?string
{
return $this->fieldPA;
}
public function setFieldPA(string $fieldPA): self
{
$this->fieldPA = $fieldPA;
return $this;
}
/**
* @return Collection|Acme[]
*/
public function getFieldPB(): Collection
{
return $this->fieldPB;
}
public function addFieldPB(Acme $fieldPB): self
{
if (!$this->fieldPB->contains($fieldPB)) {
$this->fieldPB[] = $fieldPB;
$fieldPB->setAcmeParent($this);
}
return $this;
}
public function removeFieldPB(Acme $fieldPB): self
{
if ($this->fieldPB->contains($fieldPB)) {
$this->fieldPB->removeElement($fieldPB);
// set the owning side to null (unless already changed)
if ($fieldPB->getAcmeParent() === $this) {
$fieldPB->setAcmeParent(null);
}
}
return $this;
}
public function __toString(): string
{
return $this->getId() . ' - ' . $this->getFieldPA();
}
}
Screenshot:
Acme entities before edition: acme parent field is null for ccc and ddd
AcmeParent entities before edition: field p b is at 0 for qwerty
AcmeParent edition form: ccc and ddd entities added to the field with the OneToMany relation, and name is changed
AcmeParent entities after edition: name is actualy updated, but field p b still is 0
Acme entities after edition: no change to Acme entity ccc and ddd
Hello @thibaut-st
Are you still facing the same issue ?
Please take a look at the documentation below :
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/working-with-associations.html#transitive-persistence-cascade-operations
You may have missed the cascade persist operation.
Do not hesitate to correct me if i'm wrong.
Best Regards
Good point, I forgot it in my entity, but even after adding it, it doesn't save.
It behave exactly the same as explained in the original post even with the cascade={"persist"} in the annotation.
EDIT: and I read in the doctrine documentation that line
New entities in a collection not marked as cascade: persist will produce an Exception and rollback the flush() operation.
So, shouldn't EasyAdmin throw an exception too? Or at least a warning message?
Hi @thibaut-st , I think you problem could be related to the way Symfony deals with form Types.
Have you tried to set your field by_reference to false on the form field definition ?
https://symfony.com/doc/current/reference/forms/types/form.html#by-reference
Or if you used a form configuration from easyAdmin yml file :
easy_admin:
entities:
YourEntity:
edit:
fields:
- { property: 'yourCollectionPropertyHere', type_options: { by_reference: false }}
Thanks, it work.
But I have two main issue related to this:
Hello @thibaut-st
Sorry for the late response. I was busy lately.
As @samuel-cariat-pro stated, your issue is related with the way symfony handle form collection.
EasyAdmin is built upon symfony so i don't know if it's really pertinent to have this information on EasyAdmin side.
Please find below resources that may helps you :
https://symfony.com/doc/current/form/form_collections.html
https://knpuniversity.com/screencast/easyadminbundle/fake-custom-field
Do not hesitate to make PRs to enhance the documentation.
I remain at your disposal,
Best regards
Most helpful comment
Hi @thibaut-st , I think you problem could be related to the way Symfony deals with form Types.
Have you tried to set your field
by_referencetofalseon the form field definition ?https://symfony.com/doc/current/reference/forms/types/form.html#by-reference
Or if you used a form configuration from easyAdmin yml file :