External form with own controller

Permalink
Hi there

I've mad an external form for my contact form. The styled HTML form is in the folder "external_form/forms/" and the controller with the same filename in the folder "external_form/forms/controllers". The correct function is called in my controller class when i push the send button and an email was send to me...so far, so good.

Now I've got treeproblems:
1.After that I would like to redirect the user to an other page with the command "$this->redirect('/tanks');" but that dosent work corectly. I have to put the URL with my '/tanks' together, but I can't
2. Why is the standard function "view()" or "on_start()" not working? How could I save the actually URL in a hidden input on the form when the form is showing?
3. In my URL is set the language e.x. "mysite.ch/en/company/contact" so i know the acctually language and this information has to be in the mail to. But when the form is filled out with errors and after that correctly I loose the language info in my URL, because it looks like "mysite.ch/?index.php?cID=530&bID=533&arHandle=Newsletter&ccm_token=1313742449:56fc94d929c59e8b24c9b012540d2f67&btask=passthru&method=contact_send"

Thanks for help

PS: Maybe it't completely the wrong direction i chose :S

 
jordanlev replied on at Permalink Best Answer Reply
jordanlev
I've tried to use external_forms before but ran into so many problems I just gave up and created my own blocks that have forms in them. I think external_form block should be completely eradicated from the system as it provides very little benefit over a single_page or a custom block, and causes lots of problems when you try to do anything advanced with it, and also confuses end-users because they think adding the "external form" block to a page is for things like pasting in Mailchimp/Constant Contact forms.

So I don't have a solution to your exact problems here, but I am attaching a block that you could use as a starting point as a replacement for the external_form. (Note that this goes into your site's top-level "blocks" directory, not in "packages").

Hope it helps.

-Jordan

EDIT: I've since updated this code and the latest version is available here:https://github.com/jordanlev/c5_custom_contact_form...
intellib replied on at Permalink Reply
Thanks,
it works fine with a block.

I've got one bug in it, when adding the block and fill out tanks you mesage and notify mail and click (insert/update), the two errors 'You must enter your name.' and 'You must enter your email address.' appears.
Is it possible that it calls the function "validate($data)"? how can I avoid that?
jordanlev replied on at Permalink Reply
jordanlev
Sorry about that -- yeah I did notice a few bugs in there after I posted that. I've put new updated code here:
https://github.com/jordanlev/c5_custom_contact_form...

But if you just want to correct that error in your own file, change the name of the "validate" function in controller.php to something else, like "validate_form". Then also change the code that calls that function so it's using the new name as well.

Another bug was in the view.php file, where you need to change this:
<?php if ($showThanks); ?>

...to this:
<?php if ($showThanks): ?>

