Php Symfony/spreep表单保存具有其他属性的对象

Php Symfony/spreep表单保存具有其他属性的对象,php,symfony1,propel,symfony-forms,Php,Symfony1,Propel,Symfony Forms,首先,我要说的是,我发现sfFormPropel表单的接口不一致。 还有bind(),它不返回任何内容,但会触发验证;save()它返回保存的对象;bindAndSave(),它返回布尔值,实际上的返回值是有效的()。现在,我有了一个正常工作的应用程序,但我觉得代码不对,而且我对symfony还很陌生,所以我可能遗漏了一些东西 我需要创建的对象需要一些外部属性,这些属性没有在表单中显示,是模型的外部属性,并且由应用程序处理(例如,创建实体的用户的userId、外部生成的guid等) 目前流程如下

首先,我要说的是,我发现sfFormPropel表单的接口不一致。 还有
bind()
,它不返回任何内容,但会触发验证;
save()
它返回保存的对象;
bindAndSave()
,它返回布尔值,实际上
的返回值是有效的()。现在,我有了一个正常工作的应用程序,但我觉得代码不对,而且我对
symfony
还很陌生,所以我可能遗漏了一些东西

我需要创建的对象需要一些外部属性,这些属性没有在表单中显示,是模型的外部属性,并且由应用程序处理(例如,创建实体的用户的userId、外部生成的guid等)

目前流程如下:

  • 从请求中获取值并将其绑定到表单
  • 检查表格是否有效
  • 如果有效,则添加其他值并再次将它们绑定到表单中
  • 保存表单并返回对象
显而易见的答案是将特定于应用程序的值添加到从请求中检索的值中,但如果表单无效,则绑定特定于应用程序的值是没有意义的,因为它们可能是昂贵的操作,可能会创建数据库记录等。此外,应该不可能通过post请求传递这些值,它们应该只来自应用程序

现在,我认为我必须让模型做这些事情,但是由于数据是模型的外部数据,操作仍然需要将其传递给模型。问题是,如果我在
bind()
之后调用
$form->getObject()
,它仍然有旧数据,而不是提交的数据

实现这种后处理的正确方法是什么


第二个奖励开始奖励另一个有价值的答案,正确的方法是在传递给表单构造函数的对象上设置默认值。例如,如果要在正在创建的对象上设置登录用户id:

$article = new Article();
$article->setUserId($this->getUser()->getId());
$form = new ArticleForm($article);
if ($request->isMethod('post')) {
  $form->bind($request->getParameter('article'));
  if ($form->isValid()) {
    $form->save();
  }
}
同样,对于现有对象,您可以加载记录并在将其传递给表单构造函数之前更改任何属性

编辑:

如果要在验证后修改对象,可以使用$form->updateObject(),就像Grad在其响应中建议的那样。如果生成的值取决于提交的值,则可以重写sfFormObject::processValues():

如果您需要操作中的某些内容,您始终可以将其作为选项传递给表单:

$form = new UserForm($user, array('foo' => $bar));

这样,您就可以在表单代码的任何地方使用$this->getOption('foo'),例如在processValues()中。

这在某种程度上取决于谁对额外属性有“了解”。如果它们确实是特定于请求的,因此需要在控制器中进行处理,我会进行绑定,测试是否有效,然后更新绑定对象。使用
updateObject
函数获取带有绑定(和验证)字段的更新对象

$form->bind(..)
if ($form->isValid()) {

   $obj = $form->updateObject(); // Updates the values of the object with the cleaned up values. (returns object)
   $obj->foo = 'bar';

   $obj->save();
}
但由于这通常也是特定于表单的行为,我通常会覆盖表单类。通过重写
doUpdateValues()
函数,您可以轻松访问提交的数据,并附加您自己的数据。当然,您也可以在链中走得更高,覆盖
save()
函数。
要设置此表单的自定义数据,您还可以“发布”公共方法,然后控制器可以使用这些方法。

感谢您加入讨论。这仍然需要在保存对象之前生成GUID,并且该对象可能永远不会保存。如果值取决于表单中提交的数据,例如输入标记,并根据所有输入的单词生成哈希(仅示例),该怎么办。也许在某种程度上,模型必须被修改以允许这种情况发生。ubdateObject()在PropertyForm中的作用是什么?也许表单的doSave()必须被覆盖?控制器知道-其中一个值是当前用户id(可以轻松设置为表单),另一个是通过调用另一个模型生成和检索的id(我不想执行该调用,因为提交的表单无效),并且其他值也是可能的,由将来添加的其他模型检索。问题实际上是如何在不触发已处理字段的验证的情况下更新绑定对象?您是否尝试调用
doUpdateObject()
来获取“绑定”对象?(见我更新的答案)它工作了,代码现在更干净了。非常感谢。processValues()在其他情况下对我很有用。我将把问题和悬赏留到星期五,欢迎提出其他建议。
$form->bind(..)
if ($form->isValid()) {

   $obj = $form->updateObject(); // Updates the values of the object with the cleaned up values. (returns object)
   $obj->foo = 'bar';

   $obj->save();
}