Creating a Contact Form in CakePHP 1.2

Most contact forms take a name and feedback from a user and mail it off to the administrator but don't store any information in the database. This tutorial will show how to use CakePHP's models, even when no table is being used.

CakePHP is great in that you set up a database table, define an empty class file for the Model and suddenly you're halfway there. The Form helper can automatically display error messages and outputs the proper input type depending on the field data type.

However, what do you do when you don't have a database table, as is the case with our contact form? We look to the model property, _schema. Normally this is automatically populated by CakePHP when it figures out what the database says. With no database table, you have to define the schema by hand.

Here's an example schema for our contact form:

class Contact extends AppModel {
    var $useTable = false;
    var $_schema = array(
        'name'		=>array('type'=>'string', 'length'=>100), 
        'email'		=>array('type'=>'string', 'length'=>255), 
        'details'	=>array('type'=>'text')
    );
}

As you can see, we've told the model not to use a table by setting useTable to false. Then, we define the schema for the table. In this case, we're going to ask the site visitor to fill out name, email, and contact details.

With the schema defined, we can also specify some validation rules to go along with that:

var $validate = array(
    'name' => array(
        'rule'=>array('minLength', 1), 
        'message'=>'Name is required' ),
    'email' => array(
        'rule'=>'email', 
        'message'=>'Must be a valid email address' ),
    'details' => array(
        'rule'=>array('minLength', 1), 
        'message'=>'Feedback is required' )
);

With the model now set up and ready to go, setting up the view is a piece of cake:

<?php 
    echo $form->create('Contact');
    echo $form->inputs();
    echo $form->end('Send');
?>

Then, all we have to do is set up our controller to do something.

function add() {
    if ($this->RequestHandler->isPost()) {
        $this->Contact->set($this->data);
        if ($this->Contact->validates()) {
            //send email using the Email component
            $this->Email->to = 'admin@example.com';  
            $this->Email->subject = 'Contact message from ' . $this->data['Contact']['name'];  
            $this->Email->from = $this->data['Contact']['email'];  
   
            $this->Email->send($this->data['Contact']['details']);
        }
    }
}

And that's it! The process for the contact form, validating and sending emails hasn't changed. All we had to do was define the schema to be able to take advantage of our model validation.

Published July 24, 2008
Categorized as CakePHP
Short URL: http://snook.ca/s/902

Conversation

53 Comments · RSS feed
Cristian said on July 25, 2008

Great tutorial!

Walker Hamilton said on July 25, 2008
$form->inputs();

Does this mean that, as long as one is not doing anything "weird" in a form, you don't need to put every field?!?

When did this happen?

Jonathan Snook said on July 25, 2008

@Walker: hehe, you like that, eh? Somewhere in the 1.2 stuff, it got in there. Pure genius (and I used it to show off just how easy the form helper can be).

Walker Hamilton said on July 25, 2008

Pure.

Walker Hamilton said on July 25, 2008

Completely Pure.

Brendon Kozlowski said on July 25, 2008

Darn...I really need to re-bake my applications between each release to see the new changes. Thanks for that information on the form helper's new method, Jonathan! I've seen $_schema in my debug output too, but didn't realize what it was exactly, so that part's also very useful. Thanks a bunch!

Gian said on July 25, 2008

Man, you really rock JSnook. I was never aware of that $form->inputs() function. Great tutorial dude. CakePHP is freakin awesome.

byBartus said on July 25, 2008

Hi,

many thanks about this tip, but you forgot to 'echo' the '$form->' in the views.

T+

Jonathan Snook said on July 25, 2008

@byBartus: good catch. fixed.

Pablo Impallari said on July 26, 2008

Hi Jonathan:
You should try Kohana as well. (www.kohanaphp.com)
Today I was doing a contact form too. And was surprisingly easy

In the controller:


$form=new Forge(url::current(), '', 'POST');
$form->input('name')->label('Your Name')->rules('required');
$form->input('email')->label('Your Email')->rules('valid_email');
$form->textarea('messaje')->label('Your Messaje')->rules('required');
$form->submit('submit');

