即使映射了entity1和entity2,将表单数据提交到entity1和entity2_id列也是null

时间:2013-03-20 21:39:26

标签: symfony symfony-forms

我有两个实体(Plan和PricingTier),它们被设置为相互映射。 PricingTier设置为oneToMany,Plan设置为manyToOne。映射列位于Plan实体中; plans数据库表有一个pricing_tier_id列,它将两个表/实体链接在一起。

我有一个创建新计划的表单。表单在Twig文件中正确生成,并在发布$ request-> request-> getAll();返回已发布值的数组。在数组中,我可以看到pricingTierId已明确设置为我选择的定价层的id。当我执行以下操作时:

$form->bind($request);
$newPlan = $form->getData();
$em = $this->getDoctrine()->getEntityManager();
$em->perist($newPlan);
$em->flush();

我得到一个抛出异常,说pricing_tier_id不能为NULL。我对$ newPlan变量做了一个var_dump(),它看起来返回一个对象,包括映射定价层的对象。

有人可以建议解决我为什么会收到此错误的解决方案吗?相关代码和错误如下。

PlanController.php

namespace etrak\CustomerServiceBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use etrak\OnlineOrderProcessingBundle\Entity\Plan;
use etrak\OnlineOrderProcessingBundle\Entity\PricingTier;
use etrak\CustomerServiceBundle\Form\Type\PlanType;
use Symfony\Component\HttpFoundation\Request;

class PlanController extends Controller
{
    public function indexAction($name)
    {
        return $this->render('etrakCustomerServiceBundle:Default:index.html.twig', array('name' => $name));
    }

    public function addPlanAction(Request $request)
    {
        // Set up a new Plan object
        $plan = new Plan();

        $form = $this->createForm(new PlanType(), $plan);

        // Check to see if the form has been submitted
        if ($request->isMethod('POST')) {
            $form->bind($request);
            var_dump($request->request->all()); die();
            // Validate the form
            if ($form->isValid()) {
                $newPlan = $form->getData();
//var_dump($newPlan->getPricingTierId()); die();
                $em = $this->getDoctrine()->getEntityManager();
                $em->persist($newPlan);
                $em->flush();
            }
        }

        return $this->render('etrakCustomerServiceBundle:Plan:new.html.twig', array("form" => $form->createView()));
    }
}

PlanType.php

namespace etrak\CustomerServiceBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class PlanType extends AbstractType
{
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'etrak\OnlineOrderProcessingBundle\Entity\Plan',
            'cascade_validation' => true,
        ));


    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $termsConditionsArray = array("1 Year Contract" => "1 Year Contract", "2 Year Contract" => "2 Year Contract");
        $billingFrequencyArray = array("1" => "Monthly", "6" => "6 Months", "12" => "Yearly");

        // Create the form
        $builder->add('name', 'text', array('label' => 'Plan Name: ', 'required' => false));
        $builder->add('description', 'text', array('label' => 'Plan Description: '));
        $builder->add('termsConditions', 'choice', array('choices' =>                 $termsConditionsArray, 'label' => 'Terms & Conditions'));
        $builder->add('amount', 'text', array('label' => 'Plan Price: '));
        $builder->add('affinity', 'choice', array('choices' => array('0' => 'Yes', '1' => 'No'), 'label' => 'Affinity? ', 'expanded' => true));
        $builder->add('deactivationFee', 'text', array('label' => "Deactivation Fee: "));
        $builder->add('recurringInMonths', 'choice', array('choices' => $billingFrequencyArray, 'label' => 'Billing Frequency: '));
        $builder->add('pricingTierId', 'entity', array(
        'class' => 'etrakOnlineOrderProcessingBundle:pricingTier',
        'property' => 'name',
        'label' => "Select Pricing Tier: "
    ));
        $builder->add('activeStartDate', 'datetime', array('label' => "Effective Start Date: "));
        $builder->add('activeEndDate', 'datetime', array('label' => "Effective End Date: "));
    }

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

Plan.php     namespace etrak \ OnlineOrderProcessingBundle \ Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Plan
 */
class Plan
{
    /**
     * @var integer
     */
    private $id;

    /**
     * @var string
     */
    private $name;

    /**
     * @var string
     */
    private $description;

    /**
     * @var string
     */
    private $termsConditions;

