Symfony:添加记录后更改响应


Symfony: change response after adding record

我通过ajax(使用jquery)打开一个表单,我想在不重新加载整个页面的情况下保存它。在哪里我必须更改代码,以获得文本响应(例如"好!"),而不是重定向到编辑页面?

这是我的js:

$("#newcatlink").click(function() {
    $.ajax({
    'url': "category/new",
    'success': function(data, textStatus, jqXHR) {
            $("#mdialog").html(data);
            $("#_form_jqhide").hide();
            $("#mdialog").dialog({
                modal: true,
                width: 500,
                resizable: false,
                buttons: {
                    Save: function() {
                        $.ajax({
                            'type': 'POST', 
                            'url': 'category/create', 
                            'data': $("#categoryform").serialize(),
                            'success': function(data, textStatus, jqXHR) {
                                alert(data);
                            }
                        });
                    },
                    Cancel: function() {
                        $(this).dialog("close");
                    }
                }
            });
        }
    });
});

我在actions.class.php中更改了processForm操作,如下所示:

...
if ($form->isValid())
{
  $Category = $form->save();
        if($request->isXmlHttpRequest()) {
            return $this->renderText("ok!");
        } else {
            $this->redirect('category/edit?id='.$Category->getId());
        }
}

但这并没有改变任何事情。如何做到这一点?

编辑8/1/12:

我已经根据blowski和sakfa的答案对我的代码进行了更改,但我遇到了另一个问题:如何捕捉表单错误?我向if添加了processForm else,它按预期工作,但我无法返回错误消息/代码/任何内容,只有错误存在的事实。

这是代码:http://pastebin.com/ppbPM88G这是发送表单后的服务器答案,其中一个必填字段为空:

{"haserrors":true,"error":[]}

基于此处的对话:

您已将return $this->renderText("ok!")放在processForm方法中,但未在操作中(如executeCreate)。将返回行和条件检查移动到executeXX方法。

编辑2012-01-08

我已经删除了我的旧代码片段,因为它们现在没有任何用处,因为您编辑了原始代码,有效地将我的更改包含在其中。

关于你的新问题:

基本上,symfony1API在处理表单时很糟糕,这就是为什么你会遇到这么多问题。

首先,您需要知道,当涉及到验证时,这个api并不是为处理AJAX表单提交而设计的——这是因为sfForm可以验证自己,可以在内部存储错误,并可以将其呈现为HTML——但(据我所知)没有以某种可序列化格式返回错误的例程(比如json_encode很好地编码的fieldname=>errorMessage对数组)。

从你的代码开始,我会代替你做的是:

首先:假设您执行POST请求,则仅为ajax提交处理创建单独的操作

public function exucuteAjaxFormSubmission(sfWebRequest $request)
{
    //this action handles ONLY ajax so we can safely set appropriate headers
    $this->getResponse()->setContentType('text/json');
    $form = new form();
    $form->bind($request->getPostParameters());
    if ($form->isValid()) {
        //do your logic for positive form submission, i.e. create or update record in db
        return json_encode('ok'); //notify client that everything went ok
    } else {
        return $this->doSomeMagicToGetFormErrorsAsAnJsonEncodedArray();
    }
}

现在转到doSomeMagicToGetFormErrorsAsAnJsonEncodedArray部分:您希望获得json格式的表单错误。为此,我们将向表单类添加一个简单的方法(因为这是验证逻辑的"接口")。

一些理论:内部sfForm将验证错误存储在一个名为sfValidatorErrorSchema的结构中。sfValidatorErrorSchema将错误存储在两个列表中—namedErrorsglobalErrors。命名错误是为"字段验证器"(即name字段上的必需字符串验证器)抛出的错误。全局错误是为整个表单(即全局postValidators)抛出的错。每个错误都是由有问题的验证器抛出的sfValidatorError对象。

警告:事实上,这个结构是递归的,但只有当你使用嵌入式表单时,你才会看到它在这种情况下,必须更改以下函数,以包括sfValidatorErrorSchema可以包含另一个sfValidatorError Schema,而不是sfValidatorError的情况。。我希望您不要使用嵌入式表单,因为symfony中的这比普通形式的API更糟糕。

但是说得够多了,如果你只想要代码,那么把这些方法复制粘贴到你的表单类中:

class myForm extends sfForm { 
    (...)
    /** a helper method to convert error schema to an array */
    public function getSerializableErrors()
    {
        $result = array();
        foreach ($this->getErrorSchema()->getNamedErrors() as $fieldName => $error) {
            $result[$fieldName] = $error->getMessage();
        }
        foreach ($this->getErrorSchema()->getGlobalErrors() as $error) {
            $result['_globals'][] = $error->getMessage();
        }
        return $result;
    }
    /** screw array, just give me ready to send json! */
    public function getJsonEncodedErrors()
    {
        return json_encode($this->getSerializableErrors());
    }
}

现在只需将doSomeMagicToGetFormErrorsAsAnJsonEncodedArray更改为getJsonEncodedErros,就可以完成带有验证的基本ajax表单发布了——您现在应该有足够的知识来正确地实现您的逻辑。我已经在当前的symfony 1.4版本上测试过了,所以如果出现任何问题,可能是旧sf版本的问题(你没有告诉我你使用的是哪个版本)

根据我们的对话,我可以看到发生了什么。如果我理解了你的评论,那不是重定向整个页面,只是在对话框中重新呈现原始表单?

用户提交表单后,如果表单有效,则重定向。然而,由于您绕过了重定向,它会到达代码的$this->setTemplate('new')位,因此再次显示new表单,其中填充了刚刚完成的表单中的数据。

要绕过它,请在创建操作中使用类似的东西:

if($request->isXmlHttpRequest()) {
  $this->renderText(json_encode(array('valid' => $form->isValid())));
} else {
  $this->setTemplate('new');
}

您还需要更改Ajax请求,以指定它需要JSON响应。然后,如果表单有效,请关闭对话框(或保存后要执行的任何操作)。