Jump to:

17452 Posts in 4473 Topics by 1971 members

Archive

SilverStripe Forums » Archive » infinite loop in form validator because of redirectBack

Our old forums are still available as a read-only archive.

Moderators: martimiz, Sean, biapar, Willr, Ingo, simon_w

Page: 1
Go to End
Author Topic: 1207 Views
  • jahbini
    Avatar
    Community Member
    13 Posts

    infinite loop in form validator because of redirectBack Link to this post

    This post might come under the general heading of "best practices/worst practices," and I'm putting it here to help save some other programmer from hours of debugging.

    I have a single checkbox (named 'Tracking') in a form field. It needs to be checked on submission to see if that user has proper credentials (if it fails the validation I want the user to see a message on what to do next.) There is also a field that is mandatory ('Entry') and must be filled in.

    When the check box gets selected, the validator signaled a reject. Unfortunately, when the validator returns with the invalid response code (false), the calling Form object will redirectBack to the previous page: which just happens to be the exact page we are on, and the URL ends with '?executeForm=...' . This caused an infinite redirect loop that took me about 8 hours to figure out.

    The '?executeForm=...' was causing a reload of the form data from a 'GET' rather than a 'POST' (redirectBack won't be handled as a post). This caused the form data to get loaded from the non-existent POST data. This resulted in a blank field (the mandatory 'Entry'). That new request got rejected and the cycle went on till the browser gave up.

    Fortunately, the redirectBack can be routed by setting a 'magic' request array value: $_REQUEST['_REDIRECT_BACK_URL']. This allowed me to force a 'good' destination when the validator returns the reject code.

    I also needed the check box 'Tracking' field needed to be unset. That was not obvious (even reading TFM and looking at the sapphire code).

    So when you need to reset the value of Tracking to 0 from within a validator, I called:

    $this -> form -> resetData( 'Tracking' , 0);

    This 'seems' to work. Maybe.

    Things that did NOT work:
    // unset($data['Tracking]);
    // $this -> form -> unsetDataFieldByName($this->checkboxFieldName);
    // unset ($data[$this->checkboxFieldName]);
    // unset ($_REQUEST[$this->checkboxFieldName]);

    The final 'working' code in the validator was:

    class myValidator extends Validator {
    var $thisPage; // passed in as a new argument on construction
    var $entryFieldName;
    var $checkboxFieldName;

    function javascript() { return ""; } // no javascript needed.

    function __construct($thisPage,$entryFieldName,$checkboxFieldName) { parent::__construct($entryFieldName,$checkboxFieldName);
    $this->thisPage = $thisPage;
    $this->entryFieldName = $entryFieldName;
    $this->checkboxFieldName = $checkboxFieldName;
    }

    function php ($data) {
    ...
    $accept = true;
    if($data[$this->entryFieldName] == "") {
    $this->validationError( $this->entryFieldName,
    sprintf( _t('Form.FIELDISREQUIRED'),
    strip_tags($this->entryFieldName)),
    "required");
    $accept=false;
    }
    if($data['Tracking'] && !Permission::check('SITE_WATCHER') )
    {
    $accept = false;
    $this->validationError($this->checkboxFieldName, "only Registered Voters and above may check this box", "permission" );
    }

    set $accept if we like this data
    ...
    if( $accept ) return true;
    //avoid infinite loop when previous page is ALSO a form execution on this page

    //Debug::message($this->checkboxFieldName);
    // $this -> form -> unsetDataFieldByName($this->checkboxFieldName);
    // unset ($data[$this->checkboxFieldName]);
    // unset ($_REQUEST[$this->checkboxFieldName]);
    $this->form->resetData($this->checkboxFieldName,0);

    $_REQUEST['_REDIRECT_BACK_URL'] = Director::link($this->thisPage->URLSegment);
    // we reject the data
    return false;

    }

    The call to create the validator from the Form() function:

    function Form() {

    ... lots of form kind of stuff to create the $fields and the $actions

    // the entryValidator needs to know the page we are on because it has the URLSegment (and some other stuff that may not be important for this exposition)

    // the Validator (parent class) needs to know the field names we are looking at
    $vv = new entryValidator($this, "Entry", "Tracking" );
    $f= new Form($this, 'EntrySuggestionForm', $fields, $actions,$vv);
    return $f;
    }

    1207 Views
Page: 1
Go to Top

Want to know more about the company that brought you SilverStripe? Then check out SilverStripe.com

Comments on this website? Please give feedback.