Custom Add-On: form submission & POST not passing to templater

I’m trying to put together a custom add-on controller to handle a variety of form submissions that I intend users to have access to. I do not want to use the built-in form builder, as I want to handle the form code myself.



I managed to put together a small test framework by reviewing the docs & looking at profile.update procedures. I am able to get a basic form up, but I keep running into problems with the submission thru POST.



The controller, customforms.php fires, as well as a php file I include from inside customforms.php. But, the form content of the test.tpl template never appears when I submit the form back to the same page. The source code of the served page always has a blank line inside the

tags, where my customform should appear.



The docs say all controllers need to return array(CONTROLLER_STATUS_OK,…); for all POST methods, but it doesn’t seem to make a difference in my scenario. My POST code will simply validate the form submission, and provide some visual feedback thru CSS on corrections the user needs to make, or execute a server side script to process the form.



…/cscart/index.php?dispatch=customforms.test



CustomForms.php

```php if ( !defined('AREA') ) { die('Access denied'); }

//Require login - should return user to requested URL after sign in
if (empty($auth['user_id'])) {
return array(CONTROLLER_STATUS_REDIRECT, "auth.login_form?return_url=".urlencode(Registry::get('config.current_url')));
}

$skin_path = DIR_SKINS .Registry::get('config.skin_name');
$view->assign('skin_path', $skin_path);

if ($_SERVER['REQUEST_METHOD'] == 'POST') {
//get php include for this particular form/mode name
$customform_phpfile = $skin_path ."/customer/views/customforms/" .$mode .".php";
include $customform_phpfile;
return array(CONTROLLER_STATUS_OK);
}

else {
if ($mode == 'view') {
fn_add_breadcrumb(fn_get_lang_var('customforms'));
$customforms_settings = fn_get_settings('customforms');
$view->assign('customforms_settings', $customforms_settings);
$view->assign('customforms', $customforms);
}
else {
//get php include for this particular form/mode name
$customform_phpfile = $skin_path ."/customer/views/customforms/" .$mode .".php";
include $customform_phpfile;
return array(CONTROLLER_STATUS_OK);
}
}

?> ```test.php - included from customforms.php above

```php /* This file gets called form customforms.php thru $mode - it is processed before the main form content */

include_once $skin_path ."/customer/views/customforms/formvalidator.php";
$page_title = "Installation Certificate CF-6R-MECH-21-HERS";
$form_title = "Installation Certificate CF-6R-MECH-21-HERS";
$show_form = true;
$show_thank_you = false;
$error_hash = array();
$show_error = false;


if($_SERVER['REQUEST_METHOD'] == "POST")
{
//Stuff $_POST values into $vars
$post_vars = getRealPOST();
$validator = new FormValidator();
//since the validation errors echo is commented out a few lines below, the error description parameter here really doesn't matter
$validator->addValidation("site_address","req","Site Address Required");
$validator->addValidation("enforcement_agency","req","Enforcement Agency Required");
$validator->addValidation("permit_number","req","Permit Number Required");
$validator->addValidation("duct_leakage_test_option","req","You must select a Duct Leakage Test option 1-4");
$validator->addValidation("fan_airflow_method","req","You must select a Fan Airflow method");
$validator->addValidation("company_name","req","Required Field");
$validator->addValidation("person_responsible","req","Required Field");
$validator->addValidation("cslb_license","req","Required Field");
$validator->addValidation("date_signed","req","Required Field");
$validator->addValidation("position_with_company","req","Required Field");
$validator->addValidation("third_party_quality_control","req","Required Field");

if($validator->ValidateForm())
{
$show_form = false;
$show_thank_you = true;
$pdf_email_sent = include_once('form_email_pdf.php'); //true or false if completed
if ($pdf_email_sent) {echo "EMAIL SENT";} else { echo "NOT SENT";}
}
else
{
$error_hash = $validator->GetErrors();
$show_error = true;
}
}

else {

}

$view->assign('page_title', $page_title);
$view->assign('form_title', $form_title);
$view->assign('show_form', $show_form);
$view->assign('show_thank_you', $show_thank_you);
$view->assign('error_hash', $error_hash);
$view->assign('show_error', $show_error);

?> ```test.tpl

