在Symfony 4上提交表单后,嵌入表单集合将使Collection为null

时间:2018-11-07 19:41:57

标签: forms symfony collections

我正在使用本教程:https://symfony.com/doc/current/form/form_collections.html,提交表单后,我在Product实体中有空PickupPoint集合(请查看var_dump())。可以渲染新的pickupPoints表单。有什么想法吗?

我的ProductType.php代码:

namespace App\Form\Product;

use App\Entity\Order\Contract;
use App\Entity\Product\Category;
use App\Entity\Product\Product;
use App\Repository\Order\ContractRepository;
use App\Repository\Product\CategoryRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * Class ProductType
 */
class ProductType extends AbstractType
{
    /**
     * @var User
     */
    private $user;

    /**
     * ProductType constructor.
     *
     * @param TokenStorageInterface $tokenStorage
     */
    public function __construct(TokenStorageInterface $tokenStorage)
    {
        $this->user = $tokenStorage->getToken()->getUser();
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('contract', EntityType::class, [
                    'constraints' => [
                        new Assert\NotBlank(),
                        new Assert\NotNull()
                    ],
                    'placeholder' => '',
                    'class' => Contract::class,
                    'query_builder' => function (ContractRepository $er) use ($options) {
                        return $er->createQueryBuilder('c')
                            ->where('user = :user')
                            ->setParameter('user', $this->user)
                            ->orderBy('c.name', 'ASC');
                    },
                ]
            )
            ->add('pickupPoints', CollectionType::class, [
                'entry_type' => PickupPointsTypeInProduct::class,
                'entry_options' => ['label' => false],
                'allow_add' => true,
                'allow_delete' => true,
                'by_reference' => false,
                'prototype' => true,
            ]);
        ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => Product::class,
        ));
    }
}

控制器代码:

    /**
     * @Route("/product/add", name="panel_product_add")
     *
     * @param Request $request
     *
     * @return Response
     */
    public function add(Request $request)
    {
        $product = new Product();
        $form = $this->createForm(ProductType::class, $product);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            /** @var Product $product */
            $product = $form->getData();
            var_dump($product->getPickupPoints());
            die;
            $product->setUser($this->getUser());
            $product->setAmountInRent(0);

            $this->entityManager->persist($product);
            $this->entityManager->flush();

            return $this->redirect($this->generateUrl('user_panel_products'));
        }

        return $this->render('user/panel/product/add.html.twig', [
            'form' => $form->createView(),
        ]);
    }

在“产品”实体中:

/**
 * @param PickupPoint $pickupPoint
 */
public function addPickupPoint(PickupPoint $pickupPoint)
{
    $pickupPoint->addProduct($this); // synchronously updating inverse side
    $this->pickupPoints->add($pickupPoint);
}

public function removePickupPoint(PickupPoint $pickupPoint)//TODO
{
    $this->pickupPoints->removeElement($pickupPoint);
}

视图:

               <div class="panel-body">
                    {% for pickupPoint in form.pickupPoints %}
                        <li>{{ form_row(pickupPoint.name) }}</li>
                    {% endfor %}
                    <ul class="tags" data-prototype="{{ form_widget(form.pickupPoints.vars.prototype)|e('html_attr') }}">
                    </ul>
                </div>
                <div class="panel-footer">
                    <button class="btn-success btn">add</button>
                </div>
            </div>
        </div>
    </div>
    {{ form_widget(form._token) }}
    {{ form_end(form, {'render_rest': false}) }}
{% endblock %}
{% block scripts %}
    <script>
        // setup an "add a tag" link
        var $addTagLink = $('<a href="#" class="add_tag_link">Add a tag</a>');
        var $newLinkLi = $('<li></li>').append($addTagLink);

        jQuery(document).ready(function() {
            // Get the ul that holds the collection of tags
            var $collectionHolder = $('ul.tags');

            // add the "add a tag" anchor and li to the tags ul
            $collectionHolder.append($newLinkLi);

            $collectionHolder.find('li').each(function() {
                addTagFormDeleteLink($(this));
            });

            // count the current form inputs we have (e.g. 2), use that as the new
            // index when inserting a new item (e.g. 2)
            $collectionHolder.data('index', $collectionHolder.find(':input').length);

            $addTagLink.on('click', function(e) {
                // prevent the link from creating a "#" on the URL
                e.preventDefault();

                // add a new tag form (see code block below)
                addTagForm($collectionHolder, $newLinkLi);
            });


        });

        function addTagForm($collectionHolder, $newLinkLi) {
            // Get the data-prototype explained earlier
            var prototype = $collectionHolder.data('prototype');

            // get the new index
            var index = $collectionHolder.data('index');

            var newForm = prototype;
            // You need this only if you didn't set 'label' => false in your tags field in TaskType
            // Replace '__name__label__' in the prototype's HTML to
            // instead be a number based on how many items we have
            // newForm = newForm.replace(/__name__label__/g, index);

            // Replace '__name__' in the prototype's HTML to
            // instead be a number based on how many items we have
            newForm = newForm.replace(/__name__/g, index);

            // increase the index with one for the next item
            $collectionHolder.data('index', index + 1);

            // Display the form in the page in an li, before the "Add a tag" link li
            var $newFormLi = $('<li></li>').append(newForm);
            $newLinkLi.before($newFormLi);
            addTagFormDeleteLink($newFormLi);
        }

        function addTagFormDeleteLink($tagFormLi) {
            var $removeFormButton = $('<button type="button">Delete this tag</button>');
            $tagFormLi.append($removeFormButton);

            $removeFormButton.on('click', function(e) {
                // remove the li for the tag form
                $tagFormLi.remove();
            });
        }
    </script>
{% endblock %}

0 个答案:

没有答案