简体   繁体   English

页面提交后,将其他项目添加到Symfony2表单集合类型中

[英]Add additional items to a Symfony2 Form Collection type after page submit

I have a form built on the idea of a Purchase. 我有一个基于购买的想法的表格。 It has Purchase Items, a Payment Amount and a Payment Type (VISA, Mastercard, Cash). 它具有采购项目,付款金额和付款类型(VISA,万事达卡,现金)。 I have the form preloaded with 2 Purchase Items however I am trying to add an additional Purchase Item if the user chooses a Card Payment Type (VISA or Mastercard) Type. 我已经预装了2个采购项目的表格,但是如果用户选择卡付款类型(VISA或万事达卡)类型,我试图添加一个额外的采购项目。 This additional Purchase Item I am trying to add via the Controller. 我正在尝试通过控制器添加此额外的购买商品。

Rendered Form view 渲染表单视图

The question is really, where do I implement this functionality in the Controller Action... Or is it better as an EventListener on the Form Type? 问题是,我该在Controller Action中在哪里实现此功能?或者作为EventListener作为Form Type更好?

When the form is submitted with the additional Card Fee Purchase Item I get the following error... 当表格与附加的卡费购买项目一起提交时,出现以下错误...

Catchable Fatal Error: Argument 1 passed to Aazp\\BookingBundle\\Entity\\PurchaseItem::__construct() must be an instance of Aazp\\BookingBundle\\Entity\\Product, none given, called in /project/vendor/symfony/symfony/src/Symfony/Component/Form/Extension/Core/Type/FormType.php on line 141 and defined in /project/src/Aazp/BookingBundle/Entity/PurchaseItem.php line 20 可捕获的致命错误:传递给Aazp \\ BookingBundle \\ Entity \\ PurchaseItem :: __ construct()的参数1必须是Aazp \\ BookingBundle \\ Entity \\ Product的一个实例,未提供任何实例,在/ project / vendor / symfony / symfony / symfony / src / Symfony中调用第141行的/Component/Form/Extension/Core/Type/FormType.php,并在/project/src/Aazp/BookingBundle/Entity/PurchaseItem.php第20行中定义

The BookingController BookingController

namespace Aazp\BookingBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Aazp\BookingBundle\Entity\Booking;
use Aazp\BookingBundle\Entity\Passenger;
use Aazp\BookingBundle\Entity\Payment;
use Aazp\BookingBundle\Entity\Purchase;
use Aazp\BookingBundle\Entity\PurchaseItem;

use Aazp\BookingBundle\Form\PurchaseItemType;
use Aazp\BookingBundle\Form\PurchaseType;

use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;

class BookingController extends Controller
{

