Symfony2 - 如何阻止 Form->handleRequest 清空帖子数据中不存在的字段
Posted
技术标签:
【中文标题】Symfony2 - 如何阻止 Form->handleRequest 清空帖子数据中不存在的字段【英文标题】:Symfony2 - How to stop Form->handleRequest from nulling fields that don't exist in post data 【发布时间】:2014-10-07 03:13:24 【问题描述】:我有一个在 Symfony 中构建的表单,当在视图中呈现时,html 表单可能包含也可能不包含表单对象中的所有字段(实体类型有几个不同的状态,而不是所有字段在视图中呈现)。
问题在于,当在提交处理程序中处理表单时,通过表单对象的 handleRequest() 方法,它将实体中的任何属性重置为空,而这些属性在发布数据中不存在,从而消除了任何现有值.
有什么方法可以告诉 Symfony 不要那么愚蠢,只处理 POST 数据中存在的字段?
或者我是否必须在 handleRequest 调用之前克隆实体,然后遍历 POST 值并将相关值从 post-handleRequest 实体复制到实体的 pre-handleRequest 克隆中,所以我保留了以下字段不在 POST 数据中。
呸!正如你所看到的,它有点愚蠢的解决方案,有点愚蠢的问题,tbh。
如果实体实际上是一个新创建的对象,我可以理解 symfony 这样做,但是它是从数据库加载的,然后调用了 handleRequest - 它应该足够明智地知道对象已经被初始化并且只设置字段传入 POST 数据。
感谢您的帮助。
问候
史蒂夫。
【问题讨论】:
【参考方案1】:简而言之,不要使用handleRequest
。
您应该直接使用submit
,并将clearMissing
参数设置为false。
Symfony/Component/Form/FormInterface
/**
* Submits data to the form, transforms and validates it.
*
* @param null|string|array $submittedData The submitted data.
* @param bool $clearMissing Whether to set fields to NULL
* when they are missing in the
* submitted data.
*
* @return FormInterface The form instance
*
* @throws Exception\AlreadySubmittedException If the form has already been submitted.
*/
public function submit($submittedData, $clearMissing = true);
当您使用handleRequest
时,它会计算出您想要提交的数据,然后使用$form->submit($data, 'PATCH' !== $method);
提交,这意味着除非您使用PATCH
方法提交表单,否则它将清除字段。
要自己提交表单而不清除您可以使用...
$form->submit($request->get($form->getName()), false);
..从请求中获取表单数据数组并直接提交,但将clear missing fields参数设置为false。
【讨论】:
但是如果表单有文件呢?如果您使用 $request->get($form->getName()) 方法获取所有数据,它们会不会丢失?似乎有必要重现 handleRequest 所做的所有事情,但使用不同的 $clearMissing 参数值调用提交方法。也许重写方法类型会更好?例如使用 POST 代替 GET 并将方法类型设置为 PATCH。 我一直使用$request->files->get($form->getName())
,但可能有更好的方法。理想情况下,您可以将$clearMissing
传递给请求处理程序...或者您可以使用PATCH
方法发送您的表单并使用handleRequest()
。或者,您也可以自己动手做一些工作,从github.com/symfony/symfony/blob/master/src/Symfony/Component/… 中汲取灵感
谢谢@Qoop,使用PATCH
对我来说绝对是更好的解决方案。
Form 的提交函数接受以下类型:null 或字符串或数组。所以将发送的是: $form->submit($request->request->get($form->getName()), false);
这是什么意思?【参考方案2】:
如果您的实体有不同的状态,您可以在表单类型中反映这一点。
要么创建多个包含不同字段设置的表单类型(可能使用继承),然后在控制器中实例化所需的表单类型。
类似这样的:
class YourState1FormType extends AbstractType
public function buildForm(FormBuilderInterface $builder, array $options)
$builder
->add('someField')
;
class YourState2FormType extends AbstractType
public function buildForm(FormBuilderInterface $builder, array $options)
$builder
->add('someOtherField')
;
或者在控制器中创建时将参数传递给单个表单类型,并根据状态调整字段设置。如果您不添加不存在的字段,则不会对其进行处理。
类似这样的:
class YourFormType extends AbstractType
public function buildForm(FormBuilderInterface $builder, array $options)
if($options['state'] == 'state1')
$builder
->add('someField')
;
else if($options['state'] == 'state2')
$builder
->add('someOtherField')
;
public function setDefaultOptions(OptionsResolverInterface $resolver)
$resolver->setDefaults(array(
'state' => 'state1'
));
更新
根据提交的数据修改表单的另一种方法是将事件侦听器注册到表单的 PRE_SET_DATA 和 POST_SUBMIT 事件。这些监听器在表单提交过程中的不同时刻被调用,并允许您根据创建表单时传递给表单类型的数据对象 (PRE_SET_DATA) 或用户提交的表单数据 (POST_SUBMIT) 修改表单。
你可以找到解释和例子in the docs。
【讨论】:
我相信你可以做到所有这些,但 Qoop 的答案是 1 行修复 :)以上是关于Symfony2 - 如何阻止 Form->handleRequest 清空帖子数据中不存在的字段的主要内容,如果未能解决你的问题,请参考以下文章
使用 symfony2 从 post Multipart (Content-Disposition: form-data) 获取数据