Symfony2-如何在EventListeners中使用数据转换器


Symfony2 - How to use a Data Transformer inside EventListeners

  • 我需要使用事件侦听器,因为我需要在表单中显示不同的内容,无论它是新的还是已经存在的实体。我可以应付。

  • 我需要一个数据转换器,将实体显示为文本,这也是我可以做的

=>但是,我无法同时执行2(数据转换器+事件侦听器)。我得到错误:"错误:在非对象上调用成员函数add()"。如果我替换$builder-par$form,我会得到以下错误:试图调用类"Symfony''Component''form''form"的名为"create"的未定义方法。

有效:

 $builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event){
        $element = $event->getData();
        $form = $event->getForm();
        if (!$element || null === $element->getId()) { //new entity
            $form->add(...);
        } else { //exist already
            //...
        }

同样有效:

$builder->add( $builder->create('element', 'text')->addModelTransformer($transformer));

但我不能让这两个同时工作。

    $transformer = new ElementObjToStringTransformer($this->em);
    $builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event){
        $element = $event->getData();
        $form = $event->getForm();
        if (!$element || null === $element->getId()) { //new entity
            $builder->add( $builder->create('element', 'text')->addModelTransformer($transformer));
        } else { //exist already
            //...
        }
    });

简短回答:由于表单已锁定,因此无法在侦听器中添加转换器。

长话短说:有一些解决方案。至少对我来说,最常见的是创建一个自定义表单类型,在其中添加转换器。然后你添加你的自定义表单,你通常会在事件监听器中这样做:

class ElementCustomType extends AbstractType {
    private $em;
    public function __construct(EntityManager $entityManager)
    {
        $this->em = $entityManager;
    }
    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder
            ->addModelTransformer(new ElementObjToStringTransformer($this->em))
        ;
    }
    public function getParent() {
        return 'text';
    }
    public function getName() {
        return 'elementCustom';
    }
}

将表单定义为服务:

 app.form.type.custom_element:
    class: AppBundle'Form'Type'ElementCustomType
    arguments: [@doctrine.orm.entity_manager]
    tags:
        - { name: form.type, alias: elementCustom }

在监听器中使用你通常会做的形式:

$builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event){
        $element = $event->getData();
        $form = $event->getForm();
        $form->add('element', 'elementCustom')
    });

我编写了一个表单扩展来支持这个用例,而不更改字段类型。

1)创建扩展类

namespace AppBundle'Form'Extension'ModelTransformerExtension
use Symfony'Component'Form'AbstractTypeExtension;
use Symfony'Component'Form'Extension'Core'Type'FormType;
use Symfony'Component'Form'FormBuilderInterface;
use Symfony'Component'OptionsResolver'OptionsResolver;
class ModelTransformerExtension extends AbstractTypeExtension {
    public function getExtendedType() {
        return FormType::class;
    }
    public function buildForm(FormBuilderInterface $builder, array $options) {
        parent::buildForm($builder, $options);
        if (isset($options['model_transformer'])) {
            $builder->addModelTransformer($options['model_transformer']);
        }
    }
    public function configureOptions(OptionsResolver $resolver) {
        parent::configureOptions($resolver);
        $resolver->setDefaults(array('model_transformer' => null));
    }
}

2)将此扩展注册为应用程序服务

services:
    app.form.extension.model_transformer:
        class: AppBundle'Form'Extension'ModelTransformerExtension
        tags:
            - { name: form.type_extension, extended_type: Symfony'Component'Form'Extension'Core'Type'FormType }

3)在构建表单时,为任何DataTransformer实现定义model_transformer选项。

public function buildForm(FormBuilderInterface $builder, array $options) {
    $builder->addEventListener(FormEvents::PRE_SET_DATA, function ($event) {
        $builder = $event->getForm();
        $builder->add('myField', TextType::class, array(
            'model_transformer' => new MyModelTransformer()
        ));
    });
}

这个思想也可以扩展到支持CCD_ 2方法。