我是Symfony的新手,所以我从官方教程开始,安装Symfony框架3.3.2并完成教程,同时根据我的特定需求定制实体,控制器,表单和视图。
所以基本上我有一个名为BasePreset的实体,数据库中已经有几行了,我终于设法创建了一个表单集合类型,用#" add&#呈现可编辑的BasePreset实体字段列表39;和'删除'链接:第一个将新的空白字段添加到列表中,并且每个'删除' link从DOM中删除相应的字段。一切都按照文档。
所以我成功更新了现有的字段(我在重新加载后也在数据库中看到了正确的HTML格式更改)。
问题是,添加/删除无法正常工作。没有错误。选中Chrome开发工具:按预期发送参数。
我使用了以下关于表单构建器的文档(当然还有大量的Google搜索):
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
现在,在this doc中声明:
您必须同时创建addTag()和removeTag()方法 即使by_reference为false,表单仍将使用setTag()。你' 11 在本文后面了解有关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 AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
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,
));
}
}
&#39; BasePresetType&#39;类:
<?php
namespace AppBundle\Form;
use AppBundle\Entity\BasePreset;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
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("AppBundle\Entity\BasePreset")->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 %}
最后,最长的列表 - &#39; BasePreset&#39;实体类:
<?php
namespace AppBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* Class BasePreset
* @package AppBundle\Entity
*
* @ORM\Entity
* @ORM\Table(name="base_presets")
* @UniqueEntity(fields="name", message="There should be only one (unique) base preset")
*/
class BasePreset {
/**
* @ORM\OneToMany(targetEntity="BaseParamsGroup", mappedBy="base_preset")
*/
private $base_params_groups;
/**
* @var int
*
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(type="string", length=100)
*/
private $name;
/**
* @var string
*
* @Assert\NotBlank()
* @ORM\Column(type="string", length=4000)
*/
private $description;
/**
* @var \DateTime
*
* @ORM\Column(type="datetime")
*/
private $created;
/**
* @var \DateTime
*
* @ORM\Column(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 \AppBundle\Entity\BaseParamsGroup $baseParamsGroup
*
* @return BasePreset
*/
public function addBaseParamsGroup(\AppBundle\Entity\BaseParamsGroup $baseParamsGroup)
{
$this->base_params_groups[] = $baseParamsGroup;
return $this;
}
/**
* Remove baseParamsGroup
*
* @param \AppBundle\Entity\BaseParamsGroup $baseParamsGroup
*/
public function removeBaseParamsGroup(\AppBundle\Entity\BaseParamsGroup $baseParamsGroup)
{
$this->base_params_groups->removeElement($baseParamsGroup);
}
/**
* Get baseParamsGroups
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getBaseParamsGroups()
{
return $this->base_params_groups;
}
}
答案 0 :(得分:1)
由于您使用不带Data类的表单,因此您需要直接从表单对象访问提交的数据:
foreach ($form->get('base_presets')->getData() as $base_preset) {
$em->persist($base_preset);
}
<强>更新强>:
这与管理现有的和持久的新的一起工作。如果需要删除实体,可以将从DB加载的实体与提交的实体进行比较,然后删除已过滤的实体。