Jump to content
Soma

Form API store data in session and repopulate (hint)

Recommended Posts

Maybe this helps someone. Nerd alert!

Currently building a shop module for a project, where I was looking for a easy way to handle/store form data in session and later repopulate it easily using form API. 

It can be very tedious to do that manually grab the fields, store in session repopulate form. So I found a way to do it "automatically" by serializing form object and build a name => value array that I store in session, then retrieve the array later and convert it to WireInputData as it is required for form object to process.

Further I needed to turn of CSRF temporarely to get around error when populating the form object.

Here a example code for those interested.

// generate $form

// when sent
if($input->post->send) {
    
    // process form
    $form->processInput($input->post);
    
    // if no errors
    if(!count($form->getErrors())){

         // serialize form values and store in "shop" session namespace
        $formfields = $form->getAll();
        $formdataKeys = $formfields->explode(function($item, $key){ return $item->name; });
        $formdataValues = $formfields->explode(function($item, $key){ return $item->value; });
        $formdata = array_combine($formdataKeys, $formdataValues);

        $session->setFor("shop", "userformdata", $formdata );
        $session->redirect("nextpageurl");
    }

} else {

    // if session formdata found repopulate form object
    if($formdata = $session->getFor("shop", "userformdata")){
        $formdataInput = new WireInputData($formdata);
        $form->protectCSRF = false; // to not get a CSRF validation error
        $form->processInput($formdataInput); // fills in form and validates it
        $form->protectCSRF = true;
    }
}

return $form->render();
  • Like 11

Share this post


Link to post
Share on other sites

For security. I wanted to add, that the stored values in the array are not entity encoded and if you don't strip tags they're stored as entered, so you'd have to take care of that and entity encode with htmlspecialchars() them before printing them somewhere or use a sanitizer. When using the form render() it already takes care of that when populating the inputfields. It's still possible you have or want to allow tags, so it's a question of what you do with the data. Always be careful and if in doubt ask a experienced developer.

foreach($formdata as $name => $val){
    ...
    $out .= "<td>" . htmlspecialchars($val, ENT_QUOTES, "UTF-8") . "</td>";
    ...
}

You could add a strip tags when getting the values like this:

$formdataValues = $formfields->explode(function($item, $key){ return strip_tags($item->value); });
  • Like 1

Share this post


Link to post
Share on other sites

Smells like a ProcessWire Recipe :)

Or make a module out of it?

  • Like 1

Share this post


Link to post
Share on other sites

Let's see what happens. :)

Of course alternatively, serializing the form object also works quite simply with a foreach, without using PW's WireArray::explode() which is fun anyway. :)

After all the trick here is the $form->getAll(), which returns a InputfieldWrapper containing a flat array of only the fields whithout fieldsets and nested wrappers. 

And example of how to populate the form directly without using processInput($data), which requires to toggle the CSRF and the form validates and show errors when rendering the form. So setting values to the form object using $form->get(field)->attr("value", $value) does that "silently" and it doesn't trigger any validation thus not show errors when initially loading the form.

if($input->post->send) {

    $form->processInput($input->post);

    if(!count($form->getErrors())){
        $exclude = array("send"); // skip fields by name 
        foreach($form->getAll() as $field) {
            if(in_array($field->name, $exclude)) continue;
            $formdata[$field->name] = strip_tags($field->value);
        }
        $session->setFor("shop", "userformdata", $formdata );
        $session->redirect($this->page->url . $this->nextStepSegment);
    }

} else {

    // populate data to form inputfields without using processInput(), which processes the form
    if($formdata = $session->getFor("shop", "userformdata")){
        foreach($formdata as $name => $value) 
            $form->get($name)->attr("value", $value);
    }

}

return $form->render();
  • Like 3

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...