我在Symfony 3中的表单有问题。我有一对多连接(Doctrine 2)。它处理订单(订单),产品(产品)和加入实体( OrderProduct ),它按顺序保存产品数量。
添加和更新订单条目的表单,使用订单产品集合。这一切都基于文档(link)。
在表单中,我有一个按钮,用于添加产品(从文档中添加< li>到DOM),每个添加的按钮都有一个按钮 (从文档中删除DOM中的< li>)。这部分工作 - 添加和删除DOM。
添加产品有效(在新订单中,与编辑时相比)。
但我的问题是删除。在 $ editForm-> getData() 中仍然显示 。
OrderProduct表格
namespace AppBundle\Form;
use AppBundle\Entity\ProductType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class OrderProductType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('amount')
->add('product')
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
array(
'data_class' => 'AppBundle\Entity\OrderProduct',
)
);
}
public function getName()
{
return 'app_bundle_order_product_type';
}
}
订购单
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class OrderType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('customer')
->add('date', null, array('widget' => 'single_text'))
->add('payment', null, array('widget' => 'single_text'))
->add('processed', null, array('widget' => 'single_text'))
->add(
'orderProducts',
CollectionType::class,
array(
'entry_type' => OrderProductType::class,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'prototype' => true,
'delete_empty' => true,
'entry_options' => array('data_class' => 'AppBundle\Entity\OrderProduct'),
)
);
}
public function configureOptions(OptionsResolver $resolver)
{
}
public function getName()
{
return 'app_bundle_order_type';
}
}
OrderController中的当前操作 (添加产品,不删除) public function editAction(Request $ request,$ orderId){
$em = $this->getDoctrine()->getManager();
$order = $em->getRepository('AppBundle:Order')->find($orderId);
if (!$order) {
throw $this->createNotFoundException('No order found for id '.$orderId);
}
$editForm = $this->createForm(OrderType::class, $order);
$editForm->add('submit', SubmitType::class);
$editForm->handleRequest($request);
if ($editForm->isSubmitted() && $editForm->isValid()) {
$order = $editForm->getData();
//print '<pre>';
//var_dump($order->getOrderProducts());
//die();
$orderProducts = $order->getOrderProducts();
$em->persist($order);
foreach ($orderProducts as $oneOrderProduct) {
$oneOrderProduct->setOrder($order);
$em->persist($oneOrderProduct);
}
//print '<pre>';
//var_dump($order->getOrderProducts());
//die();
$em->flush();
return $this->redirectToRoute('one_order', array('orderId' => $order->getId()));
}
return $this->render(
'order/new.html.twig', array(
'form' => $editForm->createView(),
));
}
我知道我必须在editAction中从Order中删除已删除的OrderProducts,但现在我不能,因为从表单中发送所有OrderProducts。
订单实体
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\Common\Collections\ArrayCollection;
use AppBundle\Entity\OrderProduct;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
/**
* @ORM\Entity
* @ORM\Table(name="order_")
*/
class Order
{
/**
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity="Customer", inversedBy="orders")
* @ORM\JoinColumn(name="customer_id", referencedColumnName="id")
*/
private $customer;
/**
* @ORM\Column(type="date")
*/
private $date;
/**
* @ORM\Column(type="date")
*/
private $payment;
/**
* @ORM\Column(type="date")
*/
private $processed;
public function __toString()
{
return strval($this->getId());
}
/**
* @ORM\OneToMany(targetEntity="OrderProduct", mappedBy="order")
*/
private $orderProducts;
public function __construct()
{
$this->orderProducts = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set date
*
* @param \DateTime $date
*
* @return Order
*/
public function setDate($date)
{
$this->date = $date;
return $this;
}
/**
* Get date
*
* @return \DateTime
*/
public function getDate()
{
return $this->date;
}
/**
* Set payment
*
* @param \DateTime $payment
*
* @return Order
*/
public function setPayment($payment)
{
$this->payment = $payment;
return $this;
}
/**
* Get payment
*
* @return \DateTime
*/
public function getPayment()
{
return $this->payment;
}
/**
* Set processed
*
* @param \DateTime $processed
*
* @return Order
*/
public function setProcessed($processed)
{
$this->processed = $processed;
return $this;
}
/**
* Get processed
*
* @return \DateTime
*/
public function getProcessed()
{
return $this->processed;
}
/**
* Set customer
*
* @param \AppBundle\Entity\Customer $customer
*
* @return Order
*/
public function setCustomer(\AppBundle\Entity\Customer $customer = null)
{
$this->customer = $customer;
return $this;
}
/**
* Get customer
*
* @return \AppBundle\Entity\Customer
*/
public function getCustomer()
{
return $this->customer;
}
/**
* Add orderProduct
*
* @param \AppBundle\Entity\OrderProduct $orderProduct
*
* @return Order
*/
public function addOrderProduct(\AppBundle\Entity\OrderProduct $orderProduct)
{
$this->orderProducts[] = $orderProduct;
return $this;
}
/**
* Remove orderProduct
*
* @param \AppBundle\Entity\OrderProduct $orderProduct
*/
public function removeOrderProduct(\AppBundle\Entity\OrderProduct $orderProduct)
{
$this->orderProducts->removeElement($orderProduct);
}
/**
* Get orderProducts
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getOrderProducts()
{
return $this->orderProducts;
}
}
但是在POST中没关系as you can see here,在这里我删除了4个产品中的2个。表单处理中出现问题。
答案 0 :(得分:0)
如果by_reference设置为false,则基础Order实体必须在您的案例中有一个名为[removeOrderProduct]的方法。可能还有一个问题是您没有在configureOptions方法中指定data_class选项。在您的情况下,如果Order实体位于'AppBundle \ Entity \ Order'中,则configureOptions方法应包含:
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Order',
));
}
我建议你也在OrderProductType类中做同样的事情。 我的猜测是,既然你没有在OrderType类中指定'data_class'选项,'orderProducts'字段中的by_reference选项可能无法找出在哪里查找[removeOrderProduct]方法。所以设置该选项并确保在Order实体类中有该方法。
如果这不是问题,那么您应该提供有关订单实体的更多信息以及您在何处调用getData方法。
更新
查看您的代码我无法识别问题,这可能导致实体无法删除。但是我在你的代码中发现了一些奇怪的东西:
在控制器中,当处理表单提交时,没有必要调用getData方法:在调用handleRequest之后,$ order对象会更新并保存新信息(因为对象是通过引用传递的,所以表单不能应用更改而不更改原始$ order也是如此)。因此,不需要$ order = $ form-&gt; getData(),因为您之前已经定义了$ order变量,它保存了对表单映射已发布值的同一对象的引用。
如果这没有用,我建议你加模;遍布各处的语句,只是为了确保在每一步调用正确的方法。例如添加模具;到removeOrderProduct方法,检查它是否命中。如果它被击中,问题就不会从您提供给我们的数据中显而易见,因此需要进一步调试。
现在也可能不是问题,但是如果你想在提交后删除列表中不存在的产品,你必须调用$ order-&gt; getOrderProducts并将每个项目添加到一个新的集合中之前的orderProducts(在提交之前)并将其与提交后的值进行比较,以确定哪些需要删除。
答案 1 :(得分:0)
我昨晚解决了这个问题:)
这是有效的控制器操作:
/**
* @Route("/{orderId}/edit", name="edit_order", requirements={"orderId": "\d+"})
* @param Request $request
* @param $orderId
*
* @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
*/
public function editAction(Request $request, $orderId)
{
$em = $this->getDoctrine()->getManager();
$order = $em->getRepository('AppBundle:Order')->find($orderId);
if (!$order) {
return $this->redirectToRoute('new_order');
}
$originalOrderProducts = new ArrayCollection();
foreach ($order->getOrderProducts() as $orderProduct) {
$originalOrderProducts->add($orderProduct);
}
$editForm = $this->createForm(OrderType::class, $order);
$editForm->add('submit', SubmitType::class);
$editForm->handleRequest($request);
if ($editForm->isSubmitted() && $editForm->isValid()) {
$orderProducts = $order->getOrderProducts();
foreach ($originalOrderProducts as $oneOriginalOrderProduct) {
if (false === $order->getOrderProducts()->contains($oneOriginalOrderProduct)) {
$order->removeOrderProduct($oneOriginalOrderProduct);
$em->remove($oneOriginalOrderProduct);
$em->flush();
}
}
foreach ($orderProducts as $oneOrderProduct) {
if ($oneOrderProduct->getAmount() == 0) {
$order->removeOrderProduct($oneOrderProduct);
$em->remove($oneOrderProduct);
} else {
if (!$originalOrderProducts->contains($oneOrderProduct)) {
$oneOrderProduct->setOrder($order);
}
$em->persist($oneOrderProduct);
}
$em->persist($order);
$em->flush();
}
return $this->redirectToRoute('order');
}
return $this->render('order/new.html.twig', array('form' => $editForm->createView()));
}