SonataAdmin 및 Symfony2의 일대다 관계 및 추가/편집 양식
-
21-12-2019 - |
문제
두 개의 엔터티가 있는 간단한 Symfony2 애플리케이션이 있습니다.지방자치단체와 포이.지방자치단체와 Pois 사이에는 "일대다" 관계가 있습니다(예:하나의 지방자치단체에 0개 이상의 pois가 배치됨) 따라서 엔터티 파일은 다음과 같습니다.
Poc\PocBundle\Entity\Municipality.php
<?php
// Poc\PocBundle\Entity\Municipality.php
namespace Poc\PocBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Municipality
*
* @ORM\Table()
* @ORM\Entity(repositoryClass="Poc\PocBundle\Entity\MunicipalityRepository")
*/
class Municipality
{
/**
* @ORM\OneToMany(targetEntity="Poi", mappedBy="municipality")
*/
protected $pois;
public function __construct()
{
$this->pois = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* @param string $name
* @return Municipality
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Add pois
*
* @param \Poc\PocBundle\Entity\Poi $pois
* @return Municipality
*/
public function addPois(\Poc\PocBundle\Entity\Poi $pois)
{
$this->pois[] = $pois;
return $this;
}
/**
* Remove pois
*
* @param \Poc\PocBundle\Entity\Poi $pois
*/
public function removePois(\Poc\PocBundle\Entity\Poi $pois)
{
$this->pois->removeElement($pois);
}
/**
* Get pois
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getPois()
{
return $this->pois;
}
public function __toString()
{
return $this->name;
}
}
Poc\PocBundle\Entity\Poi.php
<?php
// Poc\PocBundle\Entity\Poi.php
namespace Poc\PocBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Poi
*
* @ORM\Table()
* @ORM\Entity(repositoryClass="Poc\PocBundle\Entity\PoiRepository")
*/
class Poi
{
/**
* @ORM\ManyToOne(targetEntity="Municipality", inversedBy="pois")
* @ORM\JoinColumn(name="municipality_id", referencedColumnName="id")
*/
protected $municipality;
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* @param string $name
* @return Poi
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Set municipality
*
* @param \Poc\PocBundle\Entity\Municipality $municipality
* @return Poi
*/
public function setMunicipality(\Poc\PocBundle\Entity\Municipality $municipality = null)
{
$this->municipality = $municipality;
return $this;
}
/**
* Get municipality
*
* @return \Poc\PocBundle\Entity\Municipality
*/
public function getMunicipality()
{
return $this->municipality;
}
public function __toString()
{
return $this->name;
}
}
이 시점에서는 Sonata Admin의 지방자치단체 추가/수정 양식에서 지방자치단체와 해당 pois 간의 일대다 관계를 관리하고 싶습니다.
나는 다음에 설명된 지침을 따랐습니다. http://sonata-project.org/bundles/doctrine-orm-admin/master/doc/reference/form_field_definition.html#advanced-usage-one-to-many 이므로 MunicipalityAdmin 클래스 파일은 다음과 같습니다.
Poc/PocBundle/Admin/MunicipalityAdmin.php
<?php
namespace Poc\PocBundle\Admin;
use Sonata\AdminBundle\Admin\Admin;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Show\ShowMapper;
class MunicipalityAdmin extends Admin
{
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->addIdentifier('name')
->add('_action', 'actions', array(
'actions' => array(
'show' => array(),
'edit' => array(),
)
))
;
}
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('name')
->add('pois', 'sonata_type_collection', array(), array(
'edit' => 'inline',
'inline' => 'table',
'sortable' => 'position'
))
;
}
}
내가 얻으려는 양식은 지방 자치 단체의 이름을 정의하고 Poi 엔터티에서 관련 장소를 추가/제거할 수 있는 추가/편집 양식이지만 실제로 얻는 것은 지방 자치 단체의 이름을 정의할 수 있는 양식입니다. , 일종의 하위 양식으로 Poi 엔터티를 관리합니다.
이 스크린샷은 결과를 설명합니다 --> http://i.imgur.com/nM1ywwh.png
내 말은, 이런 방식으로 새로운 Pois를 추가하고 모든 자치단체와의 관계를 추가할 수 있다는 뜻입니다(예:로스앤젤레스), 하지만 제가 얻으려는 것은 이 지방자치단체와 관련된 알포이스 목록과 다음과 같은 가능성입니다.
- 새 관계 추가(예:자유의 여신상과 같은 고아 포이를 이 자치단체(뉴욕)에 연결합니다.
- 기존 관계를 제거합니다(예:뉴욕의 "Walt Disney Concert Hall"과 같은 잘못된 관계를 삭제하세요)
이것을 역으로 포이 추가/수정 양식(다대일)에서 각 포이와 관련된 지자체를 선택하여 관리하는 방법을 본 적이 있는데, 포이에서 이 관계를 관리할 수 있는 방법이 없을지 궁금합니다. 다른 실체.
SonataAdmin에서 이 작업을 수행할 수 있나요?어떤 단서가 있나요?
업데이트:UI를 해결하고 pois를 추가했지만 삭제하지는 않았습니다.
다음과 같이 양식을 정의하여 내가 찾고 있는 위젯을 표시하는 방법이 있습니다.
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('name')
->add('pois', null, array(), array(
'edit' => 'inline',
'inline' => 'table',
'sortable' => 'position'
))
;
}
내가 한 일은 'sonata_type_collection'을 null 값으로 변경하는 것입니다.이제 다음 스크린샷과 같은 양식이 표시됩니다 -->
...그것은 내가 원하는 행동입니다.
처음에는 이 위젯에 추가된 사항(예:지방자치단체에 새로운 pois를 추가했지만 지속되지 않았습니다.Radomir Wojtera의 의견 덕분에 내 Municipality Entity 클래스(setPois, addPoi 및 RemovePoi)에 구현되지 않은 메소드가 있음을 깨달았습니다.
이 방법을 추가했습니다 ...
public function setPois($pois)
{
if (count($pois) > 0) {
foreach ($pois as $i) {
$this->addPoi($i);
}
}
return $this;
}
public function addPoi(\Poc\PocBundle\Entity\Poi $poi)
{
$poi->setMunicipality($this);
$this->pois->add($poi);
}
public function removePoi(\Poc\PocBundle\Entity\Poi $poi)
{
$this->pois->removeElement($poi);
}
...이제 지방자치단체에 대한 새 Pois를 확보할 수 있지만 일부 Pois를 제거해도 연결이 해제되지 않았습니다.그래서 관계를 추가할 수는 있지만 제거할 수는 없습니다.
해결책
마지막으로 엔터티 구성에서 orphanRemoval=true를 설정하여 두 번째 문제(지자체에서 Poi를 제거해도 작동하지 않음)를 해결할 수 있습니다.
class Municipality
{
/**
* @ORM\OneToMany(targetEntity="Poi", mappedBy="municipality", cascade={"persist"}, orphanRemoval=true))
*/
protected $pois;
...
첫 번째 문제는 질문 업데이트에 설명된 대로 해결되었습니다.