Search code examples
typo3typo3-11.x

TYPO3 Fluid Form returns old values


Am running a form using fluid with two fields, username and password. When first run, correct data is sent to the action. When different data is resubmitted, original data is sent to the controller action instead of the new values. How do I solve this problem?

EDIT: I've discovered that an array containing the user-submitted form fields and their values are obtained from the request, serialized as is and the string stored in a hidden input field called '__referrer[arguments]', which is then submitted with the form back to the user. When the user resubmits the form again with new values, the user doesn't realize that the old values are in the form, in the form of a serialized string, which is submitted together with the new values. Turns out, this is ok if no errors are reported by the validators. In that case the data is simply passed to the controller action and processing continues. But if errors are collected, processing is not sent to the controller action but is sent to the error action. The error action unserializes the old data and forwards that data (instead of the the new values) to the intended action controller. See \TYPO3\CMS\Extbase\Mvc\Controller\ActionController::forwardToReferringRequest().

EDIT: Steps to reproduce; Create an action with one argument and create a form with one input element and a submit button. Create a validator for the element. Make it a string property. When all is said and done, start by sending a VALID value and let the form return. it will come back with no errors. but also if you look at it's hidden values, you find that the __referrer[arguments] has changes. That's because your previous values were serialized and are there. Now submit an INVALID value and check values entering your action. You'll be stunned they are the old ones.

This is weird. Currently if I disable the production of the __referrer[arguments] input field in the \TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::renderHiddenReferrerFields() method, everything works properly. How do I solve this? Please help.


Solution

  • Where things go wrong:

    Here: \TYPO3\CMS\Extbase\Mvc\Controller\ActionController::forwardToReferringRequest() . In this method, arguments are sought from __referrer internal arguments instead of the submitted values. Normally, if errors are found, only two elements are found in the arguments form variable: controller for controller name and action for action name. This is because they were submitted originally with the form and they will recycle without changing as long as the validator finds errors. Nothing else will be added to it. This is good... until it validates. When it validates, results are sent directly to the action controller and not through the error controller. When the process goes back to the form, the object or arguments submitted will be added to the form and returned to the user. Remember it validated. When you then send a wrong value next, it goes to the error controller, but the old values (that validated) and were serialized in the __referrer[arguments] are unserialized and forwarded to your action. And that's how you end up with old values in your action. This is because it assumes that the variable carries only two values inside it; the controller and action names only. It's wrong.

    Assumption:

    Form post values processing seem to be built under the presumption that once a form validates, you won't need it again.

    News.

    The values you send are sought from extbase arguments and serialized in \TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::renderHiddenReferrerFields() method, added to the form just before presenting it to you. All TYPO3 has to do is skip your values and let the default values only be serialized. Just saw that the doc section of the function has this:

    /**
         * 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)
         */
    

    The @todo part is the news. Hope it's done in the next-patch since there are many scenarios where you want to resume the form such as in data entry.

    Solution

    Easiest solution: Initialize the empty argument in your action and hand the argument to the form. In my case, I use a DTO. Example

    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();
    }
    

    Hope it helps someone.