CakePHP Contact Form – Quick and Dirty

I must say, this was a major hurdle for me when I first started out with CakePHP. If you’re working with some data from a database, then it’s all Model-View-Controller magic. Your forms are automatic: $form->input() is pretty much all you need. Why is this? That’s because all the information about the fields (names, sizes, types, etc.) come straight from the database.

You’re Out On Your Own

The problem right now is that, you’re all on your own. You need to describe your data on your own. So, on with it:

Here’s your model code:

class Contact extends AppModel {
	var $name = 'Contact';
	var $useTable = false;  // Not using the database, of course.
	
	// All the fancy validation you could ever want.
	var $validate = array(
	    'name' => array(
	        'rule' => '/.+/',
			'allowEmpty' => false,
	        'required' => true,
	    ),
		'subject' => array(
	        'rule' => array('minLength', 5),
			'message' => 'Subject must be 5 characters long'
	    ),
		'email' => array(
	        'rule' => 'email',
			'message' => 'Please enter a valid email address'
	    ),
	);

	// This is where the magic happens		   
	function schema() {
		return array (
			'name' => array('type' => 'string', 'length' => 60),
			'email' => array('type' => 'string', 'length' => 60),
			'message' => array('type' => 'text', 'length' => 2000),
			'subject' => array('type' => 'string', 'length' => 100),
		);
	}
}

What The User Sees

I think the model’s the hardest part. The view is ridiculous:

	echo $form->create(null, array('action' => 'index'));
	echo $form->input('name');
	echo $form->input('email');
	echo $form->input('subject');
	echo $form->input('message');
	echo $form->submit();
	echo $form->end(); 

I know; you’re disappointed right? Sorry.

How Do We Control All This?

So, here’s your controller. I was going to leave that up to you, but it’s so simple that I can’t help it:

class ContactController extends AppController
{
	var $name = 'Contact';
	var $uses = 'Contact';
	var $helpers = array('Html', 'Form', 'Javascript');
	var $components = array('Email', 'Session');
	function index(){
		if(isset($this->data)) {
			$this->Contact->create($this->data);
			// There is no save(), so we need to validate manually.
			if($this->Contact->validates()){
				$this->Email->to = Configure::read('CONTACT_EMAIL');
				$this->Email->replyTo = $this->data['Contact']['email'];
				$this->Email->from = $this->data['Contact']['name'].' <'.$this->data['Contact']['email'].'>';
				$this->Email->subject = 'Contact Form: '.$this->data['Contact']['subject'];
				//$this->Email->delivery = 'debug';
				if ($this->Email->send($this->data['Contact']['message'])) {
					$this->Session->setFlash('Thank you for contacting us');
					//$this->redirect('/');
				} else {
					$this->Session->setFlash('Mail Not Sent');
				}
				$this->redirect(array('action' => 'index'));
			} else {
				$this->Session->setFlash('Please Correct Errors');
				//$this->redirect('/contacts');
			}
		}
	}
}

After I got halfway through this, I remembered that Snook had written something very similar, sorry J.

There’s one subtle difference that I’ve noticed, that I need to point out.
var $_schema as apposed to function schema(). In the original CakePHP code, one of the major actions of Model::function() is to return var Model::$_shema. So, Tom-ay-to/Tom-a-to; it really doesn’t matter.

Comments

  1. Hi – thanks for posting this up. It’s interesting to see the differences between yours and Snook’s examples.

    I was wondering how secure this was (thinking spam) – and for anybody else who is wondering – I just checked the email component in the API http://api.cakephp.org/email_8php-source.html and there everything is sent through a handy function called __strip() that removes unwanted things like bcc: and to: from the subject and message of the emails sent.

    Cheers.

    John’s last blog post..CSS – note to self cursor: and nobr equivalent

    • From what I can see, he uses the var $_schema member variable, where as I override the schema() function. No real diff, since one of the things the function does is return _schema.

      Also, he uses $this->RequestHandler->isPost() to check for a POST to the server (a lil’ added security. It will prevent the more primitive methods of spam).

      Last thing:
      Snook uses: $this->Contact->set($this->data);
      as apposed to $this->Contact->create($this->data);

      I used the create() because that’s what I’ve been using for regular data related functions in controllers. Create calls set() so, everything still gets done.

      For spam though, I think you’re going to need something more robust. There are some implimentations of Akismet out there. so you may want to check these out. Off the top of my head, I don’t think it would be terribly hard to implement one of those “math-type” spam protections. I personally, hate CAPTCHA, so I don’t subject my visitors to that.

  2. Hi Kevin

    I know what you mean about CAPTCHAs – lots of them I can’t get right first time and I’ve got good eyesite – accessibility aside they just add an extra (unnecessary) element to the page.

    I find that hidden form fields work really well against automated spam – i.e. if the a field that shouldn’t be completed (because it’s normally hidden) gets completed the message can just be dumped or sent to an alternate email just for spam. When you add things like lists of banned words to test against and a check based on the number of links in a message and you can soon build something pretty comprehensive.

    As somebody who uses wordpress I have to agree with you about Askimet – its is brilliant, have not tried to hook it up to Cake yet – although I do plan to.

    John

    John’s last blog post..CSS – note to self cursor: and nobr equivalent

  3. Hi ,

    I was trying to figure it out to how to save a form data to two tables .. like username and password to one and the other details to another one …. is there something in cake to do that

  4. Hi,
    thanks for your post I have been very useful.

    rubendelafuente’s last blog post..Cliente subversion para visual studio 2008

  5. You are a legend, I’ve had so many issues getting these annoying contact forms to work.

    Cheers 😀

  6. Hi, Anoop, you can use $this->Model->saveAll($data);

    http://karaoke.com.vn <= I use CakePHP,too.

  7. glen hughes says:

    I am attempting to use this but am consistently getting a “mail not sent” error. When I add debug($this->data);exit; after the $this->Session->setFlash(‘Mail Not Sent’); I get

    Array
    (
    [Contact] => Array
    (
    [name] => test
    [email] => test@test.com
    [subject] => testing
    [message] => Test email message
    )

    )
    So it appears that all fields are working properly. Is there a method to debug this and figure out why its not being sent?

    Any thoughts would be much appreciated.

    • Hi glen, maybe you should change the
      $this->Email->to = ‘To yourname ‘;
      or change the cake’s default email (test@test.com) to any mail you want
      and dont forget to enable php_openssl extension before send your mail.