if ( $form->validate() ) {
    // Do Stuff
} else {
    $this->myFrom = $form;
}

In the View:


<h2>Contact Us</h2>
<?php echo $myfrom ?>

I just love it. Its like jQuery

Juarez P. A. Filho said on July 26, 2008

WoW... It's great, I've been working with cake about 6 months and it's very great, but I don't migrate to 1.2 yet.
@Jonathan do you think CakePHP 1.2 is stable sufficiently to use on a serious web project?
Thanks for share.

Brett Wilton said on July 26, 2008

Do you additionally use the Security component to secure the form or do you find the $this->RequestHandler->isPost() is sufficient ? I guess this question also applies in general to other forms as well e.g. Comments, was just curious.
Thanks for the insight into $from->inputs() hadn't seen that yet, is there a nice way when using that method to also customize the labels ?

primeminister said on July 27, 2008

Nice! Thnx Jonathan!

Jonathan Snook said on July 27, 2008

@Pablo: The syntax for Kohana seems really interesting. It's nice to see other frameworks taking the simplicity approach.

@Juarez: Yes, CakePHP 1.2 is definitely stable. They're onto release candidates with a final version likely out within the month.

@Brett Wilton: No, I don't use the Security component. I'm okay with just ensuring that it's a post request.

Alex Cohaniuc said on July 28, 2008

This is so cool, CakePHP rocks!!

Andreas Dantz said on July 28, 2008

This is great. I just needed something quite similar for my app. Thanks alot!

Brett Wilton said on July 29, 2008

Just in case I've missed some other auto magic features in 1.2, is there an auto magic means of setting custom input labels when using the $from->inputs() method ?

Skip Hire said on July 31, 2008

I have been aware of Cake for some time, but this is the first time I've seen any code examples. I have been thinking about doing something similar in PHP for some time where all the details for the form are stored in an XML file, which configures a controlling class. All you need to do is write and ref. the XML and its done.

Orhan said on August 03, 2008

Is the textarea field named 'feedback' or 'details'? Seems like you are using both.

Eric said on August 03, 2008

I've been reading up on different frameworks for a while and recently noticed what seems to be a misunderstanding/misuse of the View portion of the MVC pattern.

@Pablo: It seems wrong to me that the Controller, with respect to the MVC pattern, should have the ability to define the content and structure of the View. To me, this violates the separation of logic layers by which the View should define itself.

I found the same inherent problem in the Zend Framework. Perhaps i'm missing something, but i'm surprised to see it in Big-Name frameworks like Zend. Does anyone want to explain their perception of this?

Eric said on August 03, 2008

@Snook: It also seems wrong to me that the CakePHP Model is *assumed* to be database driven, and therefore you have to specifically tell it *not* to connect to a database table.

Do you have any comments on this behavior?

Jonathan Snook said on August 03, 2008

@Brett Wilton: If you declare the field names, you can declare custom labels with them. Like, $form->inputs(array('name'=>array('label'=>'My name')))

@Orhan: you're correct. A typo in the middle there which I've now corrected. Thanks!

@Eric (1): Zend in particular is a framework that can be used for MVC but wasn't built specifically as an MVC framework. I haven't looked too closely but last time I remember, their CakePHP or Code Igniter equivalent was pretty loose.

@Eric (2): CakePHP has a similar "convention over configuration" mindset as Ruby on Rails and the fact is, it's built for the 80% of apps which are database driven. It's about solving the common goal, not about some strict adherence to a methodology. Of all the apps I've built with CakePHP, 98% of the controllers have needed a database table association. I like CakePHP for automating that.

Eric said on August 03, 2008

Thanks for the response,