    public function passengerPaymentAction($passenger_id)
    {
        $request = Request::createFromGlobals();
        $purchaseBalance = 0.0;

        //Query the selected Passenger
        $em = $this->getDoctrine()->getManager();
        $passenger = $request->attributes->get('passenger', $em->getRepository('AazpBookingBundle:Passenger')->find($passenger_id));
        if (!$passenger) {
            throw $this->createNotFoundException('Unable to find Passenger entity.');
        }

        $purchase = $passenger->getPurchase();
        //Has this Passenger made a Payment. If yes then Purchase exists.
        if($purchase === NULL) //If Purchase does not exist then preload the form with default products.
        {
            $purchase = new Purchase();

            $product_category_photo = $em->getRepository('AazpBookingBundle:ProductCategory')->findOneByName('FLIGHT-PHOTO');

            $product_photo_option = $em->getRepository('AazpBookingBundle:Product')->findOneByProductCategory($product_category_photo);
            if (!$product_photo_option) {
                throw $this->createNotFoundException('Unable to find Flight Photo Product entity.');
            }

            $purchase_item_flight = new PurchaseItem($passenger->getFlight());
            $purchase_item_photo_option = new PurchaseItem($product_photo_option);

            //Add Purchase Items to the Purchase
            $purchase->addPurchaseItem($purchase_item_flight);
            $purchase->addPurchaseItem($purchase_item_photo_option);

            //Set the Purchase on the Passenger
            $passenger->setPurchase($purchase);
        }
        //Ajax call triggered by onChange event on PaymentType radio button in form
        //Add additional Purchase Item for Card Type Payment
        if($form->get('paymentType')->getData()->getId() > 1)
        {
            //PaymentType selected/modified then calculate Payment Fee
            $product_category_card_fee = $em->getRepository('AazpBookingBundle:ProductCategory')->findOneByName('CARD-FEE');
            $product_card_fee = $em->getRepository('AazpBookingBundle:Product')->findOneByProductCategory($product_category_card_fee);
            if (!$productcard_fee) {
            throw $this->createNotFoundException('Unable to find Card Fee Product entity.');
            }

            $purchase_item_card_fee = new PurchaseItem($product_card_fee);

            //Add Purchase Items to the Purchase
            $purchase->addPurchaseItem($purchase_item_card_fee);

            $passenger->setPurchase($purchase);

            return $this->render('AazpBookingBundle:Purchase:summary.html.twig', array(
                'passenger' => $passenger,
                'form'  => $form->createView(),
            ));
        }

        $form = $this->createForm(new PurchaseType($em), $purchase);

        $form->handleRequest($request);

        //If form is Valid create Payment and persist.
        if ($form->isValid())
        {
            $payment = new Payment();
            $payment->setAmount($form->get('paymentAmount')->getData());
            $payment->setPaymentType($form->get('paymentType')->getData());
            $payment->setDescription($form->get('description')->getData());

            $passenger->getPurchase()->addPayment($payment);
            $passenger->getBooking()->setStatus(Booking::STATUS_CONFIRMED);

            $em->persist($passenger->getPurchase());
            $em->flush();
            $this->get('session')->getFlashBag()->add('message', 'Payment '.$payment->getAmount().' CHF has been successful!');

            return $this->redirect($this->generateUrl('booking_show', array ('id'=> $passenger->getBooking()->getId())));
        }

        return $this->render('AazpBookingBundle:Purchase:summary.html.twig', array(
            'passenger' => $passenger,
            'form'  => $form->createView(),
        ));
    }
}

The PurchaseItemType PurchaseItemType

namespace Aazp\BookingBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Aazp\BookingBundle\Entity\ProductRepository;

class PurchaseItemType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('product', 'entity', array('label' => 'Flight', 'class' => 'AazpBookingBundle:Product','property' => 'name', 'empty_value' => 'Please Select', 'required' => false, ));
        $builder->add('amount', 'number', array('precision' => 2));
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array('data_class' => 'Aazp\BookingBundle\Entity\PurchaseItem', ));
    }

    public function getName()
    {
        return 'purchaseItem';
    }
}

The PurchaseType PurchaseType

namespace Aazp\BookingBundle\Form;

use Doctrine\ORM\EntityManager;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;

use Aazp\BookingBundle\Entity\PurchaseItem;

class PurchaseType extends AbstractType
{
    protected $em;

    function __construct(EntityManager $em)
    {
        $this->em = $em;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('purchaseItems', 'collection', array('type' => new PurchaseItemType(), 'allow_add' => true, 'allow_delete' => true, 'by_reference' => false));
        $builder->add('paymentType', 'entity', array('label' => 'Payment Type', 'class' => 'AazpBookingBundle:PaymentType','property' => 'name', 'mapped' => false, 'expanded' => true));
        $builder->add('paymentAmount', 'number', array('precision' => 2, 'data' => 0.0, 'mapped' => false));
        $builder->add('description', 'text', array('mapped' => false, 'required' => false));
        $builder->add('cancel', 'submit', array('attr' => array('formnovalidate' => true, 'data-toggle' => 'modal', 'data-target' => '#cancelWarning', )));
    $builder->add('pay', 'submit');
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array('data_class' => 'Aazp\BookingBundle\Entity\Purchase', ));
    }

    public function getName()
    {
        return 'purchase';
    }
}

The Purchase Entity 购买实体

<?php
namespace Aazp\BookingBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Validator\Constraints as Assert;

use Aazp\MainBundle\Entity\BaseEntity;

