Drupal 7 Module Development Part 6 - Form API and Database inserts

By shane
Wed, 2012-10-03 13:42
11 comments
Daily Dose of Drupal Episode #21

Share with Others

This episode works off the the previous episode to create a custom Drupal 7 form using the Drupal Form API, and then looks at how to submit data from the Drupal form into a Drupal database table.

In this episode you will learn:

  • How to use hook_menu, hook_permission, and drupal_get_form to create a custom Drupal form page
  • How to create a custom Drupal 7 form using the Drupal Form API
  • How to add a validation function to the Drupal 7 form
  • How to add a submit function the Drupal 7 form
  • How to insert form data into a database table using the Drupal 7 Database API

Welcome to another Daily Dose of Drupal, this is Shane and this is brought to you by codekarate.com. Today we’re working on Episode Number 21 and we are continuing what we started last time with a module that we called formexample and what we did last time is we created a Database Table in our module called formexample and this time we’re going to create a Form Page that we will then be able to use to submit or insert entries into that Database Table.

So the first thing that we’re going to do is we’re going to make sure we have .info created as we set up last time, the install file created as we worked through in the last episode and we have an empty module file and I’m going to go ahead and just drop in the code that I previously written or I have previously written for this example and walk through it with you … I’ll show you where I got this and how I came about with these snippets of code because it gets a little bit lengthy.

So the first; we’re going to implement a new Permission using hook_permission and if you follow the Daily Dose of Drupal before you would have seen examples like this and we’re just implementing hook_permission which of course you can find on api.drupal.org, you can grab the example code down below and replace Hook with the name of module which is formexample or creating a new Permission called Submit Form Example and this permission is going to be use to allow individuals to actually submit our form.

The next step is to implement hook_menu because we’re going to create a page that you can access this form on and in this we of course change Hook to formexample, we create an items array and then we populate it with one Menu Item. In this case the URL is going to be form-example, the title of my example is going to be My Example Form, the type is a Menu Normal Item, we just want it to be a traditional menu, Access Arguments; we’re going to make sure it matches our permission up above which is Submit Form Example, just grab from up here, the page callback, since this is going to be a form, it’s going to be drupal_get_form which is just a Drupal function, you can look it up on api.drupal.org and learn what it does but it accepts an array.

The first parameter needs to be the name of the form; in this case the form is going to be called form_example_form. And so we pass that in an array as I mentioned as the page arguments, and of course at the bottom we return the items. We could of course define multiple Menu Items and we’ll do that next time but in this case we just have one.

The next step is to actually create our form; so we start by creating the form definition and it’s just my … add a comment, it says My Example Form and it matches the Form Example Form from the argument right here and it has two parameters; the first is the $form Variable and the next is a $form_state Variable which is passed by reference and this Form State Variable is very important because that’s where your values are going to be stored after you submit the form. If you look back at our Install File; we have three different fields in our table that we want to populate; we have a my_number Field which we want to say is a field for storing an Integer Number, you have a my_textfield which is a field for storing short strings of Text and then a my_text which is longer Text.

So we will go ahead and create three different form items on our or in our form. The first one; we’re going to create … we’ll just match the name from the Database, this doesn’t have to be sync up with the Database name in anyway, you could call it whatever you want, I gave it a type of a text field, the title is My Number, the size of this field is going to be 10, max length is 10, we want this to be required and this is important and I’ll show you what it does here in a few seconds but you could also change this to false or leave it out and then this field would not require a value, we also add a description here that says “please enter a valid number”.

We’re going to create another Text Field Form Item; this one is called my_textfield and this one is going to be a little bit larger of a text field and it’s going to be use for collecting text, the last item is going to be a Text Area; so we look, we call it my_text the title of My Text Area, it’s a text area type form item, we go ahead and we have some text that’s an interesting text as a description, as you can see this one doesn’t have a description and this one does so you’d really see the difference in there, we also set a default value here, we could leave this out, it’s not required, just add up here we don’t have a default value for either of these but we could if we wanted and we set this one to be required.

The last step is to actually add a Submit button to this; so we go ahead and we say we want to add a Submit button, we want the value of this Submit button which is going to be the text to say Add Item and then the very last thing is you always have to return the form at the end of your Form Function. And now that we have the form we’re going to save this, we’re going to come to our Modules page and enable the Form Example Module. If you already have it enabled from last time you’re going to want to clear your cache so this Form Example page will be available.

