Forms Symfony表单EntityType::class-如何使用它编辑表单中的数据(3.2.13)

Forms Symfony表单EntityType::class-如何使用它编辑表单中的数据(3.2.13),forms,symfony,types,request,default,Forms,Symfony,Types,Request,Default,通过使用EntityType表单类型,可以使用表单中的下拉选择菜单。如果您添加数据,它是有用的。但是,当您尝试使用相同的FormType类编辑数据时,EntityType会覆盖您的$request数据 编辑数据时如何使用相同的FormType类?(例如控制器中的editAction)如何将请求$Request数据作为FormBuilder中元素EntityType::class的“默认值或选定值”传递给FormType字段?$builder->add()方法中是否有我可以使用的东西,比如if([

通过使用
EntityType
表单类型,可以使用表单中的下拉选择菜单。如果您添加数据,它是有用的。但是,当您尝试使用相同的FormType类编辑数据时,EntityType会覆盖您的
$request
数据

编辑数据时如何使用相同的FormType类?(例如控制器中的editAction)如何将请求
$Request
数据作为FormBuilder中元素EntityType::class的“默认值或选定值”传递给FormType字段?$builder->add()方法中是否有我可以使用的东西,比如
if(['choice_value']!==null)xx:yy

如何从请求对象中获取类似html的内容,选择selected,并将其传递给xxxFormType类,然后绑定到该类中的正确EntityType::class元素

<select>
  <option value="volvo">Volvo</option>
  <option value="vw">VW</option>
  <option value="audi" selected>Audi</option>
</select> 
表单类型:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add(
            'idCatBig',
            EntityType::class,
            [
                'label'         => '* category',
                'class'         => 'AppBundle\Entity\ProdCategoryBig',
                'choice_value'  => 'id',
                'choice_label'  => 'shortName',

                'multiple'      => false,
                'expanded'      => false,
            ]
        )
        ->add(
            'dateStart',
            DateType::class,
            [
                'label'                     => '* some date',
                'data'  => new \DateTime('now'),
                'choice_translation_domain' => true,
            ]
        )
        ->add(
            'dateEnd',
            DateType::class,
            [
                'label' => '* till',
                    'data'  => new \DateTime('now'),
            ]
        )
        ->add(
            'packageName',
            TextType::class,
            [
                'label' => '* package',
                'attr'  => ['placeholder' => 'default Name'],
                'data'  => 'your default value',
            ]
        )
问题 您正在使用
数据
选项覆盖对象

:

(!)渲染时,
数据
选项始终覆盖从域数据(对象)获取的值。这意味着当表单编辑已持久化的对象时,对象值也会被覆盖,从而在提交表单时丢失其持久化值

解决方案1:使用控制器 因此,解决方案非常简单:不要使用
数据
。相反,请在
addProdPackageAction
操作中设置默认值(或其名称):

解决方案2:使用实体构造函数 或者,您可以使用实体构造函数方法:

class ProdPackage
{
    //your attributes
    $private $dateEnd;

    public function __construct()
    {
        $this->dateEnd = new Datetime('now');
    }
}

这就是我在表单中所做的,我设置了一个“预设数据侦听器”来检查这是编辑还是创建

function buildForm(FormBuilderInterface $builder, array $options) {
    $builder->add(
    'dateStart',
    DateType::class,
    [
    'label' => '* some date'
    //I don't set a data field here because it is an edit
    'choice_translation_domain' => true,
    ]
    )

    $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
        $data = $event->getData();
        $form = $event->getForm();
        if (!$data || null === $data->getId()) {
            //if the entity does not have an ID it means that this is a new entity not an edit. because all edits have been in the database and have an id
            $builder->add(
            'dateStart',
            DateType::class,
            ['label' => '* some date',
            'data' => new \DateTime('now'), //this is a create so I override my previous setting and set a default data
            'choice_translation_domain' => true,]
            )
        }
    });
}

我主要使用这个技巧在编辑和创建密码字段之间将表单字段从必填字段更改为非必填字段,例如,有时如果有非常复杂的内容。老实说,要更改数据,在构造函数中设置默认数据更为简洁,正如Stephan所建议的那样

