SonataAdmin和Symfony2中的一对多关系和添加/编辑表单 [英] One to Many relations and add/edit form in SonataAdmin and Symfony2

查看:163
本文介绍了SonataAdmin和Symfony2中的一对多关系和添加/编辑表单的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的Symfony2应用程序,有两个实体:市政府和Poi。市政府与Pois之间存在一对多关系(即:一个市政当局放置零个或多个),因此实体文件如下所示:



Poc\PocBundle\Entity\Municipality.php

 <?php 

// Poc\PocBundle\Entity\Municipality.php

命名空间Poc\PocBundle\Entity;

使用Doctrine\ORM\Mapping作为ORM;

/ **
*市政厅
*
* @ 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整数
*
* @ 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;


/ **
*获取ID
*
* @return integer
* /
public function getId()
{
return $ this-> id;
}

/ **
*设定名称
*
* @param string $ name
* @return市政厅
* /
public function setName($ name)
{
$ this-> name = $ name;

return $ this;
}

/ **
*获取名称
*
* @return string
* /
public function getName )
{
return $ this-> name;
}

/ **
*添加pois
*
* @param \Poc\PocBundle\Entity\Poi $ pois
* @return Municipality
* /
public function addPois(\Poc\PocBundle\Entity\Poi $ pois)
{
$ this-> pois [] = $ pois;

return $ this;
}

/ **
*删除pois
*
* @param \Poc\PocBundle\Entity\Poi $ pois
* /
public function removePois(\Poc\PocBundle\Entity\Poi $ pois)
{
$ this-> pois-> removeElement($ pois );
}

/ **
*获取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

命名空间Poc\PocBundle\Entity;

使用Doctrine\ORM\Mapping作为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整数
*
* @ 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;


/ **
*获取ID
*
* @return integer
* /
public function getId()
{
return $ this-> id;
}

/ **
*设定名称
*
* @param string $ name
* @return Poi
* /
public function setName($ name)
{
$ this-> name = $ name;

return $ this;
}

/ **
*获取名称
*
* @return string
* /
public function getName )
{
return $ this-> name;
}

/ **
*设置自治市
*
* @param \Poc\PocBundle\Entity\Municipality $ municipality
* @return Poi
* /
public function setMunicipality(\Poc\PocBundle\Entity\Municipality $ municipality = null)
{
$ this- < municipality = $ municipality;

return $ this;
}

/ **
*获得自治市
*
* @return \Poc\PocBundle\Entity\Municipality
* /
public function getMunicipality()
{
return $ this-> municipality;
}

public function __toString()
{
return $ this-> name;
}
}

此时,我想管理One-市政府与他们在Sonata管理员中添加/编辑表单之间的多少关系。



我已按照 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 
命名空间Poc\PocBundle\Admin;

使用Sonata\AdminBundle\Admin\Admin;
使用Sonata\AdminBundle\Form\FormMapper;
使用Sonata\AdminBundle\Datagrid\DatagridMapper;
使用Sonata\AdminBundle\Datagrid\ListMapper;
使用Sonata\AdminBundle\Show\ShowMapper;

class MunicipalityAdmin extends Admin
{
protected function configureListFields(ListMapper $ listMapper)
{
$ listMapper
- > addIdentifier('名称')
- > add('_ action','actions',array(
'actions'=> array(
'show'=> array(),
'edit'=> array(),

))
;
}
保护函数configureFormFields(FormMapper $ formMapper)
{
$ formMapper
- > add('name')
- > add 'pois','sonata_type_collection',array(),array(
'edit'=>'inline',
'inline'=>'table',
'sortable'= >'position'
))
;
}
}

我想要获得的表单是添加/编辑表单,我可以定义自治市的名称,并从Poi实体添加/删除相关的pois,但是我实际获得的是一个形式,我可以定义自治市的名称,并以一种子类型管理Poi实体 -



此屏幕会描述结果 - > http://i.imgur.com/nM1ywwh.png



