简体   繁体   English

SonataAdmin和Symfony2中的一对多关系和添加/编辑表单

[英]One to Many relations and add/edit form in SonataAdmin and Symfony2

I have a simple Symfony2 application with two entities: Municipality and Poi. 我有一个包含两个实体的简单Symfony2应用程序:Municipality和Poi。 There is a relation "One-To-Many" between Municipality and Pois (ie: zero or more pois placed in one municipality), so the Entity files are like this: 市与Pois之间存在“一对多”关系(即:在一个市中放置零个或更多pois),因此实体文件如下所示:

Poc\\PocBundle\\Entity\\Municipality.php POC \\ PocBundle \\实体\\ 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 POC \\ PocBundle \\实体\\ 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. 在这一点上,我想通过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: 我已经按照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 POC / PocBundle /管理/ 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. 我要获取的表单是一个添加/编辑表单,我可以在其中定义市政当局的名称,并从Poi实体中添加/删除相关的Pois,但实际上,我得到的是一种可以定义市政当局的名称的表单,并以一种子形式管理Poi实体。

This screenshoot describe the result --> http://i.imgur.com/nM1ywwh.png 此屏幕快照描述了结果-> http://i.imgur.com/nM1ywwh.png

I mean, in this way, I can add new Pois and relations with any municipality (ie: 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: 我的意思是,通过这种方式,我可以添加新的Pois以及与任何市政当局(即洛杉矶)的关系,但是我要获取的是与此市政当局有关的al pois列表,并且可以:

  • Add new relations (ie: associate an orphan Poi like Statue of Liberty to this municipality (New York)). 添加新关系(即:将像自由女神像这样的孤儿Poi与该市(纽约)联系起来)。
  • Remove existing relations (ie: 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. 我已经看到了相反的管理方式,可以在Poi添加/编辑表单(多对一)中选择与每个Poi相关的自治市,但是我想知道是否有任何方法可以在其他实体。

Can I do this in SonataAdmin? 我可以在SonataAdmin中这样做吗? Any clue? 有什么线索吗?

UPDATE: Solved the UI and adding pois, but not deleting 更新:解决了用户界面并添加了pois,但未删除

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. 我所做的是将“ sonata_type_collection”更改为空值。 Now I get a form like this screenshot --> 现在,我得到了这样的屏幕截图-> 正确的表格GUI

... that as just the behavior I want. ...这只是我想要的行为。

Initially, the additions in this widget (ie: add new pois to a municipality), didn't persist. 最初,此小部件中的添加项(即:向市政当局添加新的pois)并未持久。 Thanks to the comment of Radomir Wojtera, I realized that there was methods not implemented in my Municipality Entity class (setPois, addPoi and removePoi). 多亏了Radomir Wojtera的评论,我才意识到我的市级实体类(setPois,addPoi和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. ...现在我可以为市政当局获得新的Pois,但是当我删除一些Pois时,它们并没有分离。 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 最后,我可以通过在实体配置中设置orphanRemoval = true来解决第二个问题(从市政当局删除Poi无效)

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. 如问题更新中所述,第一个问题已解决。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM