Symfony Collection Form Controller Problem



我有一个实体Product。我创建了一个包含以下字段的表单ProductType:

<<ul>
  • 名称/gh>价格
  • 参考
  • 我想创建一个集合,允许用户一次创建和提交多个产品。因此,我创建了一个新的表单,它没有实体Products类型。这个表单包含一个字段:

    • 产品它是一个CollectionType类,条目类型为ProductType。

    在我的模板中,我使用了一个原型,Javascript可以完美地创建它。但是,在提交时,我的所有条目都不会在DB中持久化。我花了几个小时终于找到了一些鼓舞人心的东西,但仍然不起作用:Symfony:从Controller

    中的CollectionType访问未映射的表单字段你看到我的错误(在控制器我猜)吗?

    ProductController

    //[...]
    class ProductController extends AbstractController
    {
    /**
    * @Route("/product", name="product")
    */
    public function index(): Response
    {
    $request = new Request();
    $formProduct = $this->createForm('AppFormProductsType');
    $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(),
    ]);
    }
    }
    

    ProductType

    //[...]
    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,
    ]);
    }
    }
    

    ProductsType

    //[...]
    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 %}
    

    希望你能看到我错过的东西。谢谢你:)

    你的控制器方法有几个问题。主要的问题是你对$request = new Request();的使用。这是在创建一个新的Request,而不是客户端发送的请求,因此在该空请求中没有提交表单数据。请求应该作为一个方法参数注入,这样自动连接将从来自客户端的当前http请求构建Request
    https://symfony.com/doc/current/forms.html处理表单

    在进行该更正之后,您的代码应该得到一个与表单中最后一个的值保持一致的Product,因为您只创建一个新的Product并在每次循环中为其设置新值。请参阅下面代码示例中的注释:

    use SymfonyComponentHttpFoundationRequest;
    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('AppFormProductsType');
    // 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(),
    ]);
    }
    }
    

    相关内容

    • 没有找到相关文章

    最新更新