Now if we go to Form Example you can see we have our form, you can see there’s a description text under My Number and My Text area but there is not any description text under My Text field and if I try to click this Add Item button you’ll notice I get a message that says these fields are required it highlights them in red and that’s what this required piece does for each of these Form Items.

The next step we’re going to do is add a Validation Handler and the Validation Handler is going to actually validate that our number is an actual number and if you want you can see it’s numeric, it’s a php function, it returns true if the item is a valid number. Keep in mind that this will probably … this numerical except decimal numbers so this isn’t exactly the best validation, you want to make sure it’s actually an integer or cut the decimals off for instance but in this case we’re just going to keep it simple, we just validated that it is some type of number.
Like I said; you’d need to do some more validation here but this is just to show how it would work; the first thing I’m going to do is I’m going to uncomment this debug line and what I’m doing here is I’m just going to print out $form_state and Values. Inside the Form State Variable there’s a values array that contains all the values that you submit.

So I’m going to save this and submit the form, so I’m going to put Test here and filled out the form, I’m going to hit Add Item and you’ll see now I get a blank page with this values array. You can see that inside there there’s a my_number which has My Value that I’ve out in for the My Number Field, My Text Field and My Text.

So those are the three values that I entered and now I can look at those values in my Validation Handler. I also would do the same thing in Submit Handler which is coming up in a second. So as you can see I’m doing If in this Not Sign, this exclamation point is important if it’s not numeric and I’m looking at the $form_state Values and My Number. So I’m looking right here; if this value, which is Test is not numeric then I’m going to use a form_set_error which is Drupal function for setting an error on the form, it starts out with accepting which field I’m setting the error for and in this case I’m setting the error for My Number and what text I want to display. In this case I’m saying you must enter a valid number and then I return false.

If this happens to be numeric I’m going to go ahead and return true and the validation will pass. So let’s save that and let’s go back to My Form and hit Add Item, you can see “you must enter a valid number” shows up, highlights My Field in red and everything is working correctly.

The last thing we’re going to be doing is we are going to add a Submit Handler and my Submit Handler is going to actually insert the data into our database table and you’ll notice that you maybe wondering how I came about that this is going to run as my Validation Handler, you’ll notice that form_example_form is here, if we add an _validate to that function name it’s automatically going to be run as the Validation Handler for this form.

So we didn’t have to do anything special to tell it that this needed to run. Drupal’s Form API looks for that for you and we’ll go ahead and call this function to actually validate. The other thing to keep in mind is these required fields; they run their handle by Drupal’s Form API without having to do anything and they run through some type of validation as well to ensure that there’s actual data entered into those fields. The same works for the submit; you just add _submit onto Form Example Form and Drupal will call this automatically add as a Submit Handler.
So after all validation passes it’s going to call this Submit Function and in here I’m using the Drupal Database API which you may want to look at, I want you to search for Database API on drupal.org and there’s a whole bunch of information here; I simply went in, you could find Insert Queries, you scroll down and it has some examples, this is the Compact Form of an Insert Query but it walks you though all the different types of insert that you can do into a database from within your module.

So this Database API is something you’re going to want to maybe bookmark or at least know how to get to it. Also when you’re creating the form don’t forget the importance of the Form API as I went through in the past. When you want to create a Text Area you just click on Text Area, It’ll bring you down on this pretty massive page and give you some examples on how to actually create a Text Area Form Item and you can do the same with all the text fields or any of these other … let’s scroll to the top, any of these other Form Items or Form Types … Form Item Type I guess that you want to create on your form.

So let’s go back to our Form Submit; we’re going to do a DB Insert, db_insert into our Table Name, in this case if you look on our Install file or Table Name is Form Example. So we’re going to actually insert into the Form Example Table and we need to then add which fields we’re going to insert.

So here; My Number, this has to match up with the Field Name here; My Number, I also need one for My Text Field and My Text, you’ll see I have those three, My Number, My Text Field and My Text and what I’m inserting in is this Form State Values … My Number Value that we checked here in our Validated Handler and when we uncommented this you can do this again if you need to see what values are passed in, you’ll be able to see that Form State Values, My Number, will contain My Number, Form State Values My Text Field will contain any of the text that I enter into that second text field and Form State Values My Text will contain anything I entered into the Text Area.

I then call execute which actually does the Insert at the end of this and this is what they call Chaining and you’re Chaining different things onto this DB Insert Statement. The last thing I do is I called Drupal Set message and I say your Form Entry has been added, I wrap this in the T Function just because that’s the standard is you always wrap any text that you display through the translation function.