我的意思是这样,我可以添加新的Pois和任何关系自治市(即:洛杉矶),但是我想要得到的是与这个市政府有关的一些名单,以及可能性:




  • 添加新的关系(即:将自由女神像的孤儿Poi与这个自治市(纽约)联系起来)。

  • 删除现有的关系(即:删除不正确的关系纽约纽约华特迪士尼音乐厅)



<我已经看到了以相反的方式来管理这个方法,选择与Poi添加/编辑表单(多对一)中的每个Poi相关的市政府,但是我想知道是否有任何方式来管理这种关系在另一个实体中。



我可以在SonataAdmin中执行此操作吗?任何线索?



更新:解决UI并添加pois,但不删除



我可以通过以下方式定义表单来显示我正在寻找的窗口小部件:

  protected function configureFormFields(FormMapper $ formMapper)
{
$ formMapper
- > add('name')
- > add('pois' ,null,array(),array(
'edit'=>'inline',
'inline'=>'table',
'sortable'=&
))
;
}

我所做的是更改sonata_type_collection为空值。现在我得到一个这样的屏幕截图 - >



...只是我想要的行为。



最初,这个小部件中的添加(即:向自治市添加新的pois),didn不坚持感谢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

  class Municipality 
{
/ **
* @ ORM\OneToMany(targetEntity =Poi,mappedBy =municipality,cascade = {persist},orphanRemoval = true))
* /
protected $ pois;
...

第一个问题在问题更新中被评论。 p>

I have a simple Symfony2 application with two entities: Municipality and Poi. There is a relation "One-To-Many" between Municipality and Pois (i.e: zero or more pois placed in one municipality), so the Entity files are like this:

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;
    }
}

At this point, I want to manage the One-To-Many relation between the municipality and their pois from the Municipality add/edit form in Sonata Admin.

I have followed the instructions explained in http://sonata-project.org/bundles/doctrine-orm-admin/master/doc/reference/form_field_definition.html#advanced-usage-one-to-many , so the MunicipalityAdmin class file is:

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'
            ))
    ;
    }
}

The form I am trying to get is an add/edit form where I can define de name of the municipality and add/remove associated pois from the Poi entity, but what I actually get is a form where I can define the name of the municipality, and manage the Poi entity in a kind of sub-form.

This screenshoot describe the result --> http://i.imgur.com/nM1ywwh.png

I mean, in this way, I can add new Pois and relations with any municipality (i.e: Los Angeles), but what I'm trying to get is a list of al pois that are related to this municipality and the posibility to:

  • Add new relations (i.e: associate an orphan Poi like Statue of Liberty to this municipality (New York)).
  • Remove existing relations (i.e: remove an incorrect relation like "Walt Disney Concert Hall" in New York)

I've seen the way to manage this in the reverse way, selecting the Municipality related to each Poi in the Poi add/edit form (Many-to-one), but I wonder if is there any way to manage this relations in the other entity.

Can I do this in SonataAdmin? Any clue?

UPDATE: Solved the UI and adding pois, but not deleting

I've got the way to show widget that I am looking for, by definining the form in this way:

protected function configureFormFields(FormMapper $formMapper)
{
    $formMapper
        ->add('name')
        ->add('pois', null, array(), array(
            'edit' => 'inline',
            'inline' => 'table',
            'sortable'  => 'position'
        ))
;
}

What I did is to change 'sonata_type_collection' for null value. Now I get a form like this screenshot -->

... that as just the behavior I want.

Initially, the additions in this widget (i.e: add new pois to a municipality), didn't persist. Thanks to the comment of Radomir Wojtera, I realized that there was methods not implemented in my Municipality Entity class (setPois, addPoi and removePoi).

I added this methods ...

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);
}

... and now I'm able to grab new Pois for a Municipality, but when I remove some Pois, they did't disassociate. so I can add relations, but not remove.

解决方案

Finally I can resolve the second issue (removing Poi from a Municipality didn't work) by setting orphanRemoval=true in Entity configuration

class Municipality
{
    /**
     * @ORM\OneToMany(targetEntity="Poi", mappedBy="municipality", cascade={"persist"}, orphanRemoval=true))
     */
    protected $pois;
...

The first issue is solved as commented in the question update.

这篇关于SonataAdmin和Symfony2中的一对多关系和添加/编辑表单的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