我正在使用本教程: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 %}