找到了另一个有趣的解决方案

在$builder的formTypeclass中

->add(
                    'trBegin',
                    DateTimeType::class,
                    [
                        'label'       => 'Tourney Begins',
                        'required'    => true,
                        'date_widget' => 'single_text',
                        'time_widget' => 'single_text',
                        'date_format' => 'dd.MM.yyyy',
                    ]
                )
及续建表格增补:

        $builder->get('trBegin')->addModelTransformer(
            new CallbackTransformer(
                function ($value) {
                        if (!$value) {
                                return new \DateTime('now + 60 minutes');
                        }

                        return $value;
                },
                function ($value) {
                        return $value;
                }
            )
        );
它在创建表单时设置默认日期。这种方法对于EntityType对象也是非常有用的,在EntityType对象中,您可以在表单中传递字段的id,并从数据库中选择您当前的实际选择(不是从一开始的所有列表),在使用EntityField编辑表单时也是非常有用的

 $builder->get('productCategory')
        ->addModelTransformer(new CallbackTransformer(
            function ($id) {
                if (!$id) {
                    return;
                }

                return $this->em->getRepository('AppBundle:ProductCategory')->find($id);
            },
            function($category) {
                return $category->getId();
            }
        ));

你的问题很难理解。删除意见,明确说明您的目标和您尝试过的内容。不,不清楚。我认为很清楚,他希望在编辑时显示现有数据,而不是让其被为创建目的而设置的默认数据覆盖。我个人使用监听器,我怀疑有什么办法可以解决这个问题,但如果有人有更干净的解决方案(也可以避免向控制器添加代码,因为我喜欢我所有的编辑功能都很相似),我会很感兴趣。你的问题很难理解,因为你的观点(“添加数据很棒”,“编辑数据很糟糕”,“大量代码”,“对抗歌利亚vs大卫…”和caps(表单实体类型)。你有一个有趣的问题,但你搞砸了。当(至少)两个人认为你的问题很难理解时,试着问你如何改进它。只是否认它(“这里一切都清楚”)或大声叫别人(“什么不清楚!”)不会对你有帮助。谢谢你更新你的问题。我已经投了赞成票。嗨,我将尝试重写这个问题并记录你的观察结果。比如@Joe Yahchouchi说:“我想很清楚,他想在编辑时显示现有数据,而不是让它被他为创建目的设置的默认数据覆盖。“我想实现的是,如果Request$Request对象(例如调用方法edit)中的'data'字段不为空,则重写EntityType::class(以及任何其他)中的'data'字段添加
$prodPackage->setDateEnd(new Datetime('now'))
到您的
editProdPackageAction
(并从表单类型中删除
数据
),然后查看发生了什么:将填写结束日期。或者像你的另一个例子:
$car=newcar()$汽车->setBrand(“沃尔沃”)
将在表单中返回
Volvo
。是否可以在表单类型中使用实体类中声明的方法?可以,但我认为不应该。我想你是想找个解决办法。请解释为什么我的答案不是您想要的答案,以便我可以更新我的答案。它适用于DataType::class,但仍然无法解析EntityType::class((->add)('idCatBig',EntityType::class,['label'=>'*category','class'=>'AppBundle\Entity\ProdCategoryBig','choice\u value'=>'id','choice\u label'=>'shortName','multiple'=>false','expanded'=>false,]))
        $builder->get('trBegin')->addModelTransformer(
            new CallbackTransformer(
                function ($value) {
                        if (!$value) {
                                return new \DateTime('now + 60 minutes');
                        }

                        return $value;
                },
                function ($value) {
                        return $value;
                }
            )
        );
 $builder->get('productCategory')
        ->addModelTransformer(new CallbackTransformer(
            function ($id) {
                if (!$id) {
                    return;
                }

                return $this->em->getRepository('AppBundle:ProductCategory')->find($id);
            },
            function($category) {
                return $category->getId();
            }
        ));