beta it republik » Articles

Articles

Untitled Document
Wednesday, 14 May 2008 | Article

Creating Web Applications Faster with CakePHP

Web frameworks – like Ruby on Rails – are rapidly gaining popularity. Sites like 43Things.com and Basecamp are using these kinds of frameworks in large production environments, and they report significant productivity gains. However, many programmers prefer to use languages they are familiar with rather than learning a new language, such as Python or Ruby. Additionally, webhost support for some languages are spotty, so some developers would prefer a framework written in PHP. An excellent PHP web framework is CakePHP. It’s a rapid development framework, similar to Rails, but lacks those disadvantages.


Introduction
CakePHP has a number of valuable features. For example, it has an Model View Controller (MVC) architecture. This refers to the three elements of the application – the model that represents the data, the view that represents the view of your data, and the controller that represents the backend logic of your application. Although the separation may seem artificial at first, it can significantly increase productivity and ease of use over monolithic architectures. It also allows for easy code reuse.

An additional part of the application are ‘helpers’, which are libraries that help you create your application. Helpers include support for forms, which can populate dropdowns from a table, automatically scaffold models, and more. You can also use AJAX helpers for a variety of Web 2.0 features – autocompletion, dynamic lists, script.aculo.us effects, and more. Like Rails, it includes a number of formatting helpers, as well – timeAgoInWords returns a string like ‘five days ago’, autoLink automatically links e-mails and URLs in a string, highlight highlights a given phrase in a string using HTML tags, and so forth.

In this article, we’ll examine the task of creating a simple CakePHP application – one to manage a to-do list. You’ll need a LAMP (Linux, Apache, MySQL, PHP) server to run these examples.

Getting Started with CakePHP
Before developing our application, you’ll need to get the latest CakePHP release from CakeForge:

http://cakeforge.org/frs/?group_id=23

Download the release in the format of your choice – tar.bz2, tar.gz or .zip. Unzip into a new directory. Under this directory will be two more directories – app and cake. The app directory will contain the source code for your application. The cake directory contains the source for the framework itself. You can, if you so desire, have multiple app directories sharing the same cake framework. (That requires some fairly simple editing of .htaccess files, however.)

First, to start our application, let’s create a simple MySQL database and then configure CakePHP to use it. Here’s our example schema:

CREATE TABLE todo_items (id INT(11) NOT NULL AUTO_INCREMENT
PRIMARY KEY, description TEXT NOT NULL, completed TINYINT NOT
NULL);


You’ll need to create a MySQL database and execute that SQL. If you don’t know your MySQL database name, user name and password, you should be able to get it from your system administrator. You’ll need all three in the next step.

Next, we’ll need to configure CakePHP install to use the MySQL database that we’ve just created. Copy the contents of the file database.php.default to a file name database.php in the app. config directory, and change the “var $default=..” line to have your new MySQL database name, username and password.

At this point, if your view your application, you should use a test page. It should display ‘Your database configuration file is present’ and ‘Cake is able to connect to the database’. If not, double check your connection parameters and ensure you created the database properly.

Creating a Controller
Once you can connect to the database, the next step is to start adding code to the skeleton. Create three directories in the app directory – ‘controllers’, ‘models’, and ‘views’. These will contain the three different parts of our MVC structure.

First, let’s create a simple controller. This will respond to the user’s actions, but not represent data or display information. Create a file todo_items_controller.php in the app\controllers directory, and fill it with the code from Listing1. You’ll notice that this creates a class with four methods, the longest of which has six lines of codes. Each method handles a different user action. If you need more possible actions, add more methods. The ‘index’ method is the default method called for the controller.

The first method, index, is the action that controls the view of our to-do list. It’s pretty simple – it calls the set method to pass a list of todo items to the view, naming the data todos. The data is retrieved by calling the findAll method of the Todo model, which we haven’t created yet. Note that the todo model will automatically be a given number of methods, including find, which will find one record by its ID number of other criteria. FindAll, which are using here, finds all records matching a given criteria. Since we didn’t specify any criteria, it finds all the records.

Next, we see the add method. This action is only slightly more complex, with just five lines of code. It tries to save the data passed to it – params[‘data’] – by calling the todo model’s save method, and, if successful, save it to the database. There isn’t any error checking in the example, but if necessary, you could report to the user the reason for failure by adding an else clause to the if block.

