Notebook

April 06, 2008 9:58PM

A Review of CakePHP

CakePHP Logo Recently, on a somewhat secret project, I've had the opportunity to try out CakePHP, an MVC framework for PHP. I wanted to take some time to share my thoughts on what I've liked and disliked in my experience so far.

Missing Migrations

My #1 favorite feature in Rails has to be migrations. They allow you to very easily add and remove fields of a database without trying to keep track of SQL queries. In CakePHP, nothing like this exists (at least that I'm aware of). I've already had numerous issues with databases being out of sync due to having the code in three different environments (dev, staging, and production). I've had to resort to a combination of phpMyAdmin and text files with SQL to keep track of all the changes that need to be made.

Models Fall Short

Personally, I'm a huge subscriber to the "fat model, skinny controller" method of structuring code, which stipulates that the majority of code should reside in your models (which handle the data), rather than the controllers and views. With CakePHP, however, this is a little difficult to implement. When querying the database using a model like $this->User->findAll();, the function just returns a text array, rather than an array of objects like Rails does.

To demonstrate my point, let's pretend I have a table of users that stores their first name as first_name and last name as last_name. I want to print out their first name, last name, and their full name (which is generated from their first and last name). With Rails, I just add the method User#full_name to the User model. Since the full object is passed to the view, I can call that method directly:

First Name: <%= @user.first_name %><br />
Last Name: <%= @user.last_name %><br />
Full Name: <%= @user.full_name %>

However, with CakePHP, since it's only an array that's passed, I can't call a function, and the code gets a little messy:

First Name: <?php echo $user['User']['first_name']; ?><br />
Last Name: <?php echo $user['User']['last_name']; ?><br />
Full Name: <?php echo $user['User']['first_name] . ' ' . $user['User']['last_name']; ?>

Granted, I could use a helper function in the view, but in my eyes, generating the full name is something that should reside in the model. In this example, it's really not that big of a problem, but as you want to do more complicated manipulations of the data, it gets a little messy with CakePHP.

Messy Syntax

While it isn't totally the fault of CakePHP, but rather of PHP itself, Cake requires some pretty messy syntax to accomplish things. For example, let's say I have posts that have both an editor and an author. To define these relationships in Cake, I'd have to do the following:

// user.php
class User extends AppModel {
  var $name = 'User';
  var $hasMany = array('EditedPosts' => 
                        array('className' => 'Post',
                              'foreignKey' => 'editor_id'),
                        'AuthoredPosts' =>
                         array('className' => 'Post',
                               'foreignKey' => 'author_id')
                      );
}

// post.php
class Post extends AppModel {
  var $name = 'Post';
  var $belongsTo = array('Editor' => 
                          array('className'  => 'User',
                                'foreignKey' => 'editor_id'),
                         'Author' =>
                          array('className'  => 'User',
                                'foreignKey' => 'author_id')
                        );
}

Pretty confusing, huh? All the arrays really get in the way. In Rails, the same situation would be done like this:

# user.rb
class User < ActiveRecord::Base
  has_many :edited_posts,   :foreign_key => 'editor_id',
                            :class       => 'Post'
  has_many :authored_posts, :foreign_key => 'author_id',
                            :class       => 'Post'
end

# post.rb
class Post < ActiveRecord::Base
  belongs_to :editor, :class => 'User'
  belongs_to :author, :class => 'User'
end

To me, the Rails code is a lot easier to read and makes much more sense. Like I said before though, this is really a Ruby vs PHP issue and not Rails vs CakePHP.

Super Easy Deployment

It may seem like I'm really ragging on CakePHP, but there are definitely things I like compared to Rails. One of my (and many others') major gripes about Rails is how difficult it is to deploy an application: there's a lot of server side configuration that can get really confusing. With CakePHP, however, it's practically a non-issue. Since that supports PHP (which I'm guessing is 99% of shared hosting). Just upload your files, and you're ready to go. With Rails, setting up a production environment would require setting up Apache forwarding, Mongrel instances, and more. In this department, Rails really can't compete with Cake.

More Resources for the Beginner

PHP has perhaps the best online documentation of any language out there. Every function is well documented, and most have user comments below with tips and explanations on various quirks. It's also a very widely used language, which means a lot more people can help you out if you have issues. Even though CakePHP itself isn't particularly well documented, it definitely benefits from the many PHP resources out there. Ruby, on the other hand, though things are getting better, isn't nearly as well documented as PHP and doesn't really have a central place to go like PHP.net. There also aren't nearly as many people that are familiar with the language.

CakePHP is Beginner-Friendly

Though CakePHP is lacking in a many areas where Rails really excels, I think it definitely has its place in the world of web frameworks. I would definitely consider using it on smaller-scale projects where I don't want to deal with the complicated setup of a Rails production environment. It's also a little more accessible for beginners than Rails because of the vast PHP community. However, for a user requiring a more powerful framework, I currently don't think there's much out there that's better than Rails.

Did you like this entry? Make sure to subscribe to my RSS feed to keep up-to-date with my newest entries and links.

Comments

Avatar

Daniel Hofstetter

April 07, 2008 at 1:13AM #

For migrations for CakePHP have a look at the following project: http://code.google.com/p/cakephp-migrations/

Avatar

Kyle

April 07, 2008 at 1:19AM #

Daniel: Thanks for the link. I took a look, and it looks very promising. Maybe it will be integrated into the Cake core at some point?

Avatar

Colin Devroe

April 07, 2008 at 11:13PM #

Really nice overview Kyle.

Avatar

nate

April 09, 2008 at 3:13PM #

Hi Kyle, I think you're misunderstanding a few things about how Cake works. Instead of a migrations system (not counting the 3rd party tool that's also available and works much the same as Rails'), we have a schema versioning system which has several notable advantages over migrations, which make it easier to manage schema changes with bigger teams.

Also, using callbacks the models provide, adding custom fields when reading or saving data is a simple matter.

Avatar

Kyle

April 09, 2008 at 4:38PM #

Nate: Thanks for your reply! It's awesome to see that someone from CakePHP actually saw this post.

I tried finding information about the schema versioning system you were talking about, but I wasn't able to locate it. Would you be able to point me in the right direction?

Also, I'm not sure callbacks solve the issue I mentioned. While I can use an "afterFind" callback and add a "full_name" custom field, Cake still returns an array rather than an actual object. In addition, if the custom field is more complex and requires an additional query to get the data, that would mean 2 queries would be made when calling find(), rather than just one upfront. The additional call will only be made if I need it in my view, which would only be some of the time.

Avatar

deizel.

April 14, 2008 at 8:36AM #

I believe by the schema versioning system, nate was referring to the Schema shell documented here: http://api.cakephp.org/1.2/classschemashell.html

This functionality was just blogged about yesterday by Daniel Hofstetter, although he doesn't go into detail about the use of revision (snapshot) numbers. http://cakebaker.42dh.com/2008/04/13/migrations-the-cakephp-way/

Avatar

Kyle

April 14, 2008 at 9:39AM #

deizel: Thanks!

Avatar

pfwd

April 18, 2008 at 7:43PM #

Nice article, im learning cakephp at the moment and i have to agree with you on the easy of deployment.

Leave a Comment

(required)

(required, never displayed)

(optional)

Ajax-loader