(they're almost exactly the same, but that should be a colon at the end, not a semicolon).
intellib replied on at Permalink Reply
Tanks.
One more question. I used two checkboxes within the form, created by the form helper. But the sate i can't read out in the controllers function action_submit_form()....any ideas?

controller.php
$data->getInfo = $this->post('infos');


view.php
<?php echo $fh->checkbox('infos', $data->infos, true); ?>
jordanlev replied on at Permalink Reply
jordanlev
Checkbox fields in HTML are always a little annoying. The problem is that *nothing* is POSTed if the checkbox isn't checked. So you can't just check the value of that field because if the user didn't check it, there is no value to check. Instead you want to do something like this:
$data->getInfos = empty($this->post('getInfos')) ? false : true;


I should probably update that code I have on github to include an example of these since it's such a tricky thing (took me a while to figure it out when I first started).
CWSpear replied on at Permalink Reply
CWSpear
jordanlev, it seems as though you deleted your GitHub repo for your contact form block. Do you still have that code somewhere? I tried looking at your other repos and didn't see anything that immediately stuck out.
jordanlev replied on at Permalink Reply
jordanlev
Oops, sorry about that. I put it back up.
vGibson replied on at Permalink Reply
vGibson
Is the block located in your GIT up to date for C5 v8?

Also, if the above is a yes anyway, is it possible to write this data to a different database instead of the concrete database or concurrently with it.

Thanks!
jordanlev replied on at Permalink Reply
jordanlev
Nope and nope (I'm still rocking Concrete5.6)
vGibson replied on at Permalink Reply
vGibson
This makes me sad :(
lol...

ok man, Rock on! 5.6 is solid too and has WAY more options in the market place... :)
p2p replied on at Permalink Reply
I stumbled across this and looking for additional help. Jordan thank you for making you custom form block first of all. What I can't figure out is the markup you place in the view.php. I have a custom built form that I'm trying to transfer to a new site for a client that has lots of radio buttons with scales and several related rows of questions. (This is why Advanced Forms will not be the solution for me.)

I'm scratching my head over your instructions for the Custom Form Block you created. I've copied and pasted the html from the old form and pasted it into view.php. What was already in view.php is this:
<?php echo $fh->label('name', 'Name:'); ?>
<?php echo $fh->text('name'); ?>


My question is do I have to go through old table based HTML form layout and convert things like:
<table width="480" border="0" cellpadding="2" cellspacing="0" class="rating">
          <tr class="repeat">
            <td colspan="4" align="left" valign="middle"><h2>Preferred Method of Contact</h2></td>
          </tr>
          <tr class="repeat">
            <td align="left" valign="middle"><input id="alumni_preferred_contact_home_phone" name="alumni[preferred_contact]" type="radio" value="Home Phone" /> Home Phone</td>
            <td align="left" valign="middle"><input id="alumni_preferred_contact_work_phone" name="alumni[preferred_contact]" type="radio" value="Work Phone" /> Work Phone</td>
            <td align="left" valign="middle"><input id="alumni_preferred_contact_home_email" name="alumni[preferred_contact]" type="radio" value="Home E-mail" /> Home E-mail</td>
            <td align="left" valign="middle"><input id="alumni_preferred_contact_work_email" name="alumni[preferred_contact]" type="radio" value="Work E-mail" /> Work E-mail</td>
          </tr>
        </table>


If so, how do I handle a complex scale style with multiple columns and rows?

Just any guidance would be helpful. Thanks.
jordanlev replied on at Permalink Reply
jordanlev
The sample code I have in view.php uses Concrete5's built-in "form helpers", which are code shortcuts for outputting form fields. But you absolutely do not need to use those if you don't want -- you can use your existing form html.
The only problem you'll run into is if the user submits the form and there's an error -- you will want some PHP code in your form to re-display the user's last inputted data (otherwise they'll have to fill out the entire form again if they miss just 1 required field for example). This is functionality that the C5 form helpers do for you automatically, which is why I use them -- because it saves me from having to write this code to "repopulate" form fields.

Note that you can also use the form helpers along with your table structure -- the form helper code just outputs the form elements -- but you can put those snippets of code inside your html <table> if you want. There are form helpers for all kinds of fields, including radio buttons, so this should be very doable given your situation.

See this documentation page for some basic info about the form helpers (unfortunately it's not very good, but hopefully gets you on the right track):
http://www.concrete5.org/documentation/developers/forms/standard-wi...
p2p replied on at Permalink Reply
Thanks for answering that.

How do you set what is required with using straight HTML for this block?
p2p replied on at Permalink Reply
Also when the form is submitted I get this displaying:

You must enter your name.
You must provide a valid email address

Where is the "required" fields being set?
p2p replied on at Permalink Reply
Nevermind. I found it in the controller.php
p2p replied on at Permalink Reply
Ok, I've got it to send the form because when I check the log I see the info, but is this supposed to be storing it in a DB too?
webdez1ner replied on at Permalink Reply
Hi,

Thanks for great tips and custom block Jordan! Everything works just fine except translating the error messages.

I've tried to wrap messages in controller.php's public function validate_form() function into t() variable like this:
$val->addRequired('name', t('You must enter your name'));


Then i updated messages.mo file with PoEdit, but the translated error messages don't show up. Any ideas how to translate the form messages?

Thanks in advance!
pypu replied on at Permalink Reply
I have been using this with the external form block to return messages.

This works but I think I am gonna use jquery to display the inputs that need to be filled out as my next task in this form. I'll leave the sanitization/validation in the controller for security but will have the page itself put a red box around the non-filled required inputs and turn off the submit button til they are filled. Possibly just have the php change the value of each field if not filled out to display the warning that way.

In the controller if the validation helper returns errors I process them like this:
// break if bad
else {
$error_list = '<p style="font-weight:bold;">We are sorry but the fields we need for your submission are not filled out.</p><p style="font-weight:normal; font-size: .4em;">Please fill out the fields pertaining to ';
foreach ($val->getError()->getList() as $error) {
$error_list .= '<span style="font-weight:bold;">'.$error.'</span>, ';
}
$error_list .= ' and any others you may have missed that will help. Thank you.</p>';
$this->set('message', t("$error_list"));
}

the foreeach loop is setting up the formatting so its legible and I have a message that lists these above the form using php like this:
/** This is the message that displays above the form. It does also display errors if required fields are not filled out. It also shows the success message. */ ?>
<div style="font-weight: bold; font-size: 2em; "><p><?=$message?></p></div>

I also use this to to check $response for the 'received' message and then show the form only when its needed (before submitting and if required not filled out) here. I am using flexbot to layout the form:
if ($response !== 'received') {
/** The basic method for having the form post to the function in "controller/BASIC_TEMPLATE_form.php" as seen in the test_form.php set. */
?>
<form method="post" action="<?=$view->action('test_search')?>">
<?php
/** I am using FlexBot to setup the form fields that look wierd taking up an entire line to themselves.
* This makes the first/last name inputs as well as the city/zip inputs look more normal.
* I am using a flex column to place the label above the input.
* I am using a flex row to place the 2 columns side by side in order to eally split the space.
* The margin is for tidyness.
*/ ?>
<div class="form-group" style="display:flex;flex-direction:row;">
<div style="display:flex;flex-direction:column;flex:1; margin-right:1em;">
<label for="firstName" style="flex:1;"><?=t('First Name <span style=" color: red;">*</span>')?></label>
<?=$form->text('first_name', array('style' => 'flex:1', 'id' => 'firstName' ))?>
</div>
<div style="display:flex;flex-direction:column;flex:1;">
<label for="lastName" style="flex:1;"><?=t('Last Name <span style=" color: red;">*</span>')?></label>
<?=$form->text('last_name', array('style' => 'flex:1', 'id' => 'lastName' ))?>
</div>
</div>

Not sure if this is useful but it worked for me. I am SUPER new to php so if I made mistakes, created ugly code, etc then my apologies. Any help with that is always welcome.

The entire code is posted here if the structure here if it helps but its in the external form block layout. See:https://documentation.concrete5.org/editors/in-page-editing/block-ar...