@Snook (1): You're right, I went to find something which stated the Zend Framework was designed specifically as an MVC framework, but couldn't find it. I still think its strange that they implement the MVC pattern (in the tutorial i'm referring to here: http://akrabat.com/zend-framework-tutorial/) and seemingly devalue the concept of independent logic layers.

@Snook (2): I definitely appreciate the "convention over configuration" philosophy - I employ it constantly. I question why the CakePHP Model doesn't skip loading table data until a database request is made. For example:

var $useTable = false;
var $_schema = array(
    'name' => array('type'=>'string', 'length'=>100),
    'email' => array('type'=>'string', 'length'=>255),
    'details' => array('type'=>'text')
);

... looks like "configuration" to me. This could easily be avoided in the spirit of "convention":

class Contact extends AppModel {
    var $validate = array(
        'name' => array(
            'rule'=>array('minLength', 1),
            'message'=>'Name is required' ),
        'email' => array(
            'rule'=>'email',
            'message'=>'Must be a valid email address' ),
        'details' => array(
            'rule'=>array('minLength', 1),
            'message'=>'Feedback is required' )
    );
};

... should be the only code needed to accomplish this, and even that could be simplified.

I guess this is relatively minor in retrospect, but it's part of what keeps me from using CakePHP and Zend frameworks. Ruby On Rails seems to have more correctly adopted this philosophy, though, I'm not a Ruby programmer. CakePHP seems like the best of the available PHP frameworks anyway.

Adam Duro said on August 05, 2008

Wow Snook! Clean. I remember chating with you on IRC a month or so ago about this subject. You really discovered a slick solution. Kudos to you and anyone else who helped come up with this solution.

Mark said on August 08, 2008

This is a great tutorial and clean solutions. I certainly like the convention over configuration philosophy in CakePHP. One of the most powerful features is the relational mapping provided by the model, and CakePHP is furthermore awesome for automating.

Alexei A. Korolev said on August 09, 2008

Btw, why CakePHP? Can you explain your chooice? Thanks.

Jonathan Snook said on August 09, 2008

Alexei: I chose CakePHP because I felt it was the PHP framework that best took the "convention over configuration" approach. I've been very happy with the features and feel that it ultimately saves me time in developing applications (and more so than any other framework I've tried so far).

Mike said on August 12, 2008

Thanks for tutorial - great job :) On my own I would spend a few hours above it

Sreejith said on August 13, 2008

I'm trying out CakePHP. Thanks for the nice tutorial !

Adriaan said on August 16, 2008

Smart! Didn't knew about the $_schema property! Simple and useful!

Maybe a bit offtopic. But I always save contactform data also in the database. Because I had some clients complaining about lost emals and such. Also it's so damn easy in Cake :)

Tom said on August 21, 2008

thanks for the tuto,

I am a beginner and have a error :
Call to a member function isPost() on a non-object

What's wrong ? I did a copy/past of your code

Jonathan Snook said on August 21, 2008

Tom: the example uses the RequestHandler component to check if it's a post request. If you don't use the RequestHandler, you can check for the existence of $this->data or there's a server variable (if I remember correctly) that you can use to check that it's a POST request. $_SERVER['REQUEST_METHOD'] I think.

Tom said on August 21, 2008

Thank you, but can you just tell me how can I use RequestHandler. I checked the file on the directory cake » libs » controller » components and I have it.

Tom said on August 21, 2008

OK, I put a declaration of the components and It seems to be OK. But I don't receive the email when I check on my development environnement, is it normal ?

Tom said on August 21, 2008

I tried in a production mode, and it's work, OK

zahid said on September 15, 2008

great article

Riman said on September 17, 2008

Thanks for this tutorial :) It's work

Peter said on September 21, 2008

Thanks for the tute, Jonathan.

I'm new to PHP and Cake. I'm wondering what the code you provided would look like if it were modified to allow the user to select (from a select list) who the e-mail is sent to, rather than just 'admin@example.com'. Eg: john@example.com, barry@example.com, danny@example.com, etc.

And what if the user wanted to choose a subject title from a list, like 'Sales', 'Orders', 'Support', 'Website', etc?

Lesti said on October 02, 2008

Great tutorial - it was very helpful for me :)

MIke said on October 06, 2008

Thanks for this, I just looking for thath

François said on October 20, 2008

Hi,
thx for sharing that :).

