Sonata Admin Bundle:刷新同一实体类型的多个Sonata_model_type输入


Sonata Admin Bundle: Refresh multiple sonata_model_type inputs of the same entity type?

我有两个实体Location和Person。Person与Location实体有四种多对一关系。

一个人有以下每个位置之一:

  • 家乡
  • 列出项目
  • 当前城镇
  • 离港到达

像这样:

class Person {
/**
 * @var integer
 *
 * @ORM'Column(name="id", type="integer")
 * @ORM'Id
 * @ORM'GeneratedValue(strategy="AUTO")
 */
private $id;
/**
 * @var string
 *
 * @ORM'Column(name="notes", type="string", length=255, nullable=false)
 */
private $name;
/**
 * @ORM'ManyToOne(targetEntity="Location", inversedBy="locationHomeTowns")
 * @ORM'JoinColumn(name="home_town_location_id", referencedColumnName="id", onDelete="SET NULL")
 */
protected $locationHomeTown;
/**
 * @ORM'ManyToOne(targetEntity="Location", inversedBy="locationCurrentTowns")
 * @ORM'JoinColumn(name="current_town_location_id", referencedColumnName="id", onDelete="SET NULL")
 */
protected $locationCurrentTown;
/**
 * @ORM'ManyToOne(targetEntity="Location", inversedBy="locationDepartures")
 * @ORM'JoinColumn(name="departure_location_id", referencedColumnName="id", onDelete="SET NULL")
 */
protected $locationDeparture;
/**
 * @ORM'ManyToOne(targetEntity="Location", inversedBy="locationArrivals")
 * @ORM'JoinColumn(name="arrival_location_id", referencedColumnName="id", onDelete="SET NULL")
 */
protected $locationArrival;
…
}
class Location {
/**
 * @var integer
 *
 * @ORM'Column(name="id", type="integer")
 * @ORM'Id
 * @ORM'GeneratedValue(strategy="AUTO")
 */
private $id;
/**
 * @var string
 *
 * @ORM'Column(name="latitude", type="decimal", scale=12, precision=18, nullable=false)
 */
private $latitude;
/**
 * @var string
 *
 * @ORM'Column(name="longitude", type="decimal", scale=12, precision=18, nullable=false)
 */
private $longitude;
/**
 * @var string
 *
 * @ORM'Column(name="notes", type="string", length=255, nullable=false)
 */
private $name;
/**
 * @ORM'OneToMany(targetEntity="Person", mappedBy="locationHomeTown", cascade={"persist"}, orphanRemoval=false)
 */
protected $locationHomeTowns;
/**
 * @ORM'OneToMany(targetEntity="Person", mappedBy="locationCurrentTown", cascade={"persist"}, orphanRemoval=false)
 */
protected $locationCurrentTowns;
/**
 * @ORM'OneToMany(targetEntity="Person", mappedBy="locationDeparture", cascade={"persist"}, orphanRemoval=false)
 */
protected $locationDepartures;
/**
 * @ORM'OneToMany(targetEntity="Person", mappedBy="locationArrival", cascade={"persist"}, orphanRemoval=false)
 */
protected $locationArrivals;
…
}

我已经设置了如下两个实体的管理类:

class LocationAdmin extends Admin {
…
/**
 * @param FormMapper $formMapper
 */
protected function configureFormFields(FormMapper $formMapper) {
    $formMapper
            ->add('longitude', null, array('attr' => array(
                    'placeholder' => 'decimal degrees e.g. 51.5072',
        )))
            ->add('latitude', null, array('attr' => array(
                    'placeholder' => 'decimal degrees e.g. -0.1275',
        )))
            ->add('name')
        ;
    }
…
}
class ExileAdmin extends Admin {
…
/**
 * @param FormMapper $formMapper
 */
protected function configureFormFields(FormMapper $formMapper) {
    $formMapper
            ->add('name')
            ->add('locationHomeTown', 'sonata_type_model', array(
                'required' => false
           ))
           ->add('locationCurrentTown', 'sonata_type_model', array(
                'required' => false
           ))
           ->add('locationDeparture', 'sonata_type_model', array(
                'required' => false
           ))
           ->add('locationArrival', 'sonata_type_model', array(
                'required' => false
           ))
           ;
    }
…
}

我在person表单中将位置设置为sonata_type_model,以便在编辑person实体时添加新位置。这对于每个输入都是按预期工作的,但是只有位置列表会更新。这意味着,如果我需要在表单上的其他位置字段中使用这个新位置,我必须保存整个人员表单。

当我将一个新的位置添加到其他输入时,有没有一种方法可以更新所有的位置输入小部件?

例如,如果我目前在数据库中存储了伦敦巴黎柏林,并将罗马添加到家乡,我希望当前城市出发到达的表单输入小部件也能更新。如果我将都柏林添加到当前城镇,我希望家乡出发到达也进行更新,依此类推,以更新离开以及抵达

您需要做的是在新位置预存在时捕获sonata-admin-append-form-element javascript事件,并将所有其他select元素的选项与触发的选项同步。

首先覆盖Sonata的表单管理字段;这将为表单中的每个元素生成事件处理javascript块。

我知道这不是在for循环中使用"选择"选择器和过滤适当元素的最优雅的方法,但这可能会对您有所指导。

YourBundle/resources/views/Form/Form_admin_fields.html.twig

{% extends 'SonataAdminBundle:Form:form_admin_fields.html.twig' %}
{% block sonata_admin_orm_many_to_one_widget %}
    {% include 'SonataDoctrineORMAdminBundle:CRUD:edit_orm_many_to_one.html.twig' %}
    <script type="text/javascript"> 
    /*The event fires twice after appending Location element, 
      so I remove the listener at first*/
    $('div[id$={{form.vars['id']}}]').off('sonata-admin-append-form-element');
    $('div[id$={{form.vars['id']}}]').on('sonata-admin-append-form-element', function(event) {
        //I loop every children of parent form
        {% for element in form.parent.children %}
            if({{element.vars['id']}}!={{form.vars['id']}}) {
                /*Copy the options from the current select 
                element with the most update values*/
                var opts = $('#{{form.vars['id']}} > option').clone();
                //console.log($('select[id$={{element.vars["id"]}}]'));
                /* I add the most updated options 
                to other select elements.
                */
                $('select[id$={{element.vars["id"]}}]').empty();
                $('select[id$={{element.vars["id"]}}]').append(opts);

            }
        {% endfor %}
    });
    </script>
{% endblock %}

然后覆盖您的ExileAdmin getFormTheme方法;

  public function getFormTheme()
  {
      return array_merge(
          parent::getFormTheme(),
          array('YourBundle:Form:form_admin_fields.html.twig')
      );
  }

我想现在就是这样了,当你坚持一个位置时,所有选择的元素都会与最新的元素同步。