Symfony2自定义字段类型来自Populate的值

时间:2014-06-06 14:30:46

标签: php forms symfony

这是早期问题Symfony2 Custom Form Type or Extension

的后续内容

我正在尝试为订单附加Product的自定义字段类型。 name字段将包含产品名称,id字段包含产品ID。

我正在使用FormEvents :: PRE_SET_DATA来尝试填充数据,但是它会抛出错误,getData()返回Form \ Type \ ProductAutoCompleteType。

如何更正代码?

OrderType具有以下内容:

    $builder->add('product', new Type\ProductAutoCompleteType(), array(
        'data_class' => 'Acme\TestBundle\Entity\Product'
    ));        

ProductAutoCompleteType:

class ProductAutoCompleteType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder
            ->add('name');
        $builder
            ->add('id');

    /* Turns out this is not needed any more
    $builder->addEventListener(
        FormEvents::PRE_SET_DATA, function (FormEvent $event) {
        $form = $event->getForm();
        $product = $form->getData();
        $form
            ->add('name', 'text', array('mapped' => false, 'data' => $product->getName()));
    }
    );  
    *//

    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
    }

    public function getParent()
    {
        return 'form';
    }

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

更新

错误:FatalErrorException:错误:在/var/www/symblog/src/Acme/TestBundle/Form/Type/ProductAutoCompleteType.php第26行中的非对象上调用成员函数getProduct()

控制器

    $em = $this->getDoctrine()->getManager();
    $order = $em->getRepository('AcmeTestBundle:Order')->find(6);

    $form = $this->createForm(new OrderType(), $order);

更新2

更改字段[product] [id]并提交表单后,我现在收到以下错误,我认为这是因为字段名称是[product] [id]而不是[product]?

属性“id”和方法“setId()”,“ set()”或“__call()”之一都不存在,并且在“Proxies__CG \ Acme \”类中具有公共访问权限TestBundle \实体\产品”。

更新3

我现在已经将数据提交给控制器,在我的控制器上提交我不得不添加以下内容,看起来很麻烦做验证并以这种方式附加产品,这是正确的方法吗?

        $data = $request->request->get($form->getName());
        if ($data['product']['id']) {
            $product = $em->getRepository('AcmeTestBundle:Product')->find($data['product']['id']);
            if ($product) {
                if ($product->getShop()->getId() != $order->getShop()->getId()) {
                    $form->get('product')->get('name')->addError(new FormError('Invalid shop product'));
                }
                $form->getData()->setProduct($product);
            } else {
                $form->get('product')->get('name')->addError(new FormError('A product must be selected'));
            }
        }

1 个答案:

答案 0 :(得分:0)

将所有逻辑放入控制器并不是一个好习惯。您的表单应尽可能多地处理这些表单以确保这些表单的可重用性。

如果您查询的订单中没有相关产品,那么$form->getData()返回null是正常的。

调试提示:

输出$form->getData()的值以检查Product对象。 输出$form->getParent()->getData()的值以从父表单检查Order对象。

验证提示:

如果此表单中的产品可以为null,请确保仅在产品不为空时才设置名称字段的数据。

查询提示:

由于存储库上的findBy方法不会自动包含相关的product,因此我建议使用QueryBuilder并进行连接。控制器中的示例:

$order = $em->getRepository('AcmeTestBundle:Order')
  ->createQueryBuilder('order')
  ->select('order, product')
  ->innerJoin('order.product', 'product')
  ->where('order.id = :order_id')
  ->setParameter('order_id', $order_id)
  ->getQuery()
  ->getOneOrNullResult();

当然,在你的控制器中拥有如此多的代码也不是很好,所以一旦你的东西工作,用自定义方法创建一个自定义存储库并将代码移到那里。

在您的实体中:

/**
 * @Entity(repositoryClass="Acme\TestBundle\Repository\OrderRepository")
 */
class Order {

在您的资料库中

class OrderRepository {
  public function findByIdWithProduct() {
    // $order = $this->createQueryBuilder...
    return $order;
  }
}