    /**
     * @var boolean
     */
    private $active;

    /**
     * @var decimal
     */
    private $amount;

    /**
     * @var boolean
     */
    private $affinity;

    /**
     * @var integer
     */
    private $deactivationFee;

    /**
     * @var integer
     */
    private $gracePeriodDays;

    /**
     * @var integer
     */
    private $recurringInMonths;

    /**
     * @var integer
     */
    private $pricingTierId;

    /**
     * @var date
     */
    private $activeStartDate;

    /**
     * @var date
     */
    private $activeEndDate;

    /**
     * @var \etrak\OnlineOrderProcessingBundle\Entity\PricingTier
     */
    private $pricingTier;


    /**
     * Set pricingTier
     *
     * @param \etrak\OnlineOrderProcessingBundle\Entity\PricingTier $pricingTier
     * @return Plan
     */
    public function setPricingTier(\etrak\OnlineOrderProcessingBundle\Entity\PricingTier $pricingTier = null)
    {
        $this->pricingTier = $pricingTier;

        return $this;
    }

    /**
     * Get pricingTier
     *
     * @return \etrak\OnlineOrderProcessingBundle\Entity\PricingTier 
     */
    public function getPricingTier()
    {
        return $this->pricingTier;
    }

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

    /**
     * Set name
     *
     * @param string $name
     * @return Plan
     */
    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 Plan
     */
    public function setDescription($description)
    {
        $this->description = $description;

        return $this;
    }

    /**
     * Get description
     *
     * @return string 
     */
    public function getDescription()
    {
        return $this->description;
    }

    /**
     * Set termsConditions
     *
     * @param string $termsConditions
     * @return Plan
     */
    public function setTermsConditions($termsConditions)
    {
        $this->termsConditions = $termsConditions;

        return $this;
    }

    /**
     * Get termsConditions
     *
     * @return string 
     */
    public function getTermsConditions()
    {
        return $this->termsConditions;
    }

    /**
     * Set active
     *
     * @param boolean $active
     * @return Plan
     */
    public function setActive($active)
    {
        $this->active = $active;

        return $this;
    }

    /**
     * Get active
     *
     * @return boolean 
     */
    public function getActive()
    {
        return $this->active;
    }

    /**
     * Set amount
     *
     * @param decimal $amount
     * @return Plan
     */
    public function setAmount($amount)
    {
        $this->amount = $amount;

        return $this;
    }

    /**
     * Get amount
     *
     * @return decimal 
     */
    public function getAmount()
    {
        return $this->amount;
    }

    /**
     * Set affinity
     *
     * @param boolean $affinity
     * @return Plan
     */
    public function setAffinity($affinity)
    {
        $this->affinity = $affinity;

        return $this;
    }

    /**
     * Get affinity
     *
     * @return boolean 
     */
    public function getAffinity()
    {
        return $this->affinity;
    }

    /**
     * Set deactivationFee
     *
     * @param integer $deactivationFee
     * @return Plan
     */
    public function setDeactivationFee($deactivationFee)
    {
        $this->deactivationFee = $deactivationFee;

        return $this;
    }

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

    /**
     * Set gracePeriodDays
     *
     * @param integer $gracePeriodDays
     * @return Plan
     */
    public function setGracePeriodDays($gracePeriodDays)
    {
        $this->gracePeriodDays = $gracePeriodDays;

        return $this;
    }

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

    /**
     * Set recurringInMonths
     *
     * @param integer $recurringInMonths
     * @return Plan
     */
    public function setRecurringInMonths($recurringInMonths)
    {
        $this->recurringInMonths = $recurringInMonths;

        return $this;
    }

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

    /**
     * Set pricingTierId
     *
     * @param integer $pricingTierId
     * @return Plan
     */
    public function setPricingTierId($pricingTierId)
    {
        $this->pricingTierId = $pricingTierId;

        return $this;
    }

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

    /**
     * Set activeStartDate
     *
     * @param \DateTime $activeStartDate
     * @return Plan
     */
    public function setActiveStartDate($activeStartDate)
    {
        $this->activeStartDate = $activeStartDate;

        return $this;
    }

    /**
     * Get activeStartDate
     *
     * @return \DateTime 
     */
    public function getActiveStartDate()
    {
        return $this->activeStartDate;
    }

