我有两个设置为相互映射的实体(Plan 和 PricingTier)。PricingTier 设置为 oneToMany,Plan 设置为 manyToOne。映射列在计划实体中;计划数据库表有一个pricing_tier_id 列,将两个表/实体链接在一起。
我有一个创建新计划的表格。表单在 Twig 文件中正确生成,并在发布时 $request->request->getAll(); 返回已发布值的数组。在数组中,我可以看到 priceTierId 已明确设置为我选择的定价层的 id。当我执行以下操作时:
$form->bind($request);
$newPlan = $form->getData();
$em = $this->getDoctrine()->getEntityManager();
$em->perist($newPlan);
$em->flush();
我得到一个抛出的异常,说pricing_tier_id 不能为NULL。我对 $newPlan 变量做了一个 var_dump() ,它看起来返回一个对象,包括映射定价层的对象。
谁能建议我为什么会收到此错误的解决方案?相关代码和错误如下。
计划控制器.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()));
}
}
计划类型.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 命名空间 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);
}
}
}
计划.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
定价层.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());
}
}
定价层.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() 魔术方法生成的表单的一行。
先谢谢了!