```php {if $show_error}

an error occurred!!

{* Display validation errors *}

{foreach from=$error_hash item=error_desc}

{$error_hash.error_desc}



{/foreach}



{else}



{$form_title}







{$form_title}



Duct Leakage Test - Existing Duct System







Site Address



















{/if} ```Anyone have an ideas where I am going wrong?

Unless you have a template in skin_stuff/customer/addons/your_addon/views/your_addon/.tpl (where is the mode the controller was called with), you need to provide a redirect URL to your array(CONTROLLER_STATUS_OK) return.



I.e. assuming you were called as dispatch=CustomForm.update as a POST method, then if you don’t have an ‘update.tpl’, you need to provide an explicity redirect URL as the 2nd element of the returned array such as:

return array(CONTROLLER_STATUS_OK, $return_url);



Cs-cart is a little weird here because of the way they “run” controllers. Hence, POSTed info simply updates the DB or other info. It does not pass through as you would expect. Specifically you can’t do the POST and then pass the values through the view. You need to call your form page with GET parameters to have them update or write them to the SESSION or DB… They assume a POST will always redirect to another controller/mode.

I do have the skin_stuff/customer/addons/your_addon/views/your_addon/.tplfile, it’s the test.tpl one I put in my first post. On a side note, I found redirection slow, as return array(CONTROLLER_STATUS_OK, $return_url); always seems to wait 10 seconds before redirecting. I was able to get instant results using fn_redirect(), but my problem with POST not passing values thru to the view was the big issue.



Your comments about POST not passing values thru to the view & expecting to pass to another controller makes sense with what I’ve seen in the docs & existing code. I am at a loss to understand why CS Cart forced this approach, but I’m sure there is some reason.



I suppose I could use a GET & stuff parameters, but I’m worried that I will eventually run into some parameter I don’t want to publish in the URL thru GET. I might store the info in the SESSION.



tbirnseth, I sincerely appreciate your fast response. I’ve searched the forums quite a bit over the last week or two, and you seem to be one of the most active, and most knowledgeable members in the developers section here. I want to say your generosity of time & effort does not go unnoticed.

Thanks for the kind words… I do have my motives though… I try to get some business from here as well, but belive it’s a give and take thing…

One thing that strikes me as odd, which I was hoping you could verify is the behavior CS Cart takes. I’ve got my code processing for both POST & GET from the same controller file (customforms.php) & mode (cf_6r_mech_21_hers). When I process the POST method, it doesn’t pass to the $mode templater skin , so I’ve added a call to fn_redirect()



Let me walk thru it:

…index.php?dispatch=customforms.cf_6r_mech_21_hers



When using GET method, customforms.php controller file completes & passes to cf_6r_mech_21_hers.tpl as expected.



When using POST method, customforms.php controller file completes, but never seems to pass to cf_6r_mech_21_hers.tpl, as I always get a blank central-content



So what I added to the end of the POST method code inside customforms.php is add fn_redirect($_SERVER[‘HTTP_REFERER’], true); , which then calls customforms.php thru GET method to get cf_6r_mech_21_hers.tpl code to display.



Seems like that fn_redirect() shouldn’t be necessary. Am I doing something wrong?

As stated a few posts up, POST in cs-cart does not behave in the way you would expect. I.e. POSTED data is NOT available to the template because they require a redirect (either explicitly via fn_redirect() or implicitly via the return array(CONTROLLER_STATUS_OK, redirect_url).



In any case, you have to either store you posted data in the SESSION or in the DB and then do a redirect to yourself to process it and pass it to the template via a GET request.



They assume that POSTED data is only to be stored and not intended to pass form values around. They assume that a GET will be used for that purpose.

I understand what you are saying about the POST data, thank you. My question pertains to the redirection. I guess I just expected the templater to able to be called without the redirect. If that’s the way it is, then that’s the way it is.



Cheers!