beta it republik » Articles

Articles

Untitled Document
Thursday, 29 May 2008 | Article

Ruby on Rails & CakePHP

This article is an attempt to port a famous Ruby on Rails tutorial to PHP using an emerging PHP MVC framework, CakePHP. CakePHP was inspired by Rails’ philosophy of Rapid Application Development. It implements a lot of the features and concepts that made Ruby on Rails popular in a very short time. Although Ruby’s syntax and way of doing things is known to be much more elegant than other programming languages, there is yet hope for PHP to get more organized and efficient. This tutorial will follow its Rails counterpart step-by-step, covering the essential steps to create a simple, yet fully functional, web application.


Introduction
Design patterns and software architectures have been around a long time, and so have frameworks; think of Microsoft .NET or Java Struts, for example. Programmers today understand the necessity of more order and structure in their applications, and that’s exactly what frameworks claim to offer.

Some may want to be able to reuse certain widgets in their application, and that’s what .NET offers – reusable components each with its own properties and events bound to them, mapping every possible action from the submission of a web form to a mouse click. This is, in a nutshell, what event-driven programming is about.

Another approach focuses on the action itself and the logic of a site rather than on ‘special’ components and widgets – the Model-View-Controller (MVC) architecture. Again, this is nothing new, since the first implementations of the MVC are over thirty years old. However, when Ruby on Rails came out with its unique MVC approach, it smelled fresh and was quickly considered as the key to developing web applications faster and better.

An Overview of the MVC Architecture
The MVC architecture aims to achieve a full separation of business logic from the ‘presentation’ layer and the ‘datasource’ layer by dividing an application into distinct entities named models (datasource), controllers (logic), and views (templates).

Unlike in event-driven programming, an MVC application doesn’t focus on an event occurring in the presentation layer – like a mouse click or movement, for example – but rather on a set number of actions that can be performed by users, not bound to a specific graphical element in the UI. While eventdriven programming is essential to code a desktop application, some developers don’t agree on the necessity of porting it to a web-based environment. This is mainly because web-based applications are less complex and [normally] don’t require a strict bound of an action to a specific element on the page.

That’s why a MVC approach is perhaps the most appropriate foundation for a Rapid Application Development (RAD) framework. It’s a simple, efficient and powerful way to create web applications and also the best way to keep your code clean, organized and maintainable. Understanding how a MVC application works is easy once you are able to focus on the purpose of each one of the three entities:
  • Controllers: controller files can be assimilated – although in a more reductive way – to the sections of a web site or web application. Every action related to a particular section is therefore defined in the appropriate controllers, so that a controller handling, say, the ‘articles’ section will define actions for adding, updating, displaying and modifying articles. A controller can also be imagined as a trait d’union with the presentation and datasource layers. All the rogramming logic of your application will be placed in the controller. So it will be the only entity able to exchange data with your datasource and display it in a view file, for example. Obviously this behavior is crucial for the separation of the three layers and the whole MVC implementation.
  • Models: in a nutshell, models are an active representation of a database table. Active because they are not only able to retrieve the data stored in your datasource, they are also used to store data into it. The advantage of accessing a database table through a model, instead of directly through standard queries, is that you can treat the model (and therefore the database table) exactly like any other class instance, in Object Oriented Programming (OOP) terms.
  • Views: views are nothing more than template files used to present content and data to the end user. There are [normally] several views for every controller and [normally] one for each action. It’s important to point out that no business logic should go inside views. If some operation needs to be performed before displaying content, it should be included in the controller instead.

Ruby vs. PHP
The MVC architecture is widely used in almost every programming language. I’m sure David Heinemeier Hansson had no doubts whatsoever about it, when he first thought about creating Ruby on Rails. On the contrary, he admitted he was undecided at first on the framework’s programming language:

“We had been using PHP for years, and I had tried as hard as I could to arrive at a reusable framework that would make my life easier. And I actually had a very early and at least somewhat decent reminiscence of Rails running in PHP at the time, but I wasn’t happy. […]

So for a short while, I went into apologetic mode and built up all the stable arguments for why to reject change. We wouldn’t be able to find programmers knowing Ruby for 37signals, PHP probably had more and better libraries, and on it went. But that thankfully didn’t last too long because I decided to actually give Ruby a try.

