Symfony表单EntityType :: class-如何使用它以形式编辑数据(3.2.13)



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

编辑数据时,如何使用相同的FormType类?(例如,在控制器中的编辑)如何将请求$request数据传递给FormType字段作为"默认值或选择" element EntityType ::类中的formBuilder中的"默认"字段?$ builder-> add()方法中是否可以使用if(['choice_value'] !=== null ) xx : yy

如何从请求对象中选择html 之类的东西,然后将其传递到xxxxformType类并绑定到右EntityType :: class element :: class element。

<select>
  <option value="volvo">Volvo</option>
  <option value="vw">VW</option>
  <option value="audi" selected>Audi</option>
</select> 

我看过EntityType字段,如何使用表单事件和许多stackoverflow帖子动态修改表单,但找不到适当的解决方案。

控制器:

public function editProdPackageAction(Request $request, ProdPackage $prodPackage)
{
    $form = $this->createForm(ProdPackageFormType::class, $prodPackage);
    $form->handleRequest($request);
    if ($form->isSubmitted() && $form->isValid()) {
        $prodPackage = $form->getData();
        $em = $this->getDoctrine()->getManager();
        $em->persist($prodPackage);
        $em->flush();
        $this->addFlash('success', 'MSG#011E');
        return $this->redirectToRoute('admin_package_list');
    }

    return $this->render(':admin/forms/ProdPackage:edit.html.twig',
        [
            'ppg' => $form->createView(),
        ]
    );
}

formType:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add(
            'idCatBig',
            EntityType::class,
            [
                'label'         => '* category',
                'class'         => 'AppBundleEntityProdCategoryBig',
                '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',
            ]
        )

这是我以我的形式所做的,我设置了一个"预集数据侦听器",以检查这是编辑还是创建

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所建议

问题

您使用data选项覆盖对象。

https://symfony.com/doc/3.2/reference/forms/types/entity.html#data:

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

解决方案1:使用控制器

因此,解决方案非常简单:不要使用data。相反,在您的addProdPackageAction操作中设置默认值(或称为任何称为):

public function editProdPackageAction(Request $request)
{
    $prodPackage = new ProdPackage();
    $prodPackage->setDateEnd(new Datetime('now'));
    //example: use Request or other controller methods to modify your entity
    if ($this->getUser()->hasRole('ROLE_ADMIN')) {
        $prodPackage->setCreatedByAdmin(true);
    }
    //your form
}

解决方案2:使用您的实体构造函数

另外,您可以使用实体构造方法:

class ProdPackage
{
    //your attributes
    private $dateEnd;
    public function __construct()
    {
        $this->dateEnd = new Datetime('now');
    }
}

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

在$ builder in 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对象也非常有用,您可以在其中以表单的形式传递字段的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();
            }
        ));

最新更新