I have a common ‘Contact Form’ in my project which is called in most of pages like index, about us etc. this page accept user inputs and sent an email to admin, then return back to the page, from which it is called
Code for contact form is
class Form_Contactus extends Zend_Form
{
public function init()
{
$this->setMethod('post');
$this->setAction('contactus/index');
$frontController = Zend_Controller_Front::getInstance();
$pageName = $this->createElement('hidden','pageName');
$pageName->setValue( $frontController->getRequest()->getControllerName() );
$FullName = $this->createElement('text','FullName');
$FullName->setLabel('Full Name')
->setRequired(true)
->addFilter('StripTags')
->addFilter('StringTrim')
->addValidator('NotEmpty');
$Email = $this->createElement('text','Email');
$Email->setLabel('Email')
->setRequired(true)
->addFilter('StringTrim')
->addValidator('EmailAddress')
->addValidator('NotEmpty');
$Message = $this->createElement('textarea','Message');
$Message->setLabel('Message')
->setAttribs( array('rows' => 3, 'cols' => 20 ))
->setRequired(true)
->addFilter('StripTags')
->addFilter('StringTrim')
->addValidator('NotEmpty');
$submit = $this->createElement('submit','submit');
$submit->setLabel('Submit')
->setIgnore(true);
$this->addElements(array( $pageName,
$FullName,
$Email,
$Message,
$submit, )
);
}
}
Please note that, the line $this->setAction('contactus/index');. My idea is, if I fill this form (note it is a common form) from index page, it pass through 'contactus controller’ index action. Sent a mail from there and return back to index page. If the page is filled from about us page, it return back to about us page.
It is included in the different pages like index, about etc by code
$conForm = new Form_Contactus();
echo $conForm;
And the controller code looks like as
class ContactusController extends Zend_Controller_Action
{
protected $_redirector = null;
public function init()
{
$registry = Zend_Registry::getInstance();
$this->msgObj = $registry['MessageHandler'];
}
public function indexAction()
{
$this->_helper->layout()->disableLayout();
$this->_helper->viewRenderer->setNoRender();
$form = new Form_Contactus();
if ($this->_request->isPost()) {
$formData = $this->_request->getPost();
if ($form->isValid($formData)) {
$pageName = $formData['pageName'];
$FullName = $formData['FullName'];
$Email = $formData['Email'];
$Message = $formData['Message'];
if( strlen(trim( $FullName) ) ){
$mailBody .= "Name:\r\n\t".$FullName ."\r\n\r\n";
$mailBody .= "Email:\r\n\t".$Email ."\r\n\r\n";
$mailBody .= "Message:\r\n\t".$Message ."\r\n\r\n";
$mail = new Zend_Mail();
$transport = new Zend_Mail_Transport_Smtp('localhost');
Zend_Mail::setDefaultTransport($transport);
$mail->setSubject('Contact Enquiry.');
$mail->setFrom($Email, $FullName);
$mail->addTo(CONTACT_ADMIN_EMAIL, CONTACT_ADMIN_NAME);
$mail->setBodyText($mailBody);
if( $mail->send() ){
$this->msgObj->addMessage('Thank you!');
$this->msgObj->addMessage('Your message has been received and will be reviewed within 72 hours.');
}
else{
$this->msgObj->addError('Unable to sent mail! Please try later.');
}
}
}
else {
$this->msgObj->addError('Please correct the following:!');
$form->populate($formData);
$pageName = 'index';
}
}
$this->view->form = $form;
$this->_helper->redirector('index', $pageName);
}
}
everything works fine and mail is gone if I fill this form except that the form is not validated. For example the mail may sent without ‘FullName’, which is a required field
another problem is unable to display messages like ‘'Thank you’ .
this may because of $this->_helper->redirector method I used. The form is redirected and hence lost the values. If I use $this->_helper->forwarded or $this_forward() it also doesn’t work.
Any one can please suggest a method for me to dipsply validation message and other messages properly? Sorry for my poor English and thanks in advance
If the form doesn't validate (and send the contact information), then don't redirect. Simply move your redirect into your "if valid" block.
You can still add a field to store the page to return to once the form is completed successfully. You probably need to go about populating it a different way though, otherwise the contact page will be used as the "go to" page when the form is created in the contactus/index action (ie. when the form doesn't validate the first time)
Also, is there a reason you're not using Zend_Mail to actually send the mail? Since you're using the Zend Framework anyway?
Yes, the problem may be is because of my approach was wrong. I used one controller/page. For eg IndexController for index page, Aboutus Controller for about us page etc. the contactus is a small form that included in all these pages and thus the problem. Anyone can please suggest a better method?
Related
I've searched the forums and have seen many similar issues but none that seem to address my concern. I believe this is different because:
Form validation is not being used at this point
The form method does not seem to be related (just 1 post action)
The routes are not wrapped in web middleware
Here's what the application is supposed to be doing:
A user (with or without Authentication) views a public page with form (display_event)
The user selects a specific ticket for ordering and is directed to a 2nd form (register_step1)
The user then fills out demographic info for as many tickets as are being ordered
The processing step, if the email address used is of a valid user (in DB) should return to the form in step 2 & 3, populate the fields and flash a message. Otherwise it would perform the save() actions required. (register_step2)
The relevant routes from web.php are here:
Route::get('/events/{event}', 'EventController#show')->name('display_event');
Route::post('/register/{event}', 'RegistrationController#showRegForm')->name('register_step1');
Route::post('/register/{event}/create', 'RegistrationController#store')->name('register_step2');
The relevant portions of the RegistrationController.php are here:
public function showRegForm (Request $request, $id) {
// Registering for an event from /event/{id}
$ticket = Ticket::find(request()->input('ticketID'));
$quantity = request()->input('quantity');
$discount_code = request()->input('discount_code');
$event = Event::find($ticket->eventID);
return view('v1.public_pages.register', compact('ticket', 'event', 'quantity', 'discount_code'));
}
And:
public function store (Request $request) {
$event = Event::find(request()->input('eventID'));
if(Auth::check()) {
$this->currentPerson = Person::find(auth()->user()->id);
}
// set up a bunch of easy-reference variables from request()->input()
$email = Email::where('emailADDR', $checkEmail)->first();
if(!Auth::check() && $email === null) {
// Not logged in and email is not in database; must create
$person = new Person;
// add person demographics from form
} elseif(!Auth::check() && $email !== null) {
// Not logged in and email is in the database;
// Should force a login -- return to form with input saved.
flash("You have an account that we've created for you.
Please attempt to login and we'll send you a password to your email address.", 'warning');
return back()->withInput();
} elseif(Auth::check() && ($email->personID == $this->currentPerson->personID)) {
// the email entered belongs to the person logged in; ergo in DB
$person = $this->currentPerson;
// add person demographics from form
} elseif(Auth::check() && ($email->personID != $this->currentPerson->personID)) {
// someone logged in is registering for someone else in the DB
$person = Person::find($email->personID);
// add person demographics from form
} else {
// someone logged in is registering for someone else NOT in the DB
$person = new Person;
// add person demographics from form
}
// do more stuff...
$reg = new Registration; (set up a registration record)
}
I took the advice indicated in #apokryfos's comment and changed the form parsing-then-display script from a POST to a get.
redirect()->back() is, apparently, always a method=get and that was the cause of the MethodNotAllowedHttpException. In my ~2 weeks using Laravel, I hadn't yet come across that fact.
I am trying to let a contact form (Contact Form 7) on a WordPress site create new contacts in my CRM program (solve360). To make it easier, I also activated a plugin (Forms: 3rd Party Integration) in which I defined a submission url and field mapping. Part of it works, but I am missing something simple here...
When pressing the send button, the data is sent to an email address (success) and to solve360 (not yet successfully). I actually receive a message that a new contact was created in solve360, however all the fields are empty. So I am guessing the problem is that the form fields are not properly transferred to the solve360 fields. However, I am using this template from solve360:
// REQUIRED Edit with the email address you login to Solve360 with
define('USER', '****************');
// REQUIRED Edit with token, Solve360 menu > My Account > API Reference > API Token
define('TOKEN', '*****************');
// Get request data
$requestData = array();
parse_str($_SERVER['QUERY_STRING'], $requestData);
// Configure service gateway object
require 'Solve360Service.php';
$solve360Service = new Solve360Service(USER, TOKEN);
//
// Preparing the contact data
//
$contactFields = array('firstname','lastname','businessemail','businessphonedirect','name','homeaddress','cus tom10641628','custom11746174','custom13346238');
$contactData = array();
// adding not empty fields
foreach ($contactFields as $solve360FieldName => $requestFieldName) {
if ($requestData[$requestFieldName]) {
$contactData[$solve360FieldName] = $requestData[$requestFieldName];
}
}
//
// Saving the contact
//
// If there was business email provided:
// check if the contact already exists by searching for a matching email address.
// if a match is found update the existing contact, otherwise create a new one.
//
if ($contactData['businessemail']) {
$contacts = $solve360Service->searchContacts(array(
'filtermode' => 'byemail',
'filtervalue' => $contactData['businessemail'],
));
}
if (isset($contacts) && (integer)$contacts->count > 0) {
$contactId = (integer)current($contacts->children())->id;
$contactName = (string)current($contacts->children())->name;
$contact = $solve360Service->editContact($contactId, $contactData);
} else {
$contact = $solve360Service->addContact($contactData);
$contactName = (string)$contact->item->name;
$contactId = (integer)$contact->item->id;
}
if (isset($contact->errors)) {
// Email the error
mail(
USER,
'Error while adding contact to Solve360',
'Error: ' . $contact->errors->asXml()
);
die ('System error');
} else {
// Email the result
mail(
USER,
'Contact posted to Solve360',
'Contact "' . $contactName . '" https://secure.solve360.com/contact/' . $contactId . ' was posted to Solve360'
);
}
In their example, they use a contact form with method="get" instead of method="post", however in the user interface of Contact Form 7, I believe the method is fixed to "post". Could this be the problem?
Or is there a different issue? Note that an empty contact is created at the moment. I can provide field mapping details and Forms 3rd party integration does allow hooks, if that helps in anyway.
Any help would be really appreciated! Thanks.
I discovered that the action method (POST) of the 3rd party plugin was not matching the expected action method (GET) of the Solve360 script. Therefore, I had to remove the following from the script:
// Get request data
$requestData = array();
parse_str($_SERVER['QUERY_STRING'], $requestData);
and change the following piece of code from
// adding not empty fields
foreach ($contactFields as $solve360FieldName => $requestFieldName) {
if ($requestData[$requestFieldName]) {
$contactData[$solve360FieldName] = $requestData[$requestFieldName];
}
}
to
// adding not empty fields
foreach ($contactFields as $solve360FieldName => $requestFieldName) {
if ($_POST[$requestFieldName]) {
$contactData[$solve360FieldName] = $_POST[$requestFieldName];
}
}
Hope this will help someone who is connecting Contact Form 7 to their Solve360 database.
I have built a contact form using CakePHP on my site. The controller logic is as follows:
<?php
class ContactController extends AppController
{
var $helpers = array ('Html','Form');
var $components = array ('Email','RequestHandler');
var $name = 'Contact';
function beforeFilter()
{
parent::beforeFilter();
$this->Auth->allow(array('*'));
}
function index()
{
if ($this->RequestHandler->isPost())
{
$this->Contact->set($this->data);
if ($this->Contact->validates())
{
$this->Email->to = '###';
$this->Email->subject = 'Contact message from ' . $this->data['Contact']['name'];
$this->Email->from = $this->data['Contact']['email'];
$this->Email->send($this->data['Contact']['message']);
$this->render('success');
}
}
}
}
?>
What I want to do is when a user submits the form is show another view file such as success.ctp but what happens is even though they have a new view they could refresh the page and send the data again and again. How do I stop this...
Can anyone help? Thanks
after you process their form data, redirect them to the same contact page (to avoid the refresh problem)
If you're not aware, you can setFlash to show a success message. But if you want to customize it the way you want, you can write a variable to Session to signal the view.
function index()
{
if ($this->RequestHandler->isPost())
{
$this->Contact->set($this->data);
if ($this->Contact->validates())
{
$this->Email->to = '###';
$this->Email->subject = 'Contact message from ' . $this->data['Contact']['name'];
$this->Email->from = $this->data['Contact']['email'];
$this->Email->send($this->data['Contact']['message']);
$this->Session->write('Contact.postmessage', true);
$this->redirect(array('action'=>'index'));
}
}
$this->Session->delete('Contact.postmessage');
}
And in the view:
if($this->Session->check('Contact.postmessage'){
// write out content of success.ctp
}else{
// write out form
}
You could try an approach of finding the count with the posted email less than five minutes ago or pop a Session flash message like 'Sorry you can only post every x minutes'
$this->Contact->find('count',array(
'conditions'=>array(
'email'=>$this->data['Contact'] ['email'],
'created <'=>date("Y-m-d H:i:s", strtotime('-5 minutes)));
To avoid sending message more then one time - place session value and check which view to render according to if that session value is placed.
e.g. on your email sending code add $this->Session->write('sent',1);
and when rendering: if ($this->Session->check('sent')) $this->render('common_view'); else $this->render('alternate_view');
And please make sure that page is redirected after email sending to itself via $this->redirect().
i have written validation class. now, is it ok to extend a form class from the validation class? or even extending the validation class from the request class?
i'm just not sure how to implement the registration process for a new user in a mvc. totally confuse.
Edit: i have found this zend tut here:
// application/controllers/GuestbookController.php
class GuestbookController extends Zend_Controller_Action
{
// snipping indexAction()...
public function signAction()
{
$request = $this->getRequest();
$form = new Application_Form_Guestbook();
if ($this->getRequest()->isPost()) {
if ($form->isValid($request->getPost())) {
$comment = new Application_Model_Guestbook($form->getValues());
$mapper = new Application_Model_GuestbookMapper();
$mapper->save($comment);
return $this->_helper->redirector('index');
}
}
$this->view->form = $form;
}
}
but i do not understand how in case of wrong inputs you can go back to the form page now with filled input fields
$this->view->form = $form;
this just sets a value but does not redirect to registration.php. so how do i get to registration.php after this
if ($form->isValid($request->getPost())) {
$comment = new Application_Model_Guestbook($form->getValues());
$mapper = new Application_Model_GuestbookMapper();
$mapper->save($comment);
return $this->_helper->redirector('index');
}
else {
// ... do redirect to registration.php and fill input fields with set $_POST
}
I wouldn't extend it. They have different "scopes" (one inputs data, and the other validates data)...
I would suggest either Dependency Injection if you want to force validation, or simply the option of setting a validation object if necessary. I've done both before.
I cant seem to figure out how to create a flexible sidebar containing and login form (Zend_Form) and various module/controller specific links.
The most common solution seems to be using:
echo $this->action('login', 'authentication', 'default');
But apperently this isnt the 'best' way? I've read that this apprently triggers a dispatchloop and thereby take a performance hit?
I've thought about sing a View_Helper for the sidebar:
class Zend_View_Helper_Sidebar extends Zend_View_Helper_Abstract
{
public function sidebar()
{
$sidebar = $this->view->placeholder('sidebar');
$sidebar->setPrefix('<div class="sidebar-element">')
->setSeparator('</div><div class="sidebar-element">')
->setPostfix('</div>');
$sidebar->append(new Form_Login);
$sidebar->append(new Model_Category->getList());
return $sidebar
}
}
In my Form_Login i have action set to /auth/login which contains the following code:
public function loginAction()
{
$request = $this->getRequest();
if($request->isPost()) {
$form = new Form_Login();
$data = $request->getPost();
if($form->isValid($data)) {
$username = $form->getValue('username');
$password = $form->getValue('password');
$users = new Model_DbTable_Users();
$authenticated = $users->login($username, $password);
if($authenticated) {
//Succes - show identity instead of loginForm
} else {
$this->view->loginForm = $form;
$this->render('/index');
}
}
}
}
If I provide the wrong username/password it renders indexAction which is currently empty. This is fine. It also renders my sidebar containing the loginForm as needed, but the form is empty (The user input is not displayed. Neither is no message that the form failed to validate).
The username-field in the form should display the input that the user provided before submitting. And a error message should be displayed.
Any help as to why this is not happing, is very much appriciated.
You are doing your form validation in a loginAction and you said you are currently posting to index action, is that a typo?
Besides that, you are creating two copies of the Form_Login. Once, in the action and once in view helper. If you validate on one instance in the action, you need to display that same instance of the form in the view helper. You could either move all the validation logic into the view helper or you could share the instance between the view helper and the action. I'm going to suggest the latter.
Check in your view helper if a form already exists in the registry. If it does, just use that instance. Otherwise you can create a new instance. Here's a rough example of what I mean:
class Zend_View_Helper_Sidebar extends Zend_View_Helper_Abstract
{
public function sidebar()
{
$sidebar = $this->view->placeholder('sidebar');
$sidebar->setPrefix('<div class="sidebar-element">')
->setSeparator('</div><div class="sidebar-element">')
->setPostfix('</div>');
if(Zend_Registry::isReigistered('loginForm')) {
$loginForm = Zend_Registry::get('loginForm');
} else {
$loginForm = new Form_Login();
}
$sidebar->append($loginForm);
$sidebar->append(new Model_Category->getList());
return $sidebar
}
}
public function loginAction()
{
$form = new Form_Login();
Zend_Registry::set('loginForm', $form);
$request = $this->getRequest();
if($request->isPost()) {
$data = $request->getPost();
if($form->isValid($data)) {
$username = $form->getValue('username');
$password = $form->getValue('password');
$users = new Model_DbTable_Users();
$authenticated = $users->login($username, $password);
if($authenticated) {
//Succes - show identity instead of loginForm
} else {
$this->view->loginForm = $form;
$this->render('/index');
}
}
}
}
Edit:
No, there is no self checking if an instance of a form already exists. You must do this yourself.
I'm pretty sure the suggested way is to use a view helper. As you said in your question, using the action view helper causes another dispatch loop which is bad for performance. I don't know what the verdict is on whether all logic should be kept in the view helper or not.