The delete method is much the same as the add method, with two variations. It is passed an $id from the web browser, and it calls the todo model’s del method instead of the save method.

The del method, unsurprisingly, deletes a record.

The toggle_complete method is the most complicated. It takes an id from the web browser, reads the record from the database, toggles the records completed field, and reports to the user whether it was toggled on or toggled off.

You may wonder how the controller called by the web browser. A facility called routes controls the mapping of URLs to controllers and actions. By default, http://yoururl.com/yourcontroller/youraction/yourparams will call the ‘youraction’ method of ‘yourcontroller’ and pass it ‘yourparams’. You can also set a default controller and action, so that yoururl.com will call the controller and action of your choice.

You’ll also notice that after each action, a method called setflash is called, followed by a call to redirect. The setflash routine sets a ‘flash message’ – a short message displayed to the user. We could have a separate view for each action, but since our actions require no response from the user, we can simply redirect back to the list of todo items with a short notification to the user. This reduces the amount of clicks for the user.

Creating a Model
If we run the code as it is now, it won’t work. We need two more parts. Let’s create a model next. Create a file app\models\todo. php and use the code from Listing 2. The listing is pretty simple, since we have a very simple model. You’ll notice that the code does not contain any information about the data definition of the table; it just contains a $name variable. The $name variable specifies the name of the database table. The column names and types are read from the database, so if they change, the model is up to date. This reduces duplication.

You might notice that none of the methods our controller users are defined in this model. This is because they are automatically provided by AppModel, which our model inherits from. If we desire additional model-specific functionality, we can provide that, but we don’t need to reinvent the wheel for every model.

Now, in our example, we don’t have any relationships; we have only one table. In most applications, though, we will have complex relations between tables. Fortunately, CakePHP has a rich set of tools for handling relationships. We can model relationships like belongs_to, has_many, and more. This will let us access children and parents of a record easily without writing a single line of SQL.

Remember, the model only manages our data. It doesn’t react to a user’s actions, nor does it display data. It does, however, manage the data itself and its relationship to other data.

If we run our application now, it till won’t work. We need one more piece – the view.

Listing 1
<?php
class TodosController extends AppController
{
var $name = ‘Todos’;
function index()
{
$this->set(‘todos’,$this->Todo->findAll());
}
function add()
{
if($this->Todo->save($this->params[‘data’]))
{
$this->Session->setFlash(“You’ve added a new todo item.”);
$this->redirect(‘/todos’);
}
}
function delete($id)
{
if($this->Todo->del($id)){
$this->Session->setFlash(“You’ve deleted a todo item.”);
$this->redirect(‘/todos’);
}
}
function toggle_complete($id)
{
$this->Todo->id = $id;
$record=->Todo->read();
$record[‘Todo’][‘completed’]=!$record[‘Todo’][‘completed’];
$verbed= $record[‘Todo’][‘completed’] ? ‘completed’ :
‘uncompleted’;
if($this->Todo->save($record)){
$this->Session->setFlash(“You’ve $verbed a todo item.”);
$this->redirect(‘/todos’);
 }
 }
}
?>


Listing 2
<?php
class Todo extends AppModel
{
var $name = ‘Todo’;
}
?>



Listing 3
<h1>My Todo List</h1>
<ol>
<?php foreach($todos as $todo){ ?>
<li <?if($todo[‘Todo’][‘completed’]){echo ‘class=completed’;}?>
><?=$todo[‘Todo’][‘description’]?> <a href=”/todos/delete/
<?=$todo[‘Todo’][‘id’]?>”>[kill]</a> <a href=”/todos/toggle_complete/
<?=$todo[‘Todo’][‘id’]?>”>[done]</a></li>
<? }
?>
</ol>
</p>
<h2>Add</h2>
<?=$html->formTag(‘/todos/add’)?>
<?=$html->input(‘Todo/description’)?>
<?=$html->submit(‘Add’)?>
</form>



Creating a View
The view actually displays the data to a viewer. This abstraction is extremely useful; we can edit the display code without editing the backend logic or the database code. We can create multiple view types for the same data without duplication; we could have an option to toggle between RSS, Atom, and HTML outputs for the same data.