I've one question about this piece of code :


$form->inputs();

Do you know any solution to display something else than the "name field" as a "<label>", witch is sometime not very friendly ?

Best regards

François

sorry for my english :)

Jonathan Snook said on October 20, 2008

You can specify the fields manually and then declare the label on any specific field.

$form->inputs(array(
   'name'  => array('label'=>'Enter your name'),
   'email',
   'comment'
));
Otte said on November 12, 2008

It's all work :) Thanks

Mozeten said on December 05, 2008

I just looking for this. Thanks.

Göte said on December 15, 2008

I was googling around looking for a howto about cake's forms, and I found your great site.

I am taking a look at cake 1.2, and I run into problems with the validation of form data. I took advantage of the console application to bake some views, a model, and a controller based on an existing MySQL-database. I don't yet have a deep understanding of cake, and would happily welcome hints and pointers which direction I should go.

All fields are considered invalid and the validation fails whatever data I use to fill in the form. I verified that the correct data from the form are assigned to the controller object's data array with Configure::write('debug', 3); The view contains code to evaluate the validation: pr($this->validationErrors);

PHP version: 5.1.6
OS: Linux

CakePHP version:
$Id: VERSION.txt 7692 2008-10-02 05:06:48Z nate $

libs/model/model.php version:
$Id: model.php 7690 2008-10-02 04:56:53Z nate $

Jonathan Snook said on December 15, 2008

It's hard to say exactly what you might be running into without seeing the code (maybe paste it to a bin). Are you trying to validate() the code? If so, remember to set the data to the model like I've done in the article ($this->Contact->set($this->data)).

Göte said on December 16, 2008

I am trying to post data from a form to a database. However, whatever data I post, I get redirected back to the form, where a label "This field cannot be left blank" is attached to all fields. For instance if I fill the alphanumeric field "last_name" with "Jones" (without qoutes), I will get the error message: "This field cannot be left blank". Futhermore, $this->validationErrors contains all fields and the same error message.

The view is just a simple form like:

echo $form->create('Lead');
echo $form->input('last_name');
echo $form->input('modified_user_id');
... quite a few more fields here ...
echo $form->end('Submit');

There are also a few form fields added with pure html code. These fields are not supposed to be posted to the database, neither be validated with the standard cake validation feature.

In the model, there is nothing but "name" and the validation array.

The model's validation array looks like:

var $validate = array(
'last_name' => array('alphanumeric'),
'modified_user_id' => array('alphanumeric'),
--- quite a few more fields here ---
)

The controller's add function:

function add() {
if (!empty($this->data)) {
if ($this->RequestHandler->isPost()) {
$this->Lead->create();
$this->Lead->set($this->data);
if ($this->Lead->save($this->data)) {
$this->Session->setFlash(__('The Lead has been saved', true));
$this->redirect(array('action'=>'index'));
} else {
$this->Session->setFlash(__('The Lead could not be saved. Please, try again.', true));
}
}
}
}

I also tried the following code in the controller: if ($this->Lead->validates()) with the same result.

Jonathan Snook said on December 17, 2008

Nothing instantly jumps out at me. Sorry I can't be of more help. Try posting to the CakePHP Google Group if you haven't already.

satheesh said on January 12, 2009

how to create of confirmation form(with back button) in cakephp for a contact form with database,

Joseph P. Buarao said on February 10, 2011

Wow.. great tutorial, big help on my project. keep up the good work man..

Thanks..

Joseph P. Buarao
Web Developer
Azure Web Design

Hello! caegdde interesting caegdde site! said on February 16, 2011

Hello! caegdde interesting caegdde site!

Very nice site! said on February 16, 2011

Very nice site!

Tuan said on April 06, 2011

Hello, I am sorry, I have acode:
echo $form->create('Message', array(
'url' => array(
'controller' => 'contacts',
'action' => 'view',
$contact['Contact']['alias'],
),
));
But I can't understand, can you help me, thank you very much.

Sorry, comments are closed for this post. If you have any further questions or comments, feel free to send them to me directly.