У меня есть простая программа Symfony2 с двумя объектами: муниципалитет и Poi. Существует отношение «Один-ко-многим» между муниципалитетом и Pois (то есть: ноль или больше pois, размещенных в одном муниципалитете), поэтому файлы Entity выглядят следующим образом:
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.
Я выполнил инструкции, описанные в 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' )) ; } }
Форма, которую я пытаюсь получить, – это форма добавления / редактирования, в которой я могу определить название муниципалитета и добавить / удалить связанные pois из объекта Poi, но то, что я действительно получаю, является формой, где я могу определить название муниципалитета , и управлять объектом Poi в виде подформы.
Этот скриншот описывает результат -> http://i.imgur.com/nM1ywwh.png
Я имею в виду, таким образом, я могу добавить новые Pois и отношения с любым муниципалитетом (то есть: Лос-Анджелес), но то, что я пытаюсь получить, – это список al pois, относящихся к этому муниципалитету, и возможность:
Я видел способ справиться с этим в обратном порядке, выбрав муниципалитет, связанный с каждым Poi в форме добавления / изменения Poi (много-к-одному), но мне интересно, есть ли способ управлять этими отношениями в другое лицо.
Могу ли я сделать это в SonataAdmin? Любая подсказка?
ОБНОВЛЕНИЕ: разрешил пользовательский интерфейс и добавил pois, но не удалил
У меня есть способ показать виджет, который я ищу, определив форму следующим образом:
protected function configureFormFields(FormMapper $formMapper) { $formMapper ->add('name') ->add('pois', null, array(), array( 'edit' => 'inline', 'inline' => 'table', 'sortable' => 'position' )) ; }
Я сделал, чтобы изменить «sonata_type_collection» для нулевого значения. Теперь я получаю форму, похожую на этот снимок экрана ->
… это как раз поведение, которое я хочу.
Первоначально дополнения в этом виджете (то есть: добавление новых маршрутов в муниципалитет) не сохранялись. Благодаря комментарию Radomir Wojtera, я понял, что в моем классе муниципалитета есть методы, которые не были реализованы (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, они не отделяются. поэтому я могу добавлять отношения, но не удалять.
Наконец, я могу решить вторую проблему (удаление Poi из муниципалитета не сработало), установив orphanRemoval = true в настройке Entity
class Municipality { /** * @ORM\OneToMany(targetEntity="Poi", mappedBy="municipality", cascade={"persist"}, orphanRemoval=true)) */ protected $pois; ...
Первая проблема решается, как указано в обновлении вопроса.