Create a ‘todos’ directory under the app/view directory, and place an index.thtml file in it. Use the code from Listing 3 for the app/view/todos/index.thtml file.

Note that while this application only has one view, most applications have many. CakePHP has separate directories for each controller for that reason; the files inside each controller are named after the actions.

At this point, you can run the application, but before we do, we’ll take one final step to improve the look of our application.

Creating a Layout
While our view has only the HTML relating to our action; it has no html, head, or body tags. In fact, if you run the application, you’ll notice a CakePHP logo, menuing, and more – none of which are in our view. This is the result of a ‘layout’. The layout is code that the output of our views is placed into. This lets us have a structure for our pages that isn’t repeated in every view; it only has the code that’s unique to that view. The default layout contains menuing and other structures we don’t want, so let’s get rid of it.

Create a layouts directory under your app/view directory. Create a app/view/layouts/default.thtml file using the code from Listing 4. This will override the default CakePHP layout, although it will still use the default CakePHP Cascading Style Sheet.

Notice that the $content_for_layout contains the actual content of the page, which is taken from the output of each view. Also note the code that checks if a flash message is present, then displays it if it is. If you’d like, you can reformat your flash messages here.

Running the Application
At this point, your application should be working. If you get unknown class errors, check for typos in the file names and class names. Model names are singular, but controller and view names are plural, and that’s an easy mistake to make. CakePHP automatically pluralizes your names, so if you’re using an obscure word or term, you might need to instruct CakePHP on how to pluralize it. You shouldn’t have a problem with this application, however.


Listing 4
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//
EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>
<title>x : <?php echo $title_for_layout;?></title>
<link rel=”shortcut icon” href=”favicon.ico” type=”image/x-icon” />
<?php echo $html->css(‘cake.basic’);?>
<?php echo $html->css(‘cake.forms’);?>
</head>
<style>
li.completed {
color:#6e6e6e;
text-decoration: line-through;
}
</style>
<body>
<div id=”container”>
<div id=”content”>
<?php if ($this->controller->Session->check(‘Message.flash’))
{
$this->controller->Session->flash();
}
echo $content_for_layout;
?>
</div>
<div id=”footer”>

<a href=”http://www.cakephp.org/” target=”_new”>
<?php echo $html->image(‘cake.power.png’,
array(‘alt’=>”CakePHP : Rapid Development Framework”,
‘border’=>”0”));?>
</a>
</div>
</div>
</body>
</html>



If you navigate to the directory you’ll still get a test page. However, if you navigate to the yourname.com/yourpath/todos directory, you’ll get your application. You should be able to add ‘to do’ items, delete them, and check them off – all with just a few lines of code. However, we want the root of our application to go to the todos controller automatically. How can we do that?

Edit the app/config/routes.rb file. Find the following line:

$Route->connect(‘/’, array(‘controller’ => ‘pages’, ‘action’ => ‘display’, ‘home’));

Change it to the following:

$Route->connect(‘/’, array(‘controller’ => ‘todos’, ‘action’ => ‘index’));

You should be able to access your to-do list from the root of your application now. This file, app/config/routes.rb, controls the mapping of URLs to controllers and actions, and the passing of data from the browser to the controller. This allows the controllers to be simpler, since they don’t need to handle the requests directly. Not all routes are in this file; if you access a controller by name, as we did earlier in this article, you don’t need a route for it. Also note that this file only connects controllers and actions; if you have
a file in the app/webroot directory, you can access it by name.

Conclusion
As you can see from the example, CakePHP can make some web development tasks much easier. Granted, production applications will typically be much more complicated, but CakePHP nonetheless makes PHP web application development much more enjoyable, productive, and elegant. Of course, no framework can entirely solve software development problems. It can, however, make it easier for you to concentrate on your ‘core problem’ – the aspect of your application which has not been solved before. You spend less time solving problems repetitively, and more time producing valuable software.



About the Author

David Berube is the proprietor of Fast Custom Software. He develops database driven web sites and applications for a wide variety of clients.


   Related Links
http://cakephp.org
http://en.wikipedia.org/wiki/Cakephp
http://cakephp.org/screencasts
http://www.actionscript.org/tutorials/intermediate/PHP_Remoting/index.shtml


Comment

Name:

Comment:

Captcha Verification !
captcha_image