TYPO3 流体形式 returns 旧值

TYPO3 Fluid Form returns old values

我 运行 使用具有两个字段 usernamepassword 的流体创建表单。当第一个 运行 时,正确的数据被发送到操作。当重新提交不同的数据时,将原始数据而不是新值发送到控制器操作。我该如何解决这个问题?

编辑:我发现包含 user-submitted 表单字段及其值的数组是从请求中获取的,按原样序列化 和存储在名为“__referrer[arguments]”的隐藏输入字段中的字符串,然后将其与表单一起提交回用户。当用户再次使用新值重新提交表单时,用户没有意识到旧值以序列化字符串的形式存在于表单中,并与新值一起提交。事实证明,如果验证器没有报告错误,这是可以的。在这种情况下,数据只是简单地传递给控制器​​操作,然后继续处理。但是如果收集到错误,则处理不会发送到控制器操作,而是发送到错误操作。错误操作反序列化旧数据并将该数据(而不是新值)转发到预期的操作控制器。参见 \TYPO3\CMS\Extbase\Mvc\Controller\ActionController::forwardToReferringRequest()

编辑:重现步骤; 创建一个带有一个参数的动作,并创建一个带有一个输入元素和一个提交按钮的表单。为元素创建一个验证器。将其设为字符串 属性。当一切都说完之后,首先发送一个 VALID 值并让表单 return。它会毫无错误地返回。而且,如果您查看它的隐藏值,您会发现 __referrer[arguments] 发生了变化。那是因为您以前的值已序列化并且存在。现在提交一个 INVALID 值并检查输入您的操作的值。你会惊呆他们是旧的。

这很奇怪。目前,如果我在 \TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::renderHiddenReferrerFields() 方法中禁用 __referrer[arguments] 输入字段的生成,则一切正常。我该如何解决这个问题?请帮忙。

哪里出了问题:

此处:\TYPO3\CMS\Extbase\Mvc\Controller\ActionController::forwardToReferringRequest()。在此方法中,arguments 是从 __referrer 内部参数而不是提交的值中寻找的。通常,如果发现错误,在arguments 表单变量中只会找到两个元素:controller 控制器名称和action 动作名称。这是因为它们最初是与表单一起提交的,只要验证器发现错误,它们就会不做更改地回收。不会添加任何其他内容。这很好......直到它验证。当它验证时,结果直接发送到动作控制器,而不是通过错误控制器。当流程返回到表单时,提交的对象或参数将被添加到表单并返回给用户。记住它已验证。当您接下来发送一个错误的值时,它会转到错误控制器,但是旧值(已验证)并在 __referrer[arguments] 中被序列化,并被反序列化并转发给您的操作。这就是你如何在你的行动中以旧价值观结束。这是因为它假定变量内部只包含两个值;仅控制器和操作名称。错了。

假设:

表单 post 值处理似乎是在这样的假设下构建的,即一旦表单通过验证,您将不再需要它。

新闻。

您发送的值是从 extbase 参数中寻找的,并在 \TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::renderHiddenReferrerFields() 方法中序列化,在呈现给您之前添加到表单中。 TYPO3 所要做的就是跳过你的值,让默认值只被序列化。刚看到函数的文档部分有这个:

/**
     * Renders hidden form fields for referrer information about
     * the current controller and action.
     *
     * @return string Hidden fields with referrer information
     * @todo filter out referrer information that is equal to the target (e.g. same packageKey)
     */

@todo部分是新闻。希望它在 next-patch 中完成,因为在许多情况下您想要恢复表单,例如在数据输入中。

解决方案

最简单的解决方案:在您的操作中初始化空参数并将该参数传递给表单。就我而言,我使用 DTO。 范例

public function accountLoginAction(DTO\Account\LoginDTO $accountLogin=null):ResponseInterface
{
    if($accountLogin){
        $this->repository->logon();
        ...
    } else{
        $accountLogin=DTO\Account\LoginDTO::getNewInstance();
    }
    $this->view->assign('object', $accountLogin);

    return $this->response();
}

希望对大家有所帮助。