Uno a muchas relaciones y agregar / editar formulario en sonataadmin y Symfony2
-
21-12-2019 - |
Pregunta
Tengo una aplicación SIMFONY2 simple con dos entidades: Municipio y PDI. Hay una relación "uno a muchos" entre el municipio y los PDI (es decir: cero o más POIs colocados en un municipio), por lo que los archivos de la entidad son así:
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;
}
}
En este punto, quiero administrar la relación de uno a muchos entre el municipio y sus PDI desde el formulario Municipio Agregar / Editar en Sonata Admin.
He seguido las instrucciones explicadas en http://sonata-project.org/bundles/doctrine-orm-admin/master/doc/reference/form_field_definition.html#advanced-usage-one-to-many , por lo que el archivo de clase MunicipalityMin es:
poc / pocbundle / admin / municipalitymin.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'
))
;
}
}
Esta pantalla de pantalla describe el resultado -> http://i.imgur.com/nm1ywwh.png
Me refiero, de esta manera, puedo agregar nuevos PDI y relaciones con cualquier municipio (es decir, Los Ángeles), pero lo que estoy tratando de obtener es una lista de Al POI que están relacionados con este municipio y la posibilidad. a:
- Añadir nuevas relaciones (es decir: asociar un POI huérfano como estatua de la libertad a este municipio (Nueva York)).
- Eliminar las relaciones existentes (es decir: eliminar una relación incorrecta como "Walt Disney Concert Hall" en Nueva York)
He visto la forma de administrar esto en la forma inversa, seleccionando el Municipio relacionado con cada PDI en el Formulario de Edición / Edición de PDI (muchos a uno), pero me pregunto si hay alguna forma de administrar esto Relaciones en la otra entidad.
¿Puedo hacer esto en SONATAADMIN? ¿Alguna pista?
Actualización: resolvió la interfaz de usuario y agregando PDI, pero no eliminando
Tengo la manera de mostrar el widget que busco, definiendo el formulario de esta manera:
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('name')
->add('pois', null, array(), array(
'edit' => 'inline',
'inline' => 'table',
'sortable' => 'position'
))
;
}
Lo que hice es cambiar 'sonata_type_collection' para el valor nulo. Ahora recibo un formulario como esta captura de pantalla ->
... que como solo el comportamiento que quiero.
Inicialmente, las adiciones en este widget (es decir: agregar nuevos PDI a un municipio), no persistió. Gracias al comentario de Radomir Wojtera, me di cuenta de que había métodos que no se implementaban en mi clase de entidad municipal (Setpois, Addpoi y RemoverPoi).
Añadido estos métodos ...
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);
}
... y ahora puedo tomar nuevos PROIS para un municipio, pero cuando quito algunos POIs, no se disociaron. Así que puedo agregar relaciones, pero no quitar.
Solución
Finalmente, puedo resolver el segundo problema (eliminar PDI de un municipio no funcionó) configurando OrphanRemoval= True en la configuración de la entidad
class Municipality
{
/**
* @ORM\OneToMany(targetEntity="Poi", mappedBy="municipality", cascade={"persist"}, orphanRemoval=true))
*/
protected $pois;
...
El primer problema se resuelve según lo comentó en la actualización de la pregunta.