PHP frameworks, Part 2: Building the sample application

Creating Blahg with Zend, symfony, and CakePHP

This "PHP frameworks" series takes a look at three widely used PHP frameworks — Zend, symfony, and CakePHP — examining their similarities and differences while building and extending a sample application in each of the three frameworks. Part 1 laid out the scope for the series and got the prerequisites out of the way. Here in Part 2, you will build the sample application in each of the three frameworks.


Duane O'Brien, PHP developer, Freelance

Photograph of Duane O'BrienDuane O'Brien has been a technological Swiss Army knife since the Oregon Trail was text only. His favorite color is sushi. He has never been to the moon.

16 October 2007

Also available in Russian Japanese Vietnamese

In Part 1 of this series, we laid out the scope for the series and got the prerequisites out of the way. Now, you will build the sample application in each of the three frameworks. In future articles, you will extend the application, look at exceptions to the rule, play with Ajax, integrate external tasks, and much more.

This article walks you through creating the sample application, Blahg, in each of the three frameworks. You'll do it all from scratch, learning the basics of developing a simple application in the Zend Framework, symfony, and CakePHP.

You should have already gone through Part 1, which covers installation and prerequisites for each framework. If you haven't, you should do so now.

It is assumed that you already know PHP, application design, and how to work in a database. It's not necessary to have used a framework before, but you should certainly be ready to jump in with both feet.

Building Blahg in the Zend Framework

To start, create the directories /column/htdocs/zend and /column/protected/zend. These will hold Web-accessible files and application files that should not be Web-accessible, respectively. In /column/htdocs/zend, create an .htaccess file with the following lines:

RewriteEngine on
RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php

Each framework has its own particular needs when it comes to directory structures. For the Zend Framework, you need to create the directories /column/protected/zend/controllers, /column/protected/zend/models, and /column/protected/zend/views to hold your controllers, models, and views. Additionally, you need to create the directory /column/protected/zend/views/scripts; and for each controller, you need to create a directory to hold some views. For example, you know Blahg is going to need some views for the post controller, so you need to create the directory /column/protected/zend/views/scripts/post to hold this view.

You've got your directories in place. Time to build your model.

Building your Zend posts table and model

In Part 1, you created the posts table you will be using. If you skipped that, go back and do it now. The model for this table will be very simple. It should be called Posts.php, and you should create it in /column/protected/zend/models/. Posts.php will extend the Zend_Db_Table class, and you'll be using most the inherited methods from that class. If you open up the Posts.php file in the code archive, you will see very little actual code.

Building your Zend Front controller and PostController

For your Front controller, you will create an index.php file in /column/htdocs/zend. This file is the only part of your application exposed to the outside world. The rest of your application is accessed through this file. The Front controller needs to do several things: load the Zend Loader (to avoid having to include every library by hand), set up your connection to the database, and dispatch requests to the appropriate application controllers; in this case, that's only the PostController.

As you might have guessed, you will be creating the file PostController.php in the /column/protected/zend/controllers directory. The PostController you need to create is fairly simple.

For starters, you need to include the posts model you created earlier. And you should probably create an init method, which will be called when the PostController object is created. In the init method, you can set up the view and model objects you will use in the subsequent actions. You can probably surmise that you need three actions: indexAction, readAction, and writeAction (the xxxxxAction naming convention for actions is part of doing things in the Zend Framework).

The indexAction is simple: get all the posts and assign them to the view. The readAction isn't much more complicated: get the post ID from the request, retrieve the post, and assign the post to the view. The writeAction isn't all that complicated, either. If a request has been posted, strip any tags and save the data to the database. Otherwise, render the form.

Take a look at the PostController in the code archive for details on the syntax and structure. Now that your controllers are done, you can move on to your views.

Building your Zend post views

You're almost done. Blahg requires a number of views, and you create them all in the /column/protected/zend/views/scripts/posts directory. You'll need at least three views (index.php, read.php, and write.php), though the code in the code archive makes use of four. The views are simple files: The index and read views simply output the data assigned to them, applying minimal formatting, while the write view displays a form to be used when posting to Blahg. Take a look at the views in the code download for details.

If you've created your model, controllers, and views properly (or installed the code properly), you should be able to try out the Zend Framework version of Blahg by going to http://localhost/zend/post (assuming you installed everything locally).

You are probably itching to play around with Blahg. Don't get carried away yet. You still have two more frameworks to go.

Building Blahg in symfony

Building Blahg in symfony is somewhat different. For starters, you need to initialize the project using symfony's command-line utility.

Running the symfony init commands

Switch to a terminal window and create the directory /column/protected/sf_column using a using a command line. This will be the protected directory to hold all the symfony code for the column. All of your symfony command-line work must be done from this directory. Change into the sf_column directory and execute the following command: php /column/protected/symfony/data/bin/symfony init-project sf_column.

This command will create a slew of directories and files in /column/protected/sf_column that are required for a symfony project. Next, you'll need to init the Blahg application. In the sf_column directory, execute the following command: php /column/protected/symfony/data/bin/symfony init-app blahg.

This command will create some more directories and files, largely in /column/protected/sf_column/apps. But before you can use most of this, you need to rearrange some of the files. Remember, your installation is exposing very few files to the outside world. The application structure built by the symfony init scripts don't know what your directory structure is. Fortunately, you can change that by adding the following lines to the end of /column/protected/sf_column/apps/config/config.php.

Listing 1. Changing the application structure for the symfony init scripts
$sf_root_dir = sfConfig::get('sf_root_dir'); 
'sf_web_dir_name' => $sf_web_dir_name = 'symfony', 
'sf_web_dir' => DIRECTORY_SEPARATOR.'column'.DIRECTORY_SEPARATOR.'htdocs'.
			  sfConfig::get('sf_upload_dir_name'), ));

In essence, these lines are telling symfony where to find your web directory.

Now that you had added these lines, you should move the contents of /column/protected/sf_column/web to /column/htdocs/symfony (create this directory if you haven't already). And last but not least, you need to modify /column/htdocs/symfony/index.php so it knows what the real root directory is for your project. Replace the existing define for SF_ROOT_DIR with the following line: define('SF_ROOT_DIR', '/column/protected/sf_column');.

You're almost done. Now you just need to init the post module for Blahg. This means running another command at the command line: php /column/protected/symfony/data/bin/symfony init-app blahg. This command, like the others, builds up some files and directories, this time in /column/protected/sf_column/apps/blahg/modules/post.

Now that you have symfony up and running, it's time to cobble together Blahg.

NOTE: symfony provides functionality to auto-generate code to provide the Create, Read, Update, and Delete (CRUD) functionality based on your database. While this can help you get the basics of an application together quickly, using it in this context wouldn't give you much of a feel for how a symfony application fits together. For the purpose of this article, you'll build your application by hand.

Generating the model

Again, the posts table you will use was created in Part 1.

Because symfony uses Propel to provide Object Relational Mapping, you need to generate the model with the symfony command-line utility. This requires that you describe your database scheme and provide some database information first.

NOTE: Technically, providing the database information first isn't necessary. symfony builds the model based on the schema, and the command-line utility can even be used to generate SQL scripts to create a database based on the schema definition. We'll try that in a subsequent article.

For the database and schema definition files, symfony uses Yet Another Markup Language (YAML). YAML isn't too complicated, but if you've never used it before, it can seem confusing. At this stage, the main thing to know about YAML is that whitespace is significant. You use two spaces for an indent, and you never use tabs.

Now you will edit your database.yml and schema.yml files. They live in /column/protected/sf_column/config. And your schema.yml file needs to be edited to describe the posts table. Edit your schema file to contain the following information.

Listing 2. Editing the schema.yml file
  posts :
    _attributes: { phpName: Post }
    title:       varchar(255)
    text:        longvarchar
    modified: timestamp

NOTE: Since you probably copied and pasted that code, go back and make sure that each indent is two spaces, and that no tabs were used. For example, the modified line should have four spaces in front of it (two for the indent to posts and two for the indent to modified).

Your database.yml file should be edited to contain your specific database parameters. It might look something like Listing 3.

Listing 3. The database.yml file
    class:          sfPropelDatabase
      phptype:      mysql
      hostspec:     localhost
      database:     symfony
      username:     frameworks
      password:     fwpw

That shouldn't have been too hard. Now that your schema and database configurations are complete, you can generate your model. Return to the command line you were using earlier, and in /column/protected/sf_column, execute the following commands:

php /column/protected/symfony/data/bin/symfony propel-build-model
php /column/protected/symfony/data/bin/symfony clear-cache

Each command will output a large amount of data, but the important end result is the creation of the Post.php and PostPeer.php files in /column/protected/sf_column/lib/model — these are your models. If you open them up, you'll see there's not much there. They just extend the base model classes.

NOTE: Whenever you rebuild your models, it is important to run the clear-cache command as above. Also note that if you installed symfony using the PHP Extension and Application Repository (PEAR), you can just run symfony propel-build-model without calling PHP first or providing the full path to the binary. Not everyone has the option of using PEAR their environment, which is why we described the alternate installation instructions in Part 1, and the corresponding model-generation instructions above.

That's it! Your model for this round is done. A lot more could be said about models, but it's time to move on to your controller.

Building out the controller

You don't need to write a Front Controller like you did in Zend, as symfony has already provided this for you.

Your post controller will actually be called actions.class.php and will live in /column/protected/sf_column/apps/blahg/modules/post/actions. This controller will handle all the actions for the post module. Like before, you need three actions, but the names are different: executeIndex, executeRead, and executeWrite (the executeXxxxxx is the naming convention used by symfony for actions and must be followed).

The executeIndex action is simple: Retrieve the posts and make them available to the view. The executeRead action is also simple: Take in the post ID, retrieve the post, and make the post data available to the view. The executeWrite action takes in the title and text from the request and saves the data to the database, returning the ID of the post that was saved.

Take a look at the post/actions/actions.class.php in the code download for details on the syntax and structure. Now that your controller is done, you can move on to your views.

Building out the views

Your post views will live in /column/protected/sf_column/apps/blahg/modules/post/templates. You need three views: indexSuccess.php, readSuccess.php, and writeSuccess.php (the xxxxSuccess.php naming convention is part of symfony and must be followed).

These views won't render into a complete HTML document like the Zend views did. symfony provides a default layout template (in apps/blahg/templates/layout.php) that provides the basic head andfoot of the HTML page. All you need to provide is the middle of the view — content specific to the action. For example, indexSuccess.php just needs to loop through and format the provided array of posts, readSuccess.php just formats the post content, and writeSuccess.php displays the form or outputs your success message if a post has been submitted.

If you've created or installed everything properly, you should be able to try out the symfony version of Blahg by going to http://localhost/symfony/post (assuming you installed everything locally).

So you've seen how Blahg fits together in the Zend Framework and symfony. Two down, one to go.

Building Blahg in CakePHP

Before you can start building Blahg in CakePHP, you need to move some of the files around. Then you'll set up your database connection and let Bake take over.

Setting up the file structure

Take a look at the /column/protected/cakephp/ directory. You should see four directories: application (the directory that will hold your application), cake (the directory containing Cake's core files), docs (readme docs), and vendors (where you put third-party libraries you may use). There are also two files: index.php and .htaccess. These two files only come into play when you install CakePHP in the webroot. This is generally a bad idea, as it makes all of your application files accessible to anyone using a Web browser.

The preferred method of installation is to make /column/protected/cakephp/app/webroot the root directory for your Web server. Equally viable (and preferred for this series) would be to copy the contents of /column/protected/cakephp/app/webroot into a Web-accessible directory (in this case, /column/htdocs/cakephp). Go ahead and do this now.

Once you've copied the files over, you need to open up /column/protected/cakephp/app/webroot/index.php and make a couple edits: The existing definitions for ROOT and APP_DIR need to be updated. They should look something like Listing 4.

Listing 4. Definitions of ROOT and APP_DIR
    if (!defined('ROOT')) {
         define('ROOT', DS . 'column' . DS . 'protected' . DS . 'cakephp');
    if (!defined('APP_DIR')) {
         define('APP_DIR', 'app');

That's enough to get you going, but you may as well enter in your database information and update core.php with a unique value for CAKE_SESSION_STRING.

In /column/protected/cakephp/app/config/ make a copy of database.php.default called database.php and enter the host, login, password, and database name for your system. Also, in /column/protected/cakephp/app/config/core.php, change the define for CAKE_SESSION_STRING to include a new value, such as define('CAKE_SESSION_STRING', 'He had a Subbuteo player in his hair. I got distracted.');.

You've got the preliminaries out of the way. Time to jump into the cake.

NOTE: Like symfony, CakePHP provides functionality to auto-generate code to provide the CRUD functionality based on your database. CakePHP also provides scaffolding, which provides a similar service without generating any code at all. Both of these features help you get the basics of an application together quickly, but as mentioned, using these features in this context wouldn't give you much of a feel for how to build an application in CakePHP.

Create the table and model

If you don't have a posts table, you skipped that part of Part 1, so go back and do it now. Create a file called post.php in the /column/protected/cakephp/app/models directory. This will contain the class definition for your model. The definition is a simple one: The class is Post and extends AppModel, and you should set the class variable $name to post.

That's really all there is. Your model will be using all inherited methods from AppModel. Now you can move on to your controller.

NOTE: You may have noticed that the table is called posts (plural), while the model name is post (singular). This is an important part of Cake conventions. Models are always singular, and their corresponding tables are always plural.

Building the Cake posts controller

Your posts controller will be simple, like the other controllers you have written today. You will pull in a couple helpers, then define three actions: index, read, and write.

The index action gets a list of posts and makes them available to the view. The read action gets the ID of a post, retrieves the post and makes the post data available to the view. The write action accepts a submission (if there was one) and saves the data to the database.

Take a look at the /column/protected/cakephp/app/controllers/posts_controller.php in the code download for details about the syntax and structure.

Your controller is done. Now you can move on to your final views.

Building the Cake views

You'll need the same three basic views you created for Blahg in the other frameworks. In this case, you'll create the files index.ctp, read.ctp, and write.ctp in the /column/protected/cakephp/app/views/posts directory. These are just templates CakePHP will use, much like the templates you created in symfony. Take a look at these files in the code archive. The views make extensive use of the forms and HTML helpers to output links and form elements, but they should look similar to the other views you created for symfony.

Note that the views do not render to complete HTML files. A default layout is provided by CakePHP. These default layout files are located in /column/protected/cakephp/cake/libs/views/templates/layouts, but you shouldn't modify them. If you want to change the default layout, place a copy of the default.ctp layout file in /column/protected/cakephp/app/views/layouts and modify it according to your needs.

Note: Forms and links in Cake are much easier to maintain when using these helpers, as Cake will make sure your links point to the right places in the application should it be installed or moved to a different directory, and Cake will do a lot of heavy lifting for you if your form element names are formatted properly.

Build the views according to the Blahg's needs, or install the views from the code download. Assuming you've written and installed everything properly, you should be able to try out the CakePHP version of Blahg at http://localhost/cakephp/posts (assuming you've installed locally).


You gotten quite a lot done. You've installed three frameworks, gotten them each up and running, and created a basic application in each framework.

Spend some time playing around with Blahg in each framework, then try your hand at extending Blahg in each framework. Try writing a comments controller that will allow users to post their own replies to each post. Don't get too wrapped up in linking the comments to the posts just yet, though. But if you feel up to it, dive in! In Part 3, you are provided with some code that covers this.


Part 2 sample codeos-php-fwk2.zip11KB



Get products and technologies



developerWorks: Sign in

Required fields are indicated with an asterisk (*).

Need an IBM ID?
Forgot your IBM ID?

Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.


All information submitted is secure.

Dig deeper into Open source on developerWorks

Zone=Open source
ArticleTitle=PHP frameworks, Part 2: Building the sample application