It took one day to say, “I really like this.” It took one week to say, “I’m never going back to PHP again.” And it took one month before my proficiency with Ruby made me run circles around my former programming capabilities in PHP. It was just such an incredibly powerful fit. Ruby fit my brain perfectly. I was having so much more fun and getting so much more done.” (Ruby on Rails: An Interview with David Heinemeier Hansson, by Edd Dumbill, at O’Reilly Network.)


Ruby has indeed proved to be the best choice for Rails, mainly because of its essentiality, its elegant syntax and its solid objectoriented foundations. PHP, on the contrary, may have been a choice geared towards simplicity and accessibility. PHP is undoubtedly more popular and more supported than Ruby (for now at least), but it would have lacked exactly those features that make the Ruby programming language unique.

Ruby’s unique features are also not a good reason to criticize every other attempt to make a similar RAD framework in other programming languages. In fact, six PHP frameworks – CakePHP, Symfony, PHP on Trax, Code Igniter, Biscuit and Pipeline – have embraced the Rails philosophy, or parts of it, to make PHP development easier, faster and more organized. Some of these frameworks admitted to be ports of Ruby on Rails to PHP while others decided to evolve in a similar, yet different way, without trying to mimic Ruby-specific features and functionalities in PHP and including some unique PHP-ish connotations.

CakePHP belongs to the latter group – it started more or less as a Rails port and then moved along its own path. In the next sections, I’ll compare these frameworks by porting a Ruby on Rails tutorial to PHP using Cake, hoping that this will help people to understand how the PHP programming language can benefit from some concepts and features implemented by the Ruby framework.




Scaffolding the Application
In this comparative tutorial we’ll create a basic address book application to manage contacts and phone numbers. To follow the development of the application both in Ruby and CakePHP, set up your development environment and testing server for both frameworks, following the appropriate installation and configuration guidelines. From now on I’ll assume that both Rails and CakePHP are installed and that the skeleton of our Rails application has been generated by issuing the rails Addressbook command. Note that CakePHP doesn’t require this, since it’s shipped with the application skeleton inside the app directory. All the file paths mentioned from now on refer to the directory of your Rails or CakePHP application, AddressBook/app and app, respectively.

The first task is to create a new database and a contacts table. The MySQL database engine will be used in this example, but both frameworks support various popular database solutions. See

Listing 1.Note: created_on and update_on are two ‘magic’ fields automatically updated by Rails when records are added or modified. CakePHP offers the same features, but the fields must be named created and updated, respectively.

The next step is to configure database access for both frameworks, by editing a configuration file, both in Ruby on Rails and in CakePHP. See Listing 2a and Listing 2b. We’ll also need a Model class to represent the table that was created (see Listing 3a and Listing 3b). (Note: the extra line in the CakePHP code is necessary only if you’re planning to support PHP4.)

Listing 1
Creating a MySQL Database and Table
CREATE DATABASE IF NOT EXISTS AddressBook;
USE AddressBook;
CREATE TABLE IF NOT EXISTS contacts (
id smallint(5) unsigned NOT NULL auto_increment,
name varchar(30) NOT NULL default ‘’,
number varchar(30) NOT NULL default ‘’,
first_met datetime NOT NULL,
created_on timestamp(14) NOT NULL,
updated_on timestamp(14) NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY name_key (name)
) TYPE=MyISAM COMMENT=’List of Contacts’;


Listing 2a
Ruby on Rails – Setting up Database Access
[config/database.yml]
development:
adapter: mysql
database: AddressBook
host: localhost
username: myuser
password: mypass


Listing 2b
CakePHP – Setting up Database Access
[config/database.yml]
var $default = array( ‘driver’ => ‘mysql’,
‘connect’ => ‘mysql_connect’,
‘host’ => ‘localhost’,
‘login’ => ‘myuser’,
‘password’ => ‘mypass’,
‘database’ => ‘AddressBook’,
‘prefix’ => ‘’ );


Listing 3a
Ruby on Rails – The Contact Model
[models/contact.rb]
class Contact <ActiveRecord::Base
end


Listing 3b
CakePHP – The Contact Model
[models/contact.rb]
1 <?php
2 class Contact extends AppModel
3 {
4 var $name = ‘Contact’;
5 }
6 ?>


