Sonata Admin Bundle: One-To-Many и sonata_type_collection
На первых порах, в Сонате возникало непонимание того как правильно организовать редактирование связи one-to-many. На самом деле, есть несколько неочевидных моментов в Сонате, которые могут вызвать проблемы.
Итак, как организовать one-to-many:
- ORM сущности
mac:
targetEntity: Mac
mappedBy: device
cascade: ["all"]
orphanRemoval: true
Здесь следует обратить внимание на параметр cascade, который говорит доктрине, что все действия, относящиеся к родителю, должны также влиять на дочерние объекты. Также важен параметр orphanRemove, который облегчит вам жизнь, так как говорит доктрине, что нужно отслеживать объекты, у которых нет привязки к родительскому объекту и удалять их. Это нужно в случаях, когда мы редактируем уже созданную сущность, внутри самой сущности, при редактировании достаточно всего лишь отвязать объект от родительской сущности и доктрина сама удалить его из базы.
- Сущность
<?php
/**
* @var Application\Ailove\EquipBundle\Entity\Mac
*/
private $mac;
/**
* Construct
*/
public function __construct()
{
$this->mac = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Set mac
*
* @param Doctrine\Common\Collections\ArrayCollection $mac
*/
public function setMac($mac)
{
if (!$mac) {
$this->mac = new \Doctrine\Common\Collections\ArrayCollection();
return;
}
foreach ($mac as $item) {
$item->setDevice($this);
}
foreach ($this->getMac() as $item) {
if (!$mac->contains($item)) {
$this->getMac()->removeElement($item);
$item->setDevice(null);
}
}
$this->mac = $mac;
}
/**
* Add mac
*
* @param Application\Ailove\EquipBundle\Entity\Mac $mac
*/
public function addMac(\Application\Ailove\EquipBundle\Entity\Mac $mac)
{
$mac->setDevice($this);
$this->mac[] = $mac;
}
/**
* Remove mac
*
* @param Application\Ailove\EquipBundle\Entity\Mac $mac
*/
public function removeMac(\Application\Ailove\EquipBundle\Entity\Mac $mac)
{
$this->getMac()->removeElement($mac);
$mac->setDevice(null);
}
/**
* Get mac
*
* @return Doctrine\Common\Collections\Collection
*/
public function getMac()
{
return $this->mac;
}
Здесь нужно обратить внимание, что в первую очередь в one-t0-many поля должны быть обязательно представлены ArrayCollection, для этого нужно добавить соответствующую строчку в конструкторе. Соната требует наличия add и remove методов для свойства, в которых через методы сущности нужно осуществлять привязку или отвязку дочерних объектов, благодаря orphanRemoval доктрина сама определит когда нужно удалять отвязанный объект.
- configureFormFields
Внутри админ класса следует добавить следующее поле:
<?php
$formBuilder->add('mac', 'sonata_type_collection',
array('required' => false, 'by_reference' => false),
array('edit' => 'inline', 'inline' => 'table')
);
На этом, собственно все. В конечном счете, one-to-many будет выглядеть примерно таким образом: