我正在处理一个表单,该表单处理带有额外参数(额外字段/列)的N:m关系。这就是我迄今为止所做的:
以OrdersType.php
形式:
class OrdersType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options)
{
// $builder fields
// $builder fields only need on edit form not in create
if ($options['curr_action'] !== NULL)
{
$builder
// other $builder fields
->add("orderProducts", "collection", array(
'type' => new OrdersHasProductType(),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false
));
}
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'TananeFrontendBundleEntityOrders',
'render_fieldset' => FALSE,
'show_legend' => FALSE,
'intention' => 'orders_form',
'curr_action' => NULL
));
}
public function getName()
{
return 'orders';
}
}
在OrderHasProductType.php
:中
class OrdersHasProductType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('product', 'text', array(
'required' => FALSE,
'label' => FALSE
))
->add('amount', 'text', array(
'required' => TRUE,
'label' => FALSE
));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'TananeFrontendBundleEntityOrderHasProduct',
'intention' => 'order_has_product'
));
}
public function getName()
{
return 'order_has_product';
}
}
最后是Orders.php
和OrdersHasProduct.php
实体:
class Orders {
use IdentifiedAutogeneratedEntityTrait;
// rest of fields for the entity
/**
* @ORMOneToMany(targetEntity="OrderHasProduct", mappedBy="order", cascade={"all"})
*/
protected $orderProducts;
protected $products;
/**
* @ORMColumn(name="deletedAt", type="datetime", nullable=true)
*/
protected $deletedAt;
public function __construct()
{
$this->orderProducts = new ArrayCollection();
$this->products = new ArrayCollection();
}
public function getOrderProducts()
{
return $this->orderProducts;
}
public function getDeletedAt()
{
return $this->deletedAt;
}
public function setDeletedAt($deletedAt)
{
$this->deletedAt = $deletedAt;
}
public function getProduct()
{
$products = new ArrayCollection();
foreach ($this->orderProducts as $op)
{
$products[] = $op->getProduct();
}
return $products;
}
public function setProduct($products)
{
foreach ($products as $p)
{
$ohp = new OrderHasProduct();
$ohp->setOrder($this);
$ohp->setProduct($p);
$this->addPo($ohp);
}
}
public function getOrder()
{
return $this;
}
public function addPo($ProductOrder)
{
$this->orderProducts[] = $ProductOrder;
}
public function removePo($ProductOrder)
{
return $this->orderProducts->removeElement($ProductOrder);
}
}
/**
* @ORMEntity
* @ORMTable(name="order_has_product")
* @GedmoSoftDeleteable(fieldName="deletedAt")
* @UniqueEntity(fields={"order", "product"})
*/
class OrderHasProduct {
use IdentifiedAutogeneratedEntityTrait;
/**
* Hook timestampable behavior
* updates createdAt, updatedAt fields
*/
use TimestampableEntity;
/**
* @ORMManyToOne(targetEntity="TananeFrontendBundleEntityOrders", inversedBy="orderProducts")
* @ORMJoinColumn(name="general_orders_id", referencedColumnName="id")
*/
protected $order;
/**
* @ORMManyToOne(targetEntity="TananeProductBundleEntityProduct", inversedBy="orderProducts")
* @ORMJoinColumn(name="product_id", referencedColumnName="id")
*/
protected $product;
/**
* @ORMColumn(type="integer", nullable=false)
*/
protected $amount;
/**
* @ORMColumn(name="deletedAt", type="datetime", nullable=true)
*/
protected $deletedAt;
public function setOrder(TananeFrontendBundleEntityOrders $order)
{
$this->order = $order;
}
public function getOrder()
{
return $this->order;
}
public function setProduct(TananeProductBundleEntityProduct $product)
{
$this->product = $product;
}
public function getProduct()
{
return $this->product;
}
public function setAmount($amount)
{
$this->amount = $amount;
}
public function getAmount()
{
return $this->amount;
}
public function getDeletedAt()
{
return $this->deletedAt;
}
public function setDeletedAt($deletedAt)
{
$this->deletedAt = $deletedAt;
}
}
但当我试图在控制器中使用以下代码编辑订单时:
public function editAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$order = $em->getRepository('FrontendBundle:Orders')->find($id);
$type = $order->getPerson()->getPersonType() === 1 ? "natural" : "legal";
$params = explode('::', $request->attributes->get('_controller'));
$actionName = substr($params[1], 0, -6);
$orderForm = $this->createForm(new OrdersType(), $order, array('action' => '#', 'method' => 'POST', 'register_type' => $type, 'curr_action' => $actionName));
return array(
"form" => $orderForm->createView(),
'id' => $id,
'entity' => $order
);
}
我得到这个错误:
表单的视图数据应为标量、数组或\ArrayAccess的实例,但它是类的实例代理__CG__\Tanane\ProductBundle\Entity\Product。你可以避免这种情况将"data_class"选项设置为"Proxies__CG__\Tanane\ProductBundle\Entity\Product"或通过添加转换类实例的视图转换器代理__CG__\Tanane\ProductBundle\Entity\Product到标量、数组或\ArrayAccess的实例。
我找不到也不知道如何修复它,有人能帮我吗?
我认为这是因为这个代码
class OrdersHasProductType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('product', 'text', array(
'required' => FALSE,
'label' => FALSE
))
));
}
//...
}
意味着Symfony期望"product"是一个类型为"text"的字段,但当它在OrderHasProduct上调用getProduct()
时,它会得到一个product对象(或一个Doctrine Proxy到一个product,因为当时还没有加载它)。Symfony字段继承自Form/AbstractType,因此它们本质上是表单,只有一个字段,因此会出现错误消息。
解决方案是使该字段的类型为"entity",或者创建一个只提供产品名称的不同方法,例如OrderHasProduct上的getProductName()
,然后将其用作字段后面的数据。