Symfony 集合表单控制器问题
Posted
技术标签:
【中文标题】Symfony 集合表单控制器问题【英文标题】:Symfony Collection Form Controller Problem 【发布时间】:2021-10-25 02:30:00 【问题描述】:我有一个实体产品。我创建了一个带有字段的表单 ProductType :
姓名 价格 参考我想创建一个集合以允许用户一次创建和提交多个产品。 因此,我创建了一个没有实体 ProductsType 的新表单。 此表单包含一个字段:
产品 这是一个具有条目类型 ProductType 的 CollectionType 类。在我的模板中,我使用了一个原型,并且 javascript 可以完美地创建它。 虽然,提交时我的条目都没有保留在数据库中。 我找了几个小时终于找到了一些鼓舞人心的东西,但仍然没有工作: Symfony: Access an unmapped form field from a CollectionType in Controller
你看到我的错误是什么(我猜是在控制器中)吗?
产品控制器
//[...]
class ProductController extends AbstractController
/**
* @Route("/product", name="product")
*/
public function index(): Response
$request = new Request();
$formProduct = $this->createForm('App\Form\ProductsType');
$product = new Product();
$formProduct->handleRequest($request);
if ($formProduct->isSubmitted() && $formProduct->isValid())
foreach ($formProduct->get('products') as $formChild)
$product->setName($formChild->get('name')->getData()); // That's it!
$product->setPrice($formChild->get('price')->getData());
$product->setReference($formChild->get('reference')->getData());
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($product);
$entityManager->flush();
return $this->redirectToRoute('task_success');
return $this->render('product/index.html.twig', [
'formProduct' => $formProduct->createView(),
]);
产品类型
//[...]
class ProductType extends AbstractType
public function buildForm(FormBuilderInterface $builder, array $options)
$builder
->add('name')
->add('price')
->add('reference')
;
public function configureOptions(OptionsResolver $resolver)
$resolver->setDefaults([
'data_class' => Product::class,
]);
产品类型
//[...]
class ProductsType extends AbstractType
public function buildForm(FormBuilderInterface $builder, array $options)
$builder
->add('products', CollectionType::class, [
'entry_type' => ProductType::class,
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
])
;
public function configureOptions(OptionsResolver $resolver)
$resolver->setDefaults([
// Configure your form options here
]);
产品模板(树枝)
% extends 'base.html.twig' %
% block title %Hello ProductController!% endblock %
% block body %
form_start(formProduct)
# store the prototype on the data-prototype attribute #
<ul id="products-fields-list"
data-prototype=" form_widget(formProduct.products.vars.prototype)|e "
data-widget-tags=" '<li></li>'|e "
data-widget-counter=" formProduct.products|length ">
% for products in formProduct.products %
<li>
form_row(products)
</li>
% endfor %
</ul>
<input type="submit" value="Submit">
form_end(formProduct)
<button type="button"
class="add-another-collection-widget"
data-list-selector="#products-fields-list">Add another email</button>
<script>
// add-collection-widget.js
jQuery(document).ready(function ()
jQuery('.add-another-collection-widget').click(function (e)
var list = jQuery(jQuery(this).attr('data-list-selector'));
// Try to find the counter of the list or use the length of the list
var counter = list.data('widget-counter') || list.children().length;
// grab the prototype template
var newWidget = list.attr('data-prototype');
// replace the "__name__" used in the id and name of the prototype
// with a number that's unique to your emails
// end name attribute looks like name="contact[emails][2]"
newWidget = newWidget.replace(/__name__/g, counter);
// Increase the counter
counter++;
// And store it, the length cannot be used if deleting widgets is allowed
list.data('widget-counter', counter);
// create a new list element and add it to the list
var newElem = jQuery(list.attr('data-widget-tags')).html(newWidget);
newElem.appendTo(list);
);
);
</script>
% endblock %
希望您能看到我缺少的东西。谢谢你:)
【问题讨论】:
你说“我的条目都没有被持久化”,但你没有说实际发生了什么。您是被重定向到task_success
路由还是再次收到表单(已填写或未填写)?
确实,我没有重定向到那个页面。所以我想这意味着如果 $formProduct 已提交且 $formProduct 有效,我没有通过条件。我再次收到未填写的表格。
【参考方案1】:
您的控制器方法存在一些问题。主要问题是您使用$request = new Request();
。那是在客户端发送的请求之外创建一个新的Request
,因此在该空请求中没有提交表单数据。该请求应作为方法参数注入,因此自动连接将从客户端的当前 http 请求构建 Request
。https://symfony.com/doc/current/forms.html#processing-forms
在进行更正后,您的代码应该会得到一个与表单中最后一个值保持一致的 Product
,因为您只需创建一个新的 Product
并在每次循环时在其上设置新值.在下面的代码示例中查看我的 cmets:
use Symfony\Component\HttpFoundation\Request;
class ProductController extends AbstractController
/**
* @Route("/product", name="product")
*/
public function index(Request $request): Response
// line below would create empty Request
// $request = new Request();
$formProduct = $this->createForm('App\Form\ProductsType');
// line below would create only ONE Product that would be overwritten in each iteration
// $product = new Product();
$formProduct->handleRequest($request);
if ($formProduct->isSubmitted() && $formProduct->isValid())
// you only need to fetch the entity manager once
$entityManager = $this->getDoctrine()->getManager();
foreach ($formProduct->get('products') as $formChild)
// create a new Product foreach $formChild
$product = new Product();
$product->setName($formChild->get('name')->getData());
$product->setPrice($formChild->get('price')->getData());
$product->setReference($formChild->get('reference')->getData());
// you only need to fetch the entity manager once
// $entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($product);
$entityManager->flush();
return $this->redirectToRoute('task_success');
return $this->render('product/index.html.twig', [
'formProduct' => $formProduct->createView(),
]);
【讨论】:
感谢您的解释。有用。我会阅读表格的文档,因为我遗漏了您解释的内容。再次感谢:)以上是关于Symfony 集合表单控制器问题的主要内容,如果未能解决你的问题,请参考以下文章
将选项从控制器传递到嵌入式 Symfony 表单时,选项不存在错误