    /**
     * Set activeEndDate
     *
     * @param \DateTime $activeEndDate
     * @return Plan
     */
    public function setActiveEndDate($activeEndDate)
    {
        $this->activeEndDate = $activeEndDate;

        return $this;
    }

    /**
     * Get activeEndDate
     *
     * @return \DateTime 
     */
    public function getActiveEndDate()
    {
        return $this->activeEndDate;
    }

    /**
     * 
     */
    public function prePersist()
    {
        if (!isset($this->affinity)) {
            $this->setAffinity(0);
        }

        if (!isset($this->active)) {
            $this->setActive(1);
        }
    }
}

Plan.orm.yml

#etrak/OnlineOrderProcessingBundle/Resources/config/doctrine/Entity/Plan.orm.yml
etrak\OnlineOrderProcessingBundle\Entity\Plan:
  type: entity
  table: plans
  id:
    id:
      type: integer
      generator: { strategy: AUTO }
  fields:
    name:
      type: string
      length: 255
      nullable: true
    description:
      type: text
      nullable: true
    termsConditions:
      column: terms_conditions
      type: text
      nullable: true
    active:
      type: boolean
      nullable: true
    amount:
      type: decimal
      nullable: true
      scale: 2
      precision: 5
    affinity:
      type: boolean
      nullable: true
    deactivationFee:
      column: deactivation_fee
      type: decimal
      scale: 2
      precision: 5
      nullable: true
    gracePeriodDays:
      column: grace_period_days
      type: integer
      nullable: true
    recurringInMonths:
      column: recurring_in_months
      type: integer
      nullable: true
    pricingTierId:
      column: pricing_tier_id
      type: integer
    activeStartDate:
      column: active_start_date
      type: date
    activeEndDate:
      column: active_end_date
      type: date
  lifecycleCallbacks:
    prePersist: [ prePersist ]
  manyToOne:
    pricingTier:
      targetEntity: PricingTier
      inversedBy: plans
      joinColumn:
        name: pricing_tier_id
        referencedColumnName: id

PricingTier.php

namespace etrak\OnlineOrderProcessingBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * PricingTier
 */
class PricingTier
{

    /**
     * @var integer
     */
    private $id;

    /**
     * @var integer
     */
    private $productId;

    /**
     * @var string
     */
    private $name;

    /**
     * @var string
     */
    private $description;

    /**
     * @var integer
     */
    private $minimumDevices;

    /**
     * @var boolean
     */
    private $isAffinity;

    /**
     * @var string
     */
    private $keyname;

    /**
     * @var string
     */
    private $createdBy;

    /**
     * @var datetime
     */
    private $createdOn;

    /**
     * @var datetime
     */
    private $updatedOn;

    /**
     * Set productId
     *
     * @param integer $productId
     * @return PricingTier
     */
    public function setProductId($productId)
    {
        $this->productId = $productId;

        return $this;
    }

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