Listing 4a
Ruby on Rails – Scaffolding
[controllers/contact_controller.rb]
1 class ContactController < ApplicationController
2 model :contact
3 scaffold :contact
4 end


Listing 4b
CakePHP – Scaffolding
[controllers/contact_controller.rb]
1 <?php
2 class ContactsController extends AppController
3 {
4 var $name = ‘Contacts’;
5 //var $uses = array(‘Contacts’);
6 var $scaffold;
7 }
8 ?>


Both Ruby on Rails and CakePHP support scaffolding; that is, the creation of a temporary section including a controller, its corresponding model and all the views necessary for basic CRUD operations with just a few lines of code. See Listing 4a and Listing 4b.

Apart from CakePHP’s verbosity, which is unavoidable due to the nature of the PHP language itself, there are some differences worth mentioning in these two snippets. First, note that Rails uses a singular name for the scaffolded controller, to avoid overwriting when the real controller is generated (see later in the article). A similar approach could be taken for CakePHP as well, especially if you plan to use CakePHP’s bake.php script (or rdBaker, a thirdparty online CakePHP code generator) for generating your code.

Further, Rails explicitly specifies the model to use for scaffolding, while CakePHP automatically refers to the Contact model if nothing is specified in the controller. To force CakePHP to use a different model or explicitly register the model in the controller, uncomment the $uses variable definition.

After defining a model and the scaffolded controller both Ruby on Rails and CakePHP are able to present a fully functional standard CRUD interface to create, retrieve, update and delete contacts from the address book. In particular, both frameworks are able to load the appropriate code for the editing views according to the table architecture. For example, if the field is of type varchar, an HTML textbox will be created while a combination of select lists will be used for a datetime field.

Although our scaffolded address book provides all the basic functionalities we need, it’s far from being usable as a real application. Scaffolding should be used at the initial stages and then removed in favour of more complex and specific controllers, models, and views. So the next logical step would be removing the scaffold variable from the controller and implementing all the methods manually. Although the model can remain unchanged in both frameworks at this point, we’ll have to create view files for every action defined in the controller.

Ruby on Rails comes with a handy generator script to generate an explicit scaffold, containing all the things we need. You can run rails script/generate scaffold Contact and a new controller (contacts_controller.rbM) with all CRUD actions explicitly defined and all view files.

On the CakePHP front, the bake.php command line script is not as fast to use, but a third party application named rdBaker is able to do the same in a more PHP-ish fashion by filling a quick online form. Listing 5a and Listing 5b holds the new controller.

Note: some of the names and parts of the methods defined in the Rails controller have been altered to allow for easy comparison with CakePHP’s implementation.

Although Ruby’s syntax is more elegant and concise than PHP’s, CakePHP has taken a step in the right direction by offering something similar in PHP, with most features being faithfully replicated within the limits of the PHP language. The most notable difference between the two is that CakePHP needs to register the variables in the views using the $this->set() method.

Some Rails developers accidentally reading this article may now start thinking on the lines of, ‘Ruby on Rails’ syntax and way of doing things is clearly more elegant and superior to CakePHP’s, so why bothering learning this PHP framework? Just switch to Ruby on Rails and abandon all copycats!’

I have heard this statement many times, and the answer is always the same – CakePHP doesn’t even attempt to be better than Rails, as they are two very different projects that use – most importantly – two very different languages. The important thing to understand is how CakePHP is able to learn from Rails and adapt its functionalities to PHP without imposing any Ruby-only practice. Cake makes extensive use of PHP’s object model and even strives to ensure compatibility with both PHP4 and PHP 5. This is what makes CakePHP one of the most interesting PHP frameworks out there – the ability to offer the same structure and organization of Rails in PHP, while allowing PHP developers to create and manage their application in a more maintainable manner.

Let’s return to our tutorial and examine some view files generated with the two frameworks, such as the index view, which lists all contacts stored in our database. See Listing 6a and Listing 6b.

In this case the CakePHP solution only displays certain columns, while Rails cycles through all fields indifferently. These are the default solutions provided by each framework, but they can be changed according to the developer’s requirements. The Rails view is just a slightly more complex scaffold, while CakePHP seems to be nearer to a real-world implementation. Of course, you can change Rails’ default view to match CakePHP’s and display only certain fields.

