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
))
;
}
…
}
我在人员表单中将位置设置为 sonata_type_model 以允许我在编辑人员实体时添加新位置。这对每个输入都按预期工作,但是只有位置列表会更新。这意味着如果我需要在表单上的其他位置字段之一中使用这个新位置,我必须保存整个 Person 表单。
当我将新位置添加到其他输入之一时,是否可以更新所有位置输入小部件?
例如,如果我目前有 London、Paris 和 Berlin 存储在数据库,我将 Rome 添加到 Home Town 我想要 Current Town 的表单输入小部件,出发和到达也要更新。如果我然后将 Dublin 添加到 Current Town 我想要 Home Town, Departure 和 Arrival 也会更新,以此类推 Departure 和 Arrival.
您需要做的是在新位置存在时捕获 sonata-admin-append-form-element
javascript 事件,并将所有其他 select 元素的选项与触发的选项同步。
首先覆盖 Sonata 的表单管理字段;这将为表单中的每个元素生成事件处理 javascript 块。
我知道这不是在 for 循环中使用 "select" selectors 和过滤适当元素的最优雅方式,但这可能会指导您。
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')
);
}
我想这就是现在,当您坚持一个位置时,所有 select 元素都与最新的元素同步。
我有两个实体 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
))
;
}
…
}
我在人员表单中将位置设置为 sonata_type_model 以允许我在编辑人员实体时添加新位置。这对每个输入都按预期工作,但是只有位置列表会更新。这意味着如果我需要在表单上的其他位置字段之一中使用这个新位置,我必须保存整个 Person 表单。
当我将新位置添加到其他输入之一时,是否可以更新所有位置输入小部件?
例如,如果我目前有 London、Paris 和 Berlin 存储在数据库,我将 Rome 添加到 Home Town 我想要 Current Town 的表单输入小部件,出发和到达也要更新。如果我然后将 Dublin 添加到 Current Town 我想要 Home Town, Departure 和 Arrival 也会更新,以此类推 Departure 和 Arrival.
您需要做的是在新位置存在时捕获 sonata-admin-append-form-element
javascript 事件,并将所有其他 select 元素的选项与触发的选项同步。
首先覆盖 Sonata 的表单管理字段;这将为表单中的每个元素生成事件处理 javascript 块。
我知道这不是在 for 循环中使用 "select" selectors 和过滤适当元素的最优雅方式,但这可能会指导您。
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')
);
}
我想这就是现在,当您坚持一个位置时,所有 select 元素都与最新的元素同步。