    /**
     * @var \Doctrine\Common\Collections\Collection
     */
    private $plans;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->plans = new \Doctrine\Common\Collections\ArrayCollection();
    }

    /**
     * Add plans
     *
     * @param \etrak\OnlineOrderProcessingBundle\Entity\Plan $plans
     * @return PricingTier
     */
    public function addPlan(\etrak\OnlineOrderProcessingBundle\Entity\Plan $plans)
    {
        $this->plans[] = $plans;

        return $this;
    }

    /**
     * Remove plans
     *
     * @param \etrak\OnlineOrderProcessingBundle\Entity\Plan $plans
     */
    public function removePlan(\etrak\OnlineOrderProcessingBundle\Entity\Plan $plans)
    {
        $this->plans->removeElement($plans);
    }

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

    /**
     * Set name
     *
     * @param string $name
     * @return PricingTier
     */
    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 PricingTier
     */
    public function setDescription($description)
    {
        $this->description = $description;

        return $this;
    }

    /**
     * Get description
     *
     * @return string 
     */
    public function getDescription()
    {
        return $this->description;
    }

    /**
     * Set minimumDevices
     *
     * @param integer $minimumDevices
     * @return PricingTier
     */
    public function setMinimumDevices($minimumDevices)
    {
        $this->minimumDevices = $minimumDevices;

        return $this;
    }

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

    /**
     * Set isAffinity
     *
     * @param boolean $isAffinity
     * @return PricingTier
     */
    public function setIsAffinity($isAffinity)
    {
        $this->isAffinity = $isAffinity;

        return $this;
    }

    /**
     * Get isAffinity
     *
     * @return boolean 
     */
    public function getIsAffinity()
    {
        return $this->isAffinity;
    }

    /**
     * Set keyname
     *
     * @param string $keyname
     * @return PricingTier
     */
    public function setKeyname($keyname)
    {
        $this->keyname = $keyname;

        return $this;
    }

    /**
     * Get keyname
     *
     * @return string 
     */
    public function getKeyname()
    {
        return $this->keyname;
    }

    /**
     * Set createdBy
     *
     * @param string $createdBy
     * @return PricingTier
     */
    public function setCreatedBy($createdBy)
    {
        $this->createdBy = $createdBy;

        return $this;
    }

    /**
     * Get createdBy
     *
     * @return string 
     */
    public function getCreatedBy()
    {
        return $this->createdBy;
    }

    /**
     * Set createdOn
     *
     * @param \DateTime $createdOn
     * @return PricingTier
     */
    public function setCreatedOn($createdOn)
    {
        $this->createdOn = $createdOn;

        return $this;
    }

    /**
     * Get createdOn
     *
     * @return \DateTime 
     */
    public function getCreatedOn()
    {
        return $this->createdOn;
    }

    /**
     * Set updatedOn
     *
     * @param \DateTime $updatedOn
     * @return PricingTier
     */
    public function setUpdatedOn($updatedOn)
    {
        $this->updatedOn = $updatedOn;

        return $this;
    }

    /**
     * Get updatedOn
     *
     * @return \DateTime 
     */
    public function getUpdatedOn()
    {
        return $this->updatedOn;
    }

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

    /**
     * @ORM\PrePersist
     */
    public function onPrePersist()
    {
        if (!isset($this->isAffinity)) {
            $this->setIsAffinity(0);
        }
        $this->setCreatedOn(new \DateTime());
    }

    /**
     * @ORM\PreUpdate
     */
    public function onPreUpdate()
    {
        $this->setUpdatedOn(new \DateTime());
    }
}

PricingTier.orm.yml

#etrak/OnlineOrderProcessingBundle/Resources/config/doctrine/Entity/PricingTier.orm.yml
etrak\OnlineOrderProcessingBundle\Entity\PricingTier:
  type: entity
  table: pricing_tiers
  id:
    id:
      type: integer
      generator: { strategy: AUTO }
  fields:
    productId:
      column: product_id
      type: integer
    name:
      type: string
      length: 50
    description:
      type: string
      length: 100
      nullable: true
    minimumDevices:
      column: minimum_devices
      type: integer
    isAffinity:
      column: is_affinity
      type: boolean
    keyname:
      type: string
      length: 55
    createdBy:
      column: created_by
      type: string
      length: 20
    createdOn:
      column: created_on
      type: datetime
    updatedOn:
      column: updated_on
      type: datetime
      nullable: true
  lifecycleCallbacks:
    prePersist: [ onPrePersist ]
    preUpdate: [ onPreUpdate ]
  oneToMany:
    plans:
      targetEntity: Plan
      mappedBy: pricingTier

那应该是与此相关的所有文件。我没有包含Twig文件,因为它只是一行呈现由PlanController中的createView()魔术方法生成的表单。

先谢谢!

1 个答案:

答案 0 :(得分:1)

在Plan.orm.yml中:

pricingTierId:
      column: pricing_tier_id
      type: integer

与多对一联接的列名相同。这可能是一种不好的做法。这不是nullable:true,可能是你问题的根源。显然,您不需要此字段。同样在你的表单中,你正在为pricingTierId加载实体类,而priceTierId不是一个实体,我认为symfony对此非常困惑。

    $builder->add('pricingTierId', 'entity', array(             // add pricingTier
    'class' => 'etrakOnlineOrderProcessingBundle:pricingTier',  // not pricingTierId
    'property' => 'name',
    'label' => "Select Pricing Tier: "
    ));

我希望如果您删除有问题的yaml部分并调整表单类型,您的问题就会消失。