Symfony 3.3:无法使用集合表单类型

时间:2017-07-11 11:51:17

标签: symfony doctrine-orm symfony-forms symfony-3.3

我是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;
    }
}

1 个答案:

答案 0 :(得分:1)

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

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

<强>更新
这与管理现有的和持久的新的一起工作。如果需要删除实体,可以将从DB加载的实体与提交的实体进行比较,然后删除已过滤的实体。