Collections 更新条目时,如果最后一个元素已存在,则新集合元素将覆盖该元素
所以我有一个任务实体通过多个关系连接到一个选项实体。在创建新任务时,可以添加几个选项(这一点没有问题)。现在,当更新任务时,当我添加一个新选项时,它会覆盖上一个选项(如果它已经存在),否则它很适合。我希望能够在修改任务时添加尽可能多的选项,而不覆盖上一个现有选项。 我发布我的代码: 特派团实体:Collections 更新条目时,如果最后一个元素已存在,则新集合元素将覆盖该元素,collections,many-to-many,symfony4,Collections,Many To Many,Symfony4,所以我有一个任务实体通过多个关系连接到一个选项实体。在创建新任务时,可以添加几个选项(这一点没有问题)。现在,当更新任务时,当我添加一个新选项时,它会覆盖上一个选项(如果它已经存在),否则它很适合。我希望能够在修改任务时添加尽可能多的选项,而不覆盖上一个现有选项。 我发布我的代码: 特派团实体: /** * @var ArrayCollection $options * * @ORM\ManyToMany(targetEntity="App\Entity\O
/**
* @var ArrayCollection $options
*
* @ORM\ManyToMany(targetEntity="App\Entity\Option", inversedBy="missionOptions", cascade={"persist","remove"})
* @ORM\JoinColumn(nullable=true)
*/
protected $options;
/**
* Mission constructor.
*/
public function __construct()
{
$this->options = new ArrayCollection();
}
public function addOption(Option $option)
{
$tag->addMission($this);
$this->options->add($option);
return $this;
}
public function addOptions($options)
{
foreach($options as $option){
$this->addOption($option);
}
return $this;
}
public function removeOption(Option $option)
{
$this->options->removeElement($option);
return $this;
}
public function removeOptions($options)
{
foreach($options as $option){
$this->removeOption($option);
}
return $this;
}
public function setOptions(Option $option)
{
$this->options[] = $option;
return $this;
}
/**
* Get options
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getOptions()
{
return $this->options;
}
期权实体:
/**
* @ORM\ManyToMany(targetEntity="App\Entity\Mission", mappedBy="options", cascade={"persist","remove"})
*/
private $missionOptions;
/**
* Option constructor.
*/
public function __construct()
{
$this->missionOptions = new ArrayCollection();
}
public function setMission($missions)
{
$this->missionOptions = $missions;
}
public function getMission()
{
return $this->missionOptions;
}
public function addMission(Mission $mission)
{
if (!$this->missionOptions->contains($mission)) {
$this->missionOptions->add($mission);
}
return $this;
}
选项类型:
$builder->add('tagname', TextType::class, array(
'required' => true,
'translation_domain' => 'FOSUserBundle',
'label' => 'form.option_name',
'attr' => array(
'class' => 'with-border',
'placeholder' => 'Nouvelle option'
)
))
->add('prix', NumberType::class, array(
'required' => true,
'translation_domain' => 'FOSUserBundle',
'label' => 'form.option_price',
'attr' => array(
'min' => '2000',
'class' => 'with-border',
'placeholder' => 'prix'
)
))
;
任务类型:
$builder->add('options', CollectionType::class, [
'entry_type' => OptionType::class,
'entry_options' => ['label' => false],
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'required' => false
])
在任务控制器中:
public function updateAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('App:Mission')->find($id);
$originalOptions = new ArrayCollection();
foreach ($entity->getOptions() as $option) {
$originalOptions->add($option);
}
$editForm = $this->createEditForm($entity);
$editForm->handleRequest($request);
if ($editForm->isSubmitted() && $editForm->isValid()) {
foreach ($originalOptions as $option) {
if ($option->getTagname() == null || $option->getPrix() == null) {
$option->getMission()->removeElement($entity);
$em->persist($option);
$em->remove($option);
}
}
$em->flush();
return $this->redirectToRoute('dashboard_missions');
}
}
在我的树枝上:
<ul class="options" data-prototype="{{ form_widget(edit_form.options.vars.prototype)|e('html_attr') }}"></ul>
<script>
var $collectionHolder;
var $addTagButton = $('<button type="button" class="button add_option_link"> Ajouter une option</button>');
var $newLinkLi = $('<li></li>').append($addTagButton);
jQuery(document).ready(function() {
$collectionHolder = $('ul.options');
$collectionHolder.append($newLinkLi);
$collectionHolder.data('index', $collectionHolder.find(':input').length);
$addTagButton.on('click', function(e) {
addTagForm($collectionHolder, $newLinkLi);
});
});
function addTagForm($collectionHolder, $newLinkLi) {
var prototype = $collectionHolder.data('prototype');
var index = $collectionHolder.data('index');
var newForm = prototype;
newForm = newForm.replace(/__name__/g, index);
$collectionHolder.data('index', index + 1);
var $newFormLi = $('<li></li>').append(newForm);
$newLinkLi.before($newFormLi);
addTagFormDeleteLink($newFormLi);
}
function addTagFormDeleteLink($tagFormLi) {
var $removeFormButton = $('<button style="margin-left: 10px" type="button" class="button"></button>');
$tagFormLi.append($removeFormButton);
$removeFormButton.on('click', function(e) {
$tagFormLi.remove();
});
}
</script>
var$collectionHolder;
变量$addTagButton=$('ajourne选项');
变量$newLinkLi=$(').append($addTagButton);
jQuery(文档).ready(函数(){
$collectionHolder=$('ul.options');
$collectionHolder.append($newLinkLi);
$collectionHolder.data('index',$collectionHolder.find(':input').length);
$addTagButton.on('click',函数(e){
addTagForm($collectionHolder,$newLinkLi);
});
});
函数addTagForm($collectionHolder,$newLinkLi){
var prototype=$collectionHolder.data('prototype');
var索引=$collectionHolder.data('index');
var newForm=原型;
newForm=newForm.replace(/\u\u name\u\u/g,索引);
$collectionHolder.data('index',index+1);
变量$newFormLi=$('')。追加(newForm);
$newLinkLi.before($newFormLi);
addTagFormDeleteLink($newFormLi);
}
函数addTagFormDeleteLink($tagFormLi){
变量$removeFormButton=$('');
$tagFormLi.append($removeFormButton);
$removeFormButton.on('click',函数(e){
$tagFormLi.remove();
});
}
筛选:
显示编辑:
添加新内容时:
更新后:
提前感谢您提供的所有帮助您描述的观察结果与以下一致 创建表单时,它会添加带有名称的字段
mission_edit[options][0][tagname]
mission_edit[options][0][prix]
mission_edit[options][1][tagname]
mission_edit[options][1][prix]
mission_edit[options][2][tagname]
mission_edit[options][2][prix]
当您添加另外两个选项时,它会添加:
mission_edit[options][0][tagname]
mission_edit[options][0][prix]
mission_edit[options][1][tagname]
mission_edit[options][1][prix]
然后,您将放弃第一个选项(包括原始选项!)
由于php总是覆盖重复的变量名。。。您可以使用新选项覆盖原来的第二个选项(使用索引1
)
您应该通过实际查看DOM来进行验证。如果我的假设是正确的,那么您“聪明地”在细枝模板中省略了表单的特定部分,其中创建了原始元素,这可能在
之外,从而导致ul
上的索引计数器变为0
,并相应地覆盖元素
老实说,我不喜欢使用symfony示例中的特定代码行(您也在使用该代码行),正是因为这个原因,代码行是:
$collectionHolder.data('index',$collectionHolder.find(':input').length)代码>
因为它使用了一组不明显的假设,特别是:您的子表单至少有一个输入类型的字段,这可能不是事实!(例如,可编辑+大量js),并且与您的示例相关,所有现有子项都放在收藏夹中,而您不这样做。公平地说,symfony的例子显示了这一点,这是绝对有效的,因为这里的假设是正确的
相反*我会使用(*表示删除另一行代码!)
数据索引=“{edit_form.options.children | length}}>{{#我在你的小树枝模板中看不到,options
子表单实际上是呈现的,只是一个基本上为空的
。。。
mission_edit[options][0][tagname]
mission_edit[options][0][prix]
mission_edit[options][1][tagname]
mission_edit[options][1][prix]
mission_edit[options][2][tagname]
mission_edit[options][2][prix]
mission_edit[options][1][tagname]
mission_edit[options][1][prix]
<ul class="options"
data-prototype="{{ form_widget(edit_form.options.vars.prototype)|e('html_attr') }}"
data-index="{{ edit_form.options.children|length }}"> {# <- this is the important part!! #}
{# I would also add the existing children here, but there may be reasons not to! #}
</ul>