So I’m going to save this and I’m going to come back to My Form, enter in a number and I’m going to hit Add Item and you can see it says my Form Entry has been added, My Values are cleared out and if I hop over to my database and I run Select Statement you can see that fe_id of 1has been created, has My Number too and you can see that My Text field and My Text now contain the values that I just entered in.

So that’s really all there is to it, there’s quite a bit a code today, so if you have to pause it and follow along, tomorrow we’re going to be going over creating a page to display the output of this and some type of table format so you can have a page that contains a form to enter the data and a page that contains a listing of that data.
And that’s all for today, as always you can follow me on Twitter @smthomas3 and you can subscribe to the Code Karate Newsletter. Until next time thanks for watching the Daily Dose of Drupal.

Comments

You've got "Database" spelled wrong in the title. (You're missing the "a" between the 'b' and the 's'.)

I am wondering why not use Fields API rather than Forms API to collect information? It can also be used with views. It will scale for lot of logged in users. And that entities are more flexible than static forms. What do you think?

I agree with you that doing an example on the Fields API would be helpful. I started with a simple Forms API example because I thought it was a much simpler starting place. I will look to try to do something on the Fields API in the future.

Thanks for the idea.

Best drupal training on the web, thanks!!

Maybe you can disable cache for the module while in development and not do it manually every time something is changed

function form_example_init() {
$GLOBALS['conf']['cache'] = FALSE;
}

from here

visualparagon.com/content/prevent_drupal_caching_your_modules_output
(Site is not active)

This section on module development with DB access is hugely valuable to me.
As a long-time web/DB programmer in non-drupal, non-php environments, the
ability to use an external database would be an attractive 'fork', and would be
also attractive to many of my colleagues.
Shane, I hope I can ask a couple of questions towards that end:
1)If we were to modify your example to write to an external database,(let's call it 'dba')
would it be better to define 'dba' in settings.php $databases and use db_set_active('dba'); at the beginning of form_example_form_submit(), then
calling db_set_active('default'); prior to the drupal_set_message() call.
OR
2)Would it be preferable to create a separate db definition in form_example.module
and a separate connection object?

FYI: My most current background is python - :) but not django, I hand-rolled my
own framework.
cheers
__keep_up_the_good_work(self)

The ability to use and write to external databases is a 'must' for me if I am to
implement drupal. What follows is what worked for me (excerpted from my submission to the drupal support mailing list).

NOTE! The socket issues with Max OSX (I miss linux!)

I am on mac osx 10.7, and there is a socket issue for drupal 7 on
macs -
see : http://drupal.org/node/752856
title :
"""
Document OS X PDO socket installation issues
"""
Two steps are needed:
1) Define connection information as an entry in settings.php to the
$databases array as follows:

'dba' => array (
'default' => array (
'driver' => 'mysql',
'database' => 'aisbooks',
'host' => 'localhost',
'username' => 'tim',
'password' => 'marion',
// explicitly define the socket file for mysql
'unix_socket' => '/opt/local/var/run/mysql5/mysqld.sock',
),
),

The default setting in php.ini for pdo_mysql.default_socket
is /tmp/mysql.sock - which works for non-drupal PHP, but
I had to create a soft link for the 'unix_socket' value above,
as is explained in the document above.

2) The following code :
// Implementation of hook_form_submit in module :
// form_example.module
function form_example_form_submit($form,&$form_state) {
$result = Database::getConnection('default','dba');
db_set_active('dba');
$fe_id = db_insert('providers')
->fields(array(
'status' => $form_state["values"]["mynumber"],
'name' => $form_state["values"]["mytextfield"],
))->execute();
db_set_active(); // restore the default connection
drupal_set_message('Your form entry has been added.');
}
I hope this add something to the drupal knowledgebase.
I would welcome any further comments as to better form and
process. Cheers ... tim

Thanks for contributing this code. I have not yet had to work with multiple databases on a Drupal 7 site, but this is similar to work I have done on Drupal 6 sites in the past (besides of course a few differences in the database calls).

What you outlined is the process I would follow if I had to do the same thing and the code looks good. Thanks again.

oh please i can't see what you're taping and the php code etc...

You can change the video quality by clicking the little "gear" icon on the bottom of the YouTube video player, and selecting the highest available video quality (should be 720). I hope that helps.

Post new comment