Lit FORM will show you the steps to write data to a database table. We will base this project on Lit LIST, and add a Contact Form, similar to the form built in The FORM.
You can open a completed version of the project in your browser here.
If you want to download completed versions of the PHP scripts for this project, you can find them here.
This project has a few steps to convert The FORM to CodeIgniter:
Much of the work done for Lit LIST can be used directly here, so we will build on what has already been built.
Project Set-up. Set up a directory in the htdocs folder to hold your project. The recommended name is n413_litform.
Copy all the files from your Lit LIST project into your project folder. Or you can use the completed set of Lit LIST files from here. Either set should contain a complete set of the CodeIgniter files.
Open config/config.php and update the "base_url" value with the new project path. It should be:
$config['base_url'] = 'http://localhost:8888/n413_litform/'; //or for XAMPP: //$config['base_url'] = 'http://localhost/n413_litform/';
If you downloaded a new set of files, be sure the config/database.php files have been updated with the correct paths and database connection credentials, port numbers, etc. (See Lit LIST.)
We will write to the same database table ("form_responses") used in The FORM project. If you don't already have that table set up, see the intructions here. Or you can download the SQL script to create the table here.
The Controller. We will add two methods to the Litjams controller. The first will create the Contact Form page. The second will handle AJAX and the form submission. Build the first method and the View before proceeding to the AJAX setup.
Name the first method "litform()". The only data it needs is the page title and the the page name ($this_page), then we can load the Views. It looks like this:(controllers/Litjams.php) ... public function litform(){ $data["page_title"] = "AMP JAMS | Lit FORM"; $data["this_page"] = "contact"; $this->load->view('templates/head', $data); $this->load->view('litform', $data); } ...
The View. Before starting with the form, update the nav-bar in views/templates/head.php. Locate the links and look for the "contact" item. Update the URL as shown below:
(views/templates/head.php) ... <li id="contact_item" class="nav-item"> <a id="contact_link" class="nav-link" href="<?=site_url()?>/litjams/litform">Contact</a> </li> ...
Create a new file in your views directory named litform.php. This file will be very similar to form.php in The SITE, so open that file and copy the contents into litform.php. Also open login.php from The PASSWORD. We will borrow the "submit" handler from that script in a later step.
Starting with the code copied from form.php:
(views/litform.php) <div class="container-fluid"> <div id="headline" class="row mt-5"> <div class="col-12 text-center"> <h2>Lit JAMS Contact Form</h2> </div> <!-- /col-12 --> </div> <!-- /row --> <form id="contact_form" method="POST" action=""> <div class="row mt-5"> <div class="col-4"></div> <!-- spacer --> <div id="form-container" class="col-4"> Name: <input type="text" id="name" name="name" class="form-control" value="" placeholder="Enter Name" required/><br/> E-mail: <input type="email" id="email" name="email" class="form-control" value="" placeholder="Enter E-mail" required/><br/> Comment: <textarea id="comment" name="comment" class="form-control" value="" placeholder="Add your comment here:"></textarea><br/> <button type="submit" id="submit" class="btn btn-primary float-right">Submit</button> </div> <!-- /#form-container --> </div> <!-- /.row --> </form> </body> <script> $(document).ready(function(){ document.title = page_title; navbar_update(this_page); }); //document.ready </script> </html>
Test this now to see that everything looks right. The form won't submit any data, but you should be able to see it in the browser, and the nav-bar should let you move around.
The next step is to add the "submit" handler to post (send) the form data back to the Controller. Open login.php from The PASSWORD project, and locate the "submit" handler. It will be inside the $(document).ready() function. Copy it into the same place in the new script. Make the following modifications:
The finished version of litform.php should look like this:
(views/litform.php) <div class="container-fluid"> <div id="headline" class="row mt-5"> <div class="col-12 text-center"> <h2>Lit JAMS Contact Form</h2> </div> <!-- /col-12 --> </div> <!-- /row --> <form id="contact_form" method="POST" action=""> <div class="row mt-5"> <div class="col-4"></div> <!-- spacer --> <div id="form-container" class="col-4"> Name: <input type="text" id="name" name="name" class="form-control" value="" placeholder="Enter Name" required/><br/> E-mail: <input type="email" id="email" name="email" class="form-control" value="" placeholder="Enter E-mail" required/><br/> Comment: <textarea id="comment" name="comment" class="form-control" value="" placeholder="Add your comment here:"></textarea><br/> <button type="submit" id="submit" class="btn btn-primary float-right">Submit</button> </div> <!-- /#form-container --> </div> <!-- /.row --> </form> </body> <script> $(document).ready(function(){ document.title = page_title; navbar_update(this_page); $("#contact_form").submit(function(event){ event.preventDefault(); $.post("<?=site_url()?>/litjams/contact_post", $("#contact_form").serialize(), function(data){ //handle messages here if(data.status){ $("#form-container").html(data.success); }else{ $("#form-container").html(data.failed); } }, "json" ); //post }); //submit }); //document.ready </script> </html>
The $.post() function will make an AJAX call with the form data to the controller method named "contact_post". The controller will then return the JSON object that has the user messages to display.
AJAX. The Contact Form is set up to send an AJAX call to the controller, so we need to put an MVC process in place to handle the data. A controller method will receive the data and pass it to a new model, which will insert the data into a data table. Before we can use the new model, we will need to load it in the controller. Begin with the last step.
Open the controllers/Litjams.php file and look at the constructor function. Copy/paste the line that loads litlist_model, and make a line that loads litform_model. It should look like this:
(controllers/Litjams.php) ... public function __construct() { parent::__construct(); $this->load->model('litlist_model'); $this->load->model('litform_model'); } ...
The controller method will be called "contact_post()" and looks like this:
(controllers/Litjams.php) ... public function contact_post(){ $contact = $this->input->post(); $messages = $this->litform_model->contact_post($contact); echo json_encode($messages); } ...
There are interesting things happening with this simple script. CodeIgniter has its own methods for accessing the $_POST array. Using $this->input->post() will get an associative array of the $_POST contents, freshly sanitized for you. Also, you can include a key in the argument for post() and get just that value (sanitized, of course).
The form data from the $_POST array is now contained in $contact, and it will be passed to the model. We will design the model to insert the data in the database and return a message object, which will come back to $messages. The messages will be encoded as JSON and sent back to the browser.
Let's write the model.
Litform_model. Make a copy of Litlist_model.php and save it in your models directory with the name Litform_model.php. Capitalization matters here. The first character must be upper case.
Make the following modifications:
(models/Litform_model.php) <?php defined('BASEPATH') OR exit('No direct script access allowed'); class Litform_model extends CI_Model { public function __construct() { parent::__construct(); //this causes the database library to be autoloaded //loading of any other models would happen here } public function contact_post($contact){ $contact["name"] = $this->db->escape_str($contact["name"]); $contact["comment"] = $this->db->escape_str($contact["comment"]); $messages = array(); $messages["status"] = $this->db->insert('form_responses', $contact); if($messages["status"]){ $messages["success"] = '<p>Thank you for submitting your comment. <br/> <span class="mt-5 float-right"><i>The Web Site Team</i></span></p>'; }else{ $messages["failed"] = '<p>Sorry, but something went wrong. Please try again later. <br/> <span class="mt-5 float-right"><i>The Web Site Team</i></span></p>'; } return $messages; } }
There are a couple of new CodeIgniter functions here. The first is db->escape_str(). CodeIgniter has alerady sanitized the data when it arrived as a POST, but there can still be problems with special characters in the string. Apostrophe's in names can be problematic, for example. So escaping strings is still a good idea. When we used mysqli_real_escape_string() for this earlier, we were required to use the database connection, but that is buried somewhere in the db object now. CodeIgniter provides a few ways to escape strings through the db object. When you use these, be careful, because some of the methods will wrap your data in single quotes, which will break your code if you don't notice. You can find the documentation here. This method will do what you expect, so we will simply process the name and comment.
The core function of the Model method is to insert a record in the database, which happens with the CodeIgniter db->insert() function. This function abstracts the SQL INSERT query. Just supply the table name and an array with keys that have the same names as the table columns, and you are good. No tedious lists of column names or values to type.
The insert operation returns true/false to indicate success. Depending on the success status, the correct message is composed and returned to the controller.
The controller then passes the message along to the browser (in JSON format), and the callback function redraws the screen with the message, as you see here.
The MVC Design Pattern Take a moment to trace the flow of data through the various parts of the project to firm up your understanding of MVC.
Remember, MVC is a design pattern. Where things are done is somewhat arbitrary, but we look for the best way to follow the design. You could certainly do a database insert from the Controller. Or have the browser call the Model directly. But we establish the role of each part of the design so that we know where to look for certain functions. And --importantly-- others know where to look, as well. Once you learn the system, it becomes a second-nature process, and frees you to think about the logical flow of the task.
The Lit FORM is done! You have built another MVC Full Stack application. This time with AJAX!
The next step is to add the pull everything together into a SITE.
Completed Project. You can open a completed version of the project in your browser here.
Here are completed versions of the scripts used for this project:
(controllers/Litjams.php)<?php defined('BASEPATH') OR exit('No direct script access allowed'); class Litjams extends CI_Controller { public function __construct() { parent::__construct(); $this->load->model('litlist_model'); } public function index(){ $data["page_title"] = "AMP JAMS | Lit LIST"; $data["this_page"] = "litlist"; $data["records"] = $this->litlist_model->get_litlist_items(); $this->load->view('templates/head', $data); $this->load->view('litlist', $data); } public function litlist(){ $data["page_title"] = "AMP JAMS | Lit LIST"; $data["this_page"] = "litlist"; $data["records"] = $this->litlist_model->get_litlist_items(); $this->load->view('templates/head', $data); $this->load->view('litlist', $data); } public function detail($id){ $detail = $this->litlist_model->get_litlist_detail($id); $data["page_title"] = "AMP JAMS | ".$detail["item"]; $data["this_page"] = "litlist"; $data["row"] = $detail; $this->load->view('templates/head', $data); $this->load->view('detail', $data); } public function litform(){ $data["page_title"] = "AMP JAMS | Lit FORM"; $data["this_page"] = "contact"; $this->load->view('templates/head', $data); $this->load->view('litform', $data); } public function contact_post(){ $contact = $this->input->post(); $messages = $this->litform_model->contact_post($contact); echo json_encode($messages); } }
(models/Litform_model.php)<?php defined('BASEPATH') OR exit('No direct script access allowed'); class Litform_model extends CI_Model { public function __construct() { parent::__construct(); //this causes the database library to be autoloaded //loading of any other models would happen here } public function contact_post($contact){ $contact["name"] = $this->db->escape_str($contact["name"]); $contact["comment"] = $this->db->escape_str($contact["comment"]); $messages = array(); $messages["status"] = $this->db->insert('form_responses', $contact); if($messages["status"]){ $messages["success"] = '<p>Thank you for submitting your comment. <br/> <span class="mt-5 float-right"><i>The Web Site Team</i></span></p>'; }else{ $messages["failed"] = '<p>Sorry, but something went wrong. Please try again later. <br/> <span class="mt-5 float-right"><i>The Web Site Team</i></span></p>'; } return $messages; } }
(views/templates/head.php)<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes"> <title><?=$page_title?></title> <link href="<?=base_url()?>assets/css/bootstrap.min.css" rel="stylesheet"> <script src="<?=base_url()?>assets/js/jquery-3.4.1.min.js" type="application/javascript"></script> <script src="<?=base_url()?>assets/js/bootstrap.min.js" type="application/javascript"></script> <script src="<?=base_url()?>assets/js/bootstrap.min.js.map" type="application/javascript"></script> <script> var this_page = "<?=$this_page?>"; var page_title = "<?=$page_title?>"; function navbar_update(this_page){ $("#"+this_page+"_item").addClass('active'); $("#"+this_page+"_link").append(' <span class="sr-only">(current)</span>'); } </script> </head> <body> <nav class="navbar navbar-expand-lg navbar-dark" style="background-color:#ee4323;"> <a class="navbar-brand" href="<?=site_url()?>">AMP JAM LIT</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarNav"> <ul class="navbar-nav"> <li id="home_item" class="nav-item"> <a id="home_link" class="nav-link" href="<?=site_url()?>">Home</a> </li> <li id="litlist_item" class="nav-item"> <a id="litlist_link" class="nav-link" href="<?=site_url()?>/litjams/litlist">The List</a> </li> <li id="contact_item" class="nav-item"> <a id="contact_link" class="nav-link" href="<?=site_url()?>/litjams/litform">Contact</a> </li> </ul> </div> </nav>
(views/litform.php)<div class="container-fluid"> <div id="headline" class="row mt-5"> <div class="col-12 text-center"> <h2>Lit JAMS Contact Form</h2> </div> <!-- /col-12 --> </div> <!-- /row --> <form id="contact_form" method="POST" action=""> <div class="row mt-5"> <div class="col-4"></div> <!-- spacer --> <div id="form-container" class="col-4"> Name: <input type="text" id="name" name="name" class="form-control" value="" placeholder="Enter Name" required/><br/> E-mail: <input type="email" id="email" name="email" class="form-control" value="" placeholder="Enter E-mail" required/><br/> Comment: <textarea id="comment" name="comment" class="form-control" value="" placeholder="Add your comment here:"></textarea><br/> <button type="submit" id="submit" class="btn btn-primary float-right">Submit</button> </div> <!-- /#form-container --> </div> <!-- /.row --> </form> </body> <script> $(document).ready(function(){ document.title = page_title; navbar_update(this_page); $("#contact_form").submit(function(event){ event.preventDefault(); $.post("<?=site_url()?>/litjams/contact_post", $("#contact_form").serialize(), function(data){ //handle messages here if(data.status){ $("#form-container").html(data.success); }else{ $("#form-container").html(data.failed); } }, "json" ); //post }); //submit }); //document.ready </script> </html>
If you want to download completed versions of the PHP scripts and image files, you can find them here.
Move ahead to the Lit SITE when you are ready to go!