/**
 * @ORM\Entity(repositoryClass="Aazp\BookingBundle\Entity\PurchaseRepository")
 * @ORM\Table(name="purchase")
 * @Gedmo\SoftDeleteable(fieldName="deleted")
 */
class Purchase extends BaseEntity
{
    /**
     * Constructor
     */
    public function __construct()
    {
        $this->purchaseItems = new \Doctrine\Common\Collections\ArrayCollection();
        $this->payments = new \Doctrine\Common\Collections\ArrayCollection();
    }

    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\ManyToMany(targetEntity="PurchaseItem", cascade={"all"})
     * @ORM\JoinTable(name="purchase_purchase_items",
     *      joinColumns={@ORM\JoinColumn(name="purchase_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="purchase_item_id", referencedColumnName="id", unique=true)}
     *      )
     **/
    protected $purchaseItems;

    /**
     * @ORM\ManyToMany(targetEntity="Payment", inversedBy="purchases", cascade={"all"})
     * @ORM\JoinTable(name="purchases_payments",
     *      joinColumns={@ORM\JoinColumn(name="purchase_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="payment_id", referencedColumnName="id")}
     *      )
     **/
    protected $payments;

    /**
     * @ORM\OneToOne(targetEntity="Passenger", mappedBy="purchase")
     **/
    protected $passenger;


    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Add purchaseItems
     *
     * @param \Aazp\BookingBundle\Entity\PurchaseItem $purchaseItems
     * @return Purchase
     */
    public function addPurchaseItem(\Aazp\BookingBundle\Entity\PurchaseItem $purchaseItems)
    {
        $this->purchaseItems[] = $purchaseItems;

        return $this;
    }

    /**
     * Remove purchaseItems
     *
     * @param \Aazp\BookingBundle\Entity\PurchaseItem $purchaseItems
     */
    public function removePurchaseItem(\Aazp\BookingBundle\Entity\PurchaseItem $purchaseItems)
    {
        $this->purchaseItems->removeElement($purchaseItems);
    }

    /**
     * Get purchaseItems
     *
     * @return \Doctrine\Common\Collections\Collection 
     */
    public function getPurchaseItems()
    {
        return $this->purchaseItems;
    }

    /**
     * Add payments
     *
     * @param \Aazp\BookingBundle\Entity\Payment $payments
     * @return Purchase
     */
    public function addPayment(\Aazp\BookingBundle\Entity\Payment $payments)
    {
        $this->payments[] = $payments;

        return $this;
    }

    /**
     * Remove payments
     *
     * @param \Aazp\BookingBundle\Entity\Payment $payments
     */
    public function removePayment(\Aazp\BookingBundle\Entity\Payment $payments)
    {
        $this->payments->removeElement($payments);
    }

    /**
     * Get payments
     *
     * @return \Doctrine\Common\Collections\Collection 
     */
    public function getPayments()
    {
        return $this->payments;
    }

    /**
     * Set passenger
     *
     * @param \Aazp\BookingBundle\Entity\Passenger $passenger
     * @return Purchase
     */
    public function setPassenger(\Aazp\BookingBundle\Entity\Passenger $passenger = null)
    {
        $this->passenger = $passenger;

        return $this;
    }

    /**
     * Get passenger
     *
     * @return \Aazp\BookingBundle\Entity\Passenger 
     */
    public function getPassenger()
    {
        return $this->passenger;
    }   
}

This happened because the default data_class option calls that constructor with no arguments. 发生这种情况是因为默认的data_class选项不带参数调用该构造函数。 If your class Aazp\\Booking Bundle\\Entity\\PurchaseItem has parameters in the constructor, you need to use the empty_data option to instantiate: 如果您的类Aazp\\Booking Bundle\\Entity\\PurchaseItem在构造函数中具有参数,则需要使用empty_data选项实例化:

// Aazp\BookingBundle\Form\PurchaseItemType.php

$resolver->setDefaults([
    'empty_data' => function (FormInterface $form) {
        return new PurchaseItem($form->get('product')->getData());
    },
]);

You can lean more about this option here . 您可以在此处更多地了解此选项。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM