Reputation: 6062
I have a bidirectional many-to-one relationship. Let's go with Foo
and Bar
. Foo
has the following:
class Foo
{
/**
* @ORM\OneToMany(targetEntity="Bar", mappedBy="foo", cascade={"all"}, orphanRemoval=true)
*/
private $bars;
public function __construct()
{
$this->bars = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* @param mixed $bars
*/
public function setBars($bars)
{
$this->bars = $bars;
}
/**
* @param Bar $bar
*/
public function addBar(Bar $bar)
{
$this->bars->add($bar);
}
/**
* @return mixed
*/
public function getBars()
{
return $this->bars;
}
}
And Bar
:
class Bar
{
/**
* @ORM\Id()
* @ORM\ManyToOne(targetEntity="Foo", inversedBy="bars")
* @ORM\JoinColumn(name="foo_id", referencedColumnName="id", nullable=false)
*/
protected $foo;
/**
* @param Foo $foo
*/
public function setFoo(Foo $foo)
{
$this->foo = $foo;
}
/**
* @return Foo
*/
public function getFoo()
{
return $this->foo;
}
}
Okay, so with the classes above, when I write:
$foo = new Foo();
$bar1 = new Bar();
$bar2 = new Bar();
$foo->addBar($bar1);
$foo->addBar($bar2);
And try to persist, I get an error about how each Bar
's foo property is null:
Similarly, if I flip it around to:
$foo = new Foo();
$bar1 = new Bar();
$bar2 = new Bar();
$bar1->setFoo($foo);
$bar2->setFoo($foo);
I can persist, but then my Foo
s newly generated PersistentCollection
for that property is empty:
Is this intended behavior? I'm used to other ORMs on different platforms wiring up the bidirectional relationship upon assignment, so I'm not sure if this is normal for Doctrine/PHP, or if my annotations are messed up (which the error message above leads me to believe).
So, any help would be greatly appreciated.
Upvotes: 1
Views: 141
Reputation: 3928
add this to your addBar
function. you missed the back ref. from bar
entity to the foo
entity
/**
* @param Bar $bar
*/
public function addBar(Bar $bar)
{
$bar->setFoo($this);
$this->bars->add($bar);
}
Upvotes: 0
Reputation: 17759
Your main issue is that you are not setting Foo in Bar when you add a Bar.
To auto set that you can do the following (I've also added a check to see if the Bar has already been added and a return to chain set's)..
/**
* Add bar
*
* @param Bar $bar
* @return $this
*/
public function addBar(Bar $bar)
{
if (!$this->bars->contains($bar)) {
$this->bars->add($bar);
$bar->setFoo($this)
}
return $this;
}
You should probably get rid of the setBars
as I can see that causing an issue if you used set but didn't use an array collection.
Also you should add a remove bar so you don't have get, remove, and then reset every time, like..
/**
* Remove bar
*
* @param Bar $bar
* @return $this
*/
public function removeBar(Bar $bar)
{
if ($this->bars->contains($bar)) {
$this->bars->removeElement($bar);
$bar->setFoo(null);
}
return $this;
}
Which would mean your setFoo
would need to be able to accept a null value..
/**
* Set foo
*
* @param Foo $foo
*/
public function setFoo(Foo $foo = null)
{
$this->foo = $foo;
}
Upvotes: 1
Reputation: 1238
You need to set the two sides of the association, for instance
/**
* @param Bar $bar
*/
public function addBar(Bar $bar)
{
if(!$this->bars->contains($bar)) {
$this->bars->add($bar);
$bar->setFoo($this);
}
}
----
/**
* @param Foo $foo
*/
public function setFoo(Foo $foo)
{
if($this->foo !== $foo) {
$this->foo = $foo;
$foo->addBar($this);
}
}
At the moment your only setting one side of the association and Doctrine does not do the rest for you.
If you don't want to modify your add/remove methods you have to
$bar->setFoo($foo)
$foo->addBar($bar)
Everytime you want to add a foo or a bar
EDIT:
If you want to use only one side to do all the operation, read about owning/inverse side. Maybe it could help with your problem. But I'm not sure it will do the correct bidir link between your entities.
Upvotes: 1
Reputation: 5280
The error message you are getting is telling that an entity can't be persisted without filling the id
field. Also, it looks like you are missing id
field in your Foo entity.
Anyway, the id
field is probably already in your database (autogenerated by Doctrine), but no autoincrement is set so filling it manually is mandatory before persist.
Try adding the following code in your entities:
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
Hope it helps.
Upvotes: 0