As you can see in Listing 7a and Listing 7b, both frameworks offer similar, equally efficient solutions to quickly code an editing form. For instance, CakePHP uses the pre-defined HTML Helper class to easily create and format HTML tags, saving the developer a lot of typing.

The view and add files are not very different to the code we examined so far. Both the files are equally optimized to save the developer from typing boring, repetitive code. From this point onwards, it’s easy to add additional functionalities and manage more than one database table, using the powerful table association rules that both frameworks integrate.


Listing 5a
Ruby on Rails – Contacts Controller
[controllers/contact_controller.rb]
1 class ContactsController < ApplicationController
2
3 def index
4 @contacts = Contact.find_all
5 end
6
7 def view
8 @contact = Contact.find(params[:id])
9 end
10
11 def add
12 @contact = Contact.new(params[:contact])
13 if @contact.save
14 flash[:notice] = ‘Contact was successfully created.’
15 redirect_to :action => ‘index’
16 else
17 render :action => ‘add’
18 end
19 end
20
21 def edit
22 @contact = Contact.find(params[:id])
23 if @contact.update_attributes(params[:contact])
24 flash[:notice] = ‘Contact was successfully updated.’
25 redirect_to :action => ‘show’, :id => @contact
26 else
27 render :action => ‘edit’
28 end
29 end
30
31 def delete
32 Contact.find(params[:id]).destroy
33 redirect_to :action => ‘index’
34 end
35
36 end


Listing 5b
Ruby on Rails – CakePHP
[controllers/contact_controller.rb]
1 <?php
2
3 class ContactsController extends AppController
4 {
5 var $name = ‘Contacts’;//for php4
6
7 function index(){
8 $this->set(‘data’, $this->Contact->findAll());
9 }
10
11 function view($id){
12 $this->set(‘data’, $this->Contact->read());
13 }
14
15 function add(){
16 if (empty($this->data)){
17 $this->render();
18 }
19 else{
20 if ($this->Contact->save($this->data)){
21 this->flash(‘Your contact has been saved.’,’/contacts’);
22 }
23 else{
24 $this->set(‘data’, $this->data);
25 $this->render();
26 }
27 }
28 }
29
30 function edit($id=null){
31 if (empty($this->data)){
32 $this->Contact->setId($id);
33 $this->data = $this->Contact->read();
34 $this->render();
35 }
36 else{
37 if ( $this->Contact->save($this->data)){
38 $this->flash(‘Your contact has been updated.’,’/
contacts’);
39 }
40 else{
41 $this->set(‘data’, $this->data);
42 $this->render();
43 }
44 }
45 }
46
47 function delete($id){
48 if ($this->Contact->del($id)){
49 $this->flash(‘The contact with id: ‘.$id.’ has been deleted.’,
‘/contacts’);
50 }
51 }
52 }
53
54 ?>


Listing 6a
Ruby on Rails – List Contacts
[views/contacts/index.rhtml]
1 <h1>Listing contacts</h1>
2
3 <table>
4 <tr>
5 <% for column in Contact.content_columns %>
6 <th><%= column.human_name %></th>
7 <% end %>
8 </tr>
9
10 <% for contact in @contacts %>
11 <tr>
12 <% for column in Contact.content_columns %>
13 <td><%=h contact.send(column.name) %></td>
14 <% end %>
15 <td><%= link_to ‘View’, :action => ‘view’, :id => contact %></td>
16 <td><%= link_to ‘Edit’, :action => ‘edit’, :id => contact %></td>
17 <td><%= link_to ‘Delete’, { :action => ‘delete’, :id => contact }, :confirm => ‘Are you sure?’, :post => true %></td>
18 </tr>
19 <% end %>
20 </table>
21 <br />
22 <%= link_to ‘New contact’, :action => ‘add’ %>


Listing 6b
CakePHP – List Contacts
[views/contacts/index.rhtml]
1 <h1>Listing contacts</h1>
2 <table cellpadding=”4” cellspacing=”4”>
3 <tr>
4 <th>ID</th>
5 <th>Name</th>
6 <th>Created</th>
7 <th> </th>
8 <th> </th>
9 </tr>
10 <?php foreach ($data as $contact): ?>
11 <tr>
12 <td>
13 <?php echo $contact[‘Contact’][‘id’] ?>
14 </td>
15 <td>
16 <?php echo $html->link($contact[‘Contact’][‘name’], “/contacts/view/{$contact[‘Contact’][‘id’]}”) ?>
17 </td>
18 <td>
19 <?php echo $contact[‘Contact’][‘created’] ?>
20 </td>
21 <td>
22 <?php echo $html->link(‘Delete’,”/contacts/delete/{$contact[‘Contact’][‘id’]}”, null, “Are you sure you want to delete contact entitled \’{$con
tact[‘Contact’][‘title’]}\’?”) 23 ?>
24 </td>
25 <td>
26 <?php echo $html->link(‘Edit’,”/contacts/edit/{$contact[‘Contact’][‘id’]}”) ?>
27 </td>
28 </tr>
29 <?php endforeach; ?>
30 </table>
31 <?php echo $html->linkTo(‘Add new contact’, ‘/contacts/add’) ?>


Listing 7a
Ruby on Rails – Edit Contact
[views/contacts/edit.thtml]
1 <h1>Edit contact</h1>
2 <%= error_messages_for ‘contact’ %>
3 <%= start_form_tag :action => ‘update’ %>
4 <%= hidden_field ‘contact’, ‘id’ %>
5 <p><label for=”contact_name”>Name</label><br/>
6 <%= text_field ‘contact’, ‘name’ %></p>
7 <p><label for=”contact_number”>Phone Number</label><br/>
8 <%= text_field ‘contact’, ‘number’ %></p>
9 <p><label for=”first_met”>Known Since</label><br/>
10 <%= date_select “contact”, “first_met”, :use_month_numbers => false %></p>
11 <%= submit_tag ‘Edit’ %>
12 <%= end_form_tag %>


Listing 7b
CakePHP – Edit Contact
[views/contacts/edit.thtml]
1 <h1>Edit Contact</h1>
2 <?php echo $html->formTag(‘/contacts/edit’)?>
3 <?php echo $html->hidden(‘Contact/id’); ?>
4 <p> Name: <?php echo $html->input(‘Contact/name’) ?>
5 </p>
6 <p>
7 Phone Number: <?php echo $html->input(‘Contact/number’) ?>
8 </p>
9 <p>
10 Known Since: <?php echo $html->dateTimeOptionTag(‘Contact/first_met’) ?>
11 </p>
12 <p>
13 <?php echo $html->submit(‘Save’) ?>
14 </p>
15 </form>


Conclusion
After examining Ruby on Rails and CakePHP through this comparative tutorial it is clear that both frameworks can make the development of a web application faster and more organized. If Rails syntax and structure is substantially helped by the Ruby programming language itself, the CakePHP folks did an outstanding job trying to reduce PHP’s excessive verbosity and inconsistencies. Since I started developing with CakePHP, I have never used include() or require() anymore – the framework is able to locate and automatically load the right files by itself. So I have stopped worrying about providing functional database abstraction and concentrated on the business logic specific to my application, rather than on re-writing boring code, over and over.

Some traditional PHP programmers, who tried CakePHP, have pointed out that the structure and concepts introduced by the framework attempt to modify the programmer’s way of coding an application, by proposing a rigid structure to follow. Having used some of the other PHP frameworks available, I think CakePHP is one of the most easy to use and less strict. Of course, the internal MVC architecture must not be altered, but that’s about the only price to pay to achieve truly amazing results.


About the Author

Fabio Cevasco is currently employed as technical writer for Siemens Italia, contributing to the documentation of the company’s corporate MES framework, Simatic IT. He graduated in IT Engineering at the University of Genoa, Italy, where he learnt the basics of software engineering, application design and programming. During his free time, he enjoys writing about information technology, web development, and PHP programming for his own web site and for various magazines or web sites.


   Related Links
http://www.php-mag.net
http://www.rubyonrails.org
http://www.cakephp.org
http://www-128.ibm.com/developerworks/linux/library/l-rubyrails/
http://cakeforge.org/frs/?group_id=13


Comment

Name:

Comment:

Captcha Verification !
captcha_image