【问题标题】:Symfony2 - How to use a Data Transformer inside EventListenersSymfony2 - 如何在 EventListeners 中使用数据转换器
【发布时间】:2015-11-18 20:36:56
【问题描述】:
  • 我需要使用事件侦听器,因为我需要在表单中显示不同的内容,无论它是新实体还是现有实体。我可以做到。

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

=> 但是,我无法同时执行 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
            //...
        }
    });

【问题讨论】:

  • 你可以将数据转换器定义为服务并注入到Listener中,但是这样使用它看起来很奇怪。我认为,这是个坏主意。

标签: php symfony


【解决方案1】:

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

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()
        ));
    });
}

这个想法可以扩展到支持addViewTransformer方法。

【讨论】:

  • 为我工作。谢谢!
  • 这很棒。谢谢
【解决方案2】:

简短回答:您不能在侦听器中添加转换器,因为表单已被锁定。

长答案:有一些解决方案。至少对我来说,最常见的是创建一个自定义表单类型,您可以在其中添加您的转换器。 然后,您可以按照通常在事件侦听器中的操作方式添加自定义表单:

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')
    });

【讨论】:

  • 效果很好。非常感谢。快速且切中要害。
  • 感谢您的回答,它拯救了我的一天。这种方法也适用于 Symfony5.2。我需要为filed_1 应用变压器,前提是用户在field_2 中设置了值。所以,我创建了 2 个自定义字段 - 有和没有转换器。由于我没有成功地在订阅者中有条件地为field_1 应用转换器,因此我只是根据field_2 中的值添加一个或另一个自定义字段。它似乎有效!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-03
  • 1970-01-01
  • 1970-01-01
  • 2014-08-20
  • 1970-01-01
相关资源
最近更新 更多