【问题标题】:Symfony/propel form saving an object with additional propertiesSymfony/propel 形式保存具有附加属性的对象
【发布时间】:2011-10-30 13:21:00
【问题描述】:

首先,让我说,我发现 sfFormPropel 表单的界面不一致。 有bind(),不返回任何内容,但触发验证,save(),返回保存的对象,bindAndSave(),返回布尔值,实际上是isValid()的返回值。现在,我有一个工作应用程序,但我觉得代码不正确,而且我对symfony 很陌生,所以也许我遗漏了一些东西。

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

目前流程如下:

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

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

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

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

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

【问题讨论】:

    标签: php symfony1 propel symfony-forms


    【解决方案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() 函数。 要为此表单设置自定义数据,您还可以“发布”公共方法,然后控制器可以使用这些方法。

    【讨论】:

    • 控制器知道 - 其中一个值是当前用户 ID(可以轻松设置为表单),另一个是通过调用另一个模型生成和检索的 ID(我不想执行该调用是提交的表单无效),并且将来可能添加其他模型检索到的其他值。问题实际上是如何更新绑定对象而不触发对已处理字段的验证?
    • 您是否尝试过调用doUpdateObject() 来获取“绑定”对象? (见我更新的答案)
    • 它工作了,代码现在更干净了。谢谢你。 processValues() 在其他情况下对我有用。我将把问题和赏金留到星期五,欢迎提出其他建议。
    【解决方案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();
      }
    }
    

    同样对于现有对象,您可以在将记录传递给表单构造函数之前加载记录并更改任何属性。

    编辑:

    如果你想在验证后修改对象,你可以像 Grad 在他的回复中建议的那样使用 $form->updateObject() 。如果生成的值依赖于提交的值,可以覆盖 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'),例如。在 processValues() 中。

    【讨论】:

    • 感谢您加入讨论。这仍然需要在保存对象之前生成 GUID,并且该对象可能永远不会保存。如果值取决于表单中提交的数据,例如您输入标签,并且根据所有输入的单词生成哈希(仅示例),该怎么办。也许必须以某种方式改变模型以允许这种情况发生。 ubdateObject() 在 PropelForm 中的作用是什么?也许表单的 doSave() 必须被覆盖?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-03
    • 2012-01-14
    • 1970-01-01
    相关资源
    最近更新 更多