Symfony 3.3:无法添加和删除具有集合表单类型的同一实体的项目



我是Symfony的新手,所以我从官方教程开始,安装了Symfony框架3.3.2,并在根据我的特定需求自定义实体,控制器,表单和视图的同时完成了教程。

所以基本上我有一个名为 BasePreset 的实体,数据库中已经有几行,我终于设法创建了一个表单集合类型,该类型呈现带有"添加"和"删除"链接的可编辑 BasePreset 实体字段列表:第一个将新的空白字段添加到列表中,每个"删除"链接从 DOM 中删除相应的字段。 一切都根据文档。

所以我成功地更新了现有字段(我在重新加载后和数据库中看到了表单 HTML 中的正确更改(。

问题是,添加/删除不起作用。没有给出错误。已检查 Chrome 开发工具:参数按预期发送。

我使用了以下有关表单构建器的文档(当然还有很多谷歌搜索(:

http://symfony.com/doc/current/forms.html

https://symfony.com/doc/current/best_practices/forms.html

https://symfony.com/doc/current/form/form_collections.html

https://symfony.com/doc/current/reference/forms/types/collection.html

现在,在本文档中声明:

你必须同时创建addTag((和removeTag((方法,否则 表单仍将使用 setTag(( 即使by_reference是假的。你会 在本文后面了解有关 removeTag(( 方法的更多信息。

目前,我没有任何引用的子实体,如示例中所述。我只想能够编辑相同的普通实体,包括添加新项目和删除现有项目。也许我错了,但这在我心目中似乎是一个微不足道的基本目标。我不明白如何将"setBasePreset"和"removeBasePreset"方法正确添加到"BasePreset"实体本身。

当然,我可以跳过使用表单构建器,但我想利用它作为框架的一部分。任何建议,例如,也许指向我错过的一些相关文档/教程 - 将不胜感激。

发布示例(一个添加和一个删除(:

base_presets[base_presets][5][name]:new_preset
base_presets[base_presets][5][description]:new, not really added
base_presets[base_presets][0][name]:ffffas44432df
base_presets[base_presets][0][description]:asdfffff2333
base_presets[base_presets][2][name]:ffffasdf2222
base_presets[base_presets][2][description]:asdff3fff2333
base_presets[base_presets][3][name]:yoyoshka
base_presets[base_presets][3][description]:nananaf
base_presets[base_presets][4][name]:123fffdsaasdf
base_presets[base_presets][4][description]:pop123
base_presets[_token]:H2QwRHdvZW1WAdc6VTONnspxvH1U-oC8rCEEprDdMCQ

"BasePresetsType"类:

<?php
namespace AppBundleForm;
use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolver;
use SymfonyComponentFormExtensionCoreTypeCollectionType;
class BasePresetsType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('base_presets', CollectionType::class, array(
'entry_type' => BasePresetType::class,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false // also tried 'true' but without any success
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => null,
));
}
}

"BasePresetType"类:

<?php
namespace AppBundleForm;
use AppBundleEntityBasePreset;
use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolver;
use SymfonyComponentFormExtensionCoreTypeTextType;
use SymfonyComponentFormExtensionCoreTypeTextareaType;
class BasePresetType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('name', TextType::class)
->add('description', TextareaType::class);
}
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults([
'data_class' => BasePreset::class,
]);
}
}

控制器方法:

<?php
// ...
/**
* @Route("/admin/list_base_presets", name="list_base_presets")
*/
public function listBasePresetsAction(Request $request, EntityManagerInterface $em, LoggerInterface $logger) {
$base_presets = $em->getRepository("AppBundleEntityBasePreset")->findAll();
$form = $this->createForm(BasePresetsType::class, array('base_presets' => $base_presets));
$form->handleRequest($request);
$current_route = $request->get('_route');
if ($form->isSubmitted() && $form->isValid()) {
foreach ($base_presets as $base_preset) {
$em->persist($base_preset);
}
$em->flush();
// ... do other work - like sending an email, etc..
// maybe set a 'flash' success message for the user
return $this->redirectToRoute($current_route);
}
return $this->render('manage_params/list_base_presets.html.twig', array(
'form' => $form->createView()
));
}

观点:

{% extends "base.html.twig" %}
{% block body %}
{{ form_start(form) }}
{{ form_label(form.base_presets) }}
{{ form_errors(form.base_presets) }}
<ul class="base-presets" data-prototype="{{ form_widget(form.base_presets.vars.prototype)|e('html_attr') }}">
{% for base_preset in form.base_presets %}
<li class="base-preset-item">
{{ form_errors(base_preset) }}
{{ form_widget(base_preset) }}
</li>
{% endfor %}
<li class="form-submit">
<input type="submit" value="Submit" class="btn btn-default pull-right" />
</li>
</ul>
{{ form_end(form) }}
{% endblock %}
{% block javascripts %}
<script>
var $collection_holder;
// Setup an "add a base preset" link
var $add_base_preset_link = $('<a href="#" class="add_base_preset_link">Add a base preset</a>');
var $new_link_li = $('<li></li>').append($add_base_preset_link);
$(document).ready(function () {
// Get the ul that holds the collection of base presets
$collection_holder = $('ul.base-presets');
// add the "add a base preset" anchor and li to the tags ul
$collection_holder.prepend($new_link_li);
// count the current form inputs we have, use that as the new index when inserting a new item
$collection_holder.data('index', $collection_holder.find('li.base-preset-item').length);
$add_base_preset_link.on('click', function (e) {
e.preventDefault();
addBasePresetForm($collection_holder, $new_link_li);
});
// add a delete link to all of the existing base presets form li elements
$collection_holder.find('li.base-preset-item').each(function () {
addBasePresetFormDeleteLink($(this));
});
});
function addBasePresetForm($collection_holder, $new_link_li) {
// Get the data-prototype
var prototype = $collection_holder.data('prototype');
// Get the new index
var index = $collection_holder.data('index');
// Replace '__name__' in the prototype's HTML to instead be a number based on how many items we have
var new_form = prototype.replace(/__name__/g, index);
// increment the index for the next item
$collection_holder.data('index', index + 1);
// Display the form in the page in an li, before the "Add a base preset" link li
var $new_form_li = $('<li class="base-preset-item"></li>').append(new_form);
$new_link_li.after($new_form_li);
addBasePresetFormDeleteLink($new_form_li);
}
function addBasePresetFormDeleteLink($base_preset_form_li) {
var $remove_form_a = $('<a href="#">Delete this base preset</a>');
$base_preset_form_li.append($remove_form_a);
$remove_form_a.on('click', function (e) {
e.preventDefault();
$base_preset_form_li.remove();
})
}
</script>
{% endblock %}

最后,最长的列表 - "BasePreset"实体类:

<?php
namespace AppBundleEntity;
use DoctrineCommonCollectionsArrayCollection;
use DoctrineORMMapping as ORM;
use SymfonyComponentValidatorConstraints as Assert;
use SymfonyBridgeDoctrineValidatorConstraintsUniqueEntity;

/**
* Class BasePreset
* @package AppBundleEntity
*
* @ORMEntity
* @ORMTable(name="base_presets")
* @UniqueEntity(fields="name", message="There should be only one (unique) base preset")
*/
class BasePreset {
/**
* @ORMOneToMany(targetEntity="BaseParamsGroup", mappedBy="base_preset")
*/
private $base_params_groups;
/**
* @var int
*
* @ORMColumn(type="integer")
* @ORMId
* @ORMGeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORMColumn(type="string", length=100)
*/
private $name;
/**
* @var string
*
* @AssertNotBlank()
* @ORMColumn(type="string", length=4000)
*/
private $description;
/**
* @var DateTime
*
* @ORMColumn(type="datetime")
*/
private $created;
/**
* @var DateTime
*
* @ORMColumn(type="datetime", columnDefinition="TIMESTAMP on update CURRENT_TIMESTAMP")
*/
private $updated;
public function __construct() {
$this->base_params_groups = new ArrayCollection();
$this->created = new DateTime();
$this->updated = new DateTime();
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* @param string $name
*
* @return BasePreset
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Set description
*
* @param string $description
*
* @return BasePreset
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* @return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set created
*
* @param DateTime $created
*
* @return BasePreset
*/
public function setCreated($created)
{
$this->created = $created;
return $this;
}
/**
* Get created
*
* @return DateTime
*/
public function getCreated()
{
return $this->created;
}
/**
* Set updated
*
* @param DateTime $updated
*
* @return BasePreset
*/
public function setUpdated($updated)
{
$this->updated = $updated;
return $this;
}
/**
* Get updated
*
* @return DateTime
*/
public function getUpdated()
{
return $this->updated;
}
/**
* Add baseParamsGroup
*
* @param AppBundleEntityBaseParamsGroup $baseParamsGroup
*
* @return BasePreset
*/
public function addBaseParamsGroup(AppBundleEntityBaseParamsGroup $baseParamsGroup)
{
$this->base_params_groups[] = $baseParamsGroup;
return $this;
}
/**
* Remove baseParamsGroup
*
* @param AppBundleEntityBaseParamsGroup $baseParamsGroup
*/
public function removeBaseParamsGroup(AppBundleEntityBaseParamsGroup $baseParamsGroup)
{
$this->base_params_groups->removeElement($baseParamsGroup);
}
/**
* Get baseParamsGroups
*
* @return DoctrineCommonCollectionsCollection
*/
public function getBaseParamsGroups()
{
return $this->base_params_groups;
}
}

由于您使用的表单没有数据类,因此您需要直接从表单对象访问提交的数据:

foreach ($form->get('base_presets')->getData() as $base_preset) {
$em->persist($base_preset);
}

更新
与管理现有和持久化的新内容一起工作。如果需要删除实体,可以将从数据库加载的实体与提交的实体进行比较,然后删除筛选的实体。

相关内容

  • 没有找到相关文章

最新更新