Symfony / propel表单保存具有附加属性的对象

时间:2011-08-19 11:27:14

标签: php symfony1 propel symfony-forms

首先,我要说,我发现sfFormPropel表单的接口不一致。 有bind(),它不返回任何内容,但触发验证,save()返回保存的对象,bindAndSave()返回布尔值,实际上是isValid()的返回值。现在,我有一个有效的应用程序,但我觉得代码不对,我对symfony很新,所以也许我错过了什么。

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

现在流程如下:

  • 从请求中获取值并将其绑定到表单
  • 检查表格是否有效
  • 如果它有效,请添加其他值并将它们绑定以形成一次
  • 保存表单并返回对象

显而易见的答案是将特定于应用程序的值添加到从请求中检索的值,但如果表单无效,则绑定特定于应用程序的值没有意义,因为它们可能很昂贵操作,可能会创建数据库记录等。此外,不应该使用post请求传递这些值,它们应该仅来自应用程序。

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

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

第二个赏金开始奖励其他有价值的答案

2 个答案:

答案 0 :(得分:2)

正确的方法是在传递给表单构造函数的对象上设置默认值。例如,如果要在要创建的对象上设置登录用户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():

class UserForm {

  public function processValues($values) {
    $values['hash'] = sha1($values['id'] . $values['username']);
    return parent::processValues($values);
  }

}

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

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

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

答案 1 :(得分:1)

这取决于谁具有关于额外属性的“知识”。如果它们确实是特定于请求,因此需要在控制器中进行处理,我会进行绑定,测试是否有效,然后更新绑定对象。要使用绑定(和验证)字段获取更新的对象,请使用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();
}

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