Buggy CakePHP Code: The 6 Most Common Mistakes CakePHP Developers Make

View all articles

CakePHP is an amazing PHP framework, but it has a steep learning curve! It requires a good amount of research and training to become an expert.

I have been fortunate to use CakePHP for over 7 years now, and in that time I’ve had the honor of working with many members of the CakePHP community.

In this CakePHP tutorial I’d like to describe few bad practices which I have seen over the years, and propose the correct approach to avoid these mistakes. This isn’t to say my code is perfect, but as a programmer we are always learning, so it is important to follow the best practices and adjust as you learn!

Content of this article is inspired by a post from CakeCoded. If you would like to learn more about CakePHP please visit our learning section here.

This beginner CakePHP tutorial will help you avoid frying your CakePHP code with errors and mistakes!

Common Mistake #1: Not Following CakePHP Coding Conventions

CakePHP coding conventions can be viewed here. I will highlight a few things which I often notice when viewing other programmers’ code.

Control structures. So often you see programmers get this wrong, and in some cases bring practices from other coding languages. CakePHP expects the following syntax:

if ((expr_1) || (expr_2)) {
    // action_1;
} elseif (!(expr_3) && (expr_4)) {
    // action_2;
} else {
    // default_action;
}

There should be 1 (one) space before the first parenthesis and 1 (one) space between the last parenthesis and the opening bracket. So this means that the following is incorrect:

if($this->request->data){

}

Note the spacing between the if and (, and between ) and {

Always use curly brackets in control structures, even if they are not needed. They increase the readability of the code, and they give you fewer logical errors.

So, for example, the following is incorrect:

if ($foo)
    $bar = true

This should be formatted like this:

if ($foo) {
    $bar = true
}

Finally, watch where you place the brackets. Opening brackets shouldn’t start a new line. And make sure all your brackets line up so that each new bracket is in line with the closing bracket.

Here are some incorrect examples:

if ($foo)
{
    $bar = true;
}

This is incorrect, the opening bracket should be in the first line:

if ($foo) {    
    $bar = true;
if ($action) {
    $to = false;
}
}

The indentation needs to line up correctly.

I often hear programmers say, “But I am too busy to make the code neat….” My response is, “Trust me, neat code will stand the test of time”. Writing CakePHP code which isn’t readable will be a nightmare to come back to if you need to make a change in a few months.

Common Mistake #2: Improper Use of Containable Behaviors and Recursive Levels in ORM

I was fortunate recently to have an informal discussion with a database developer from Facebook. We started talking about CakePHP and he said to me, “Oh, that uses ORM doesn’t it? That can be scary.” I asked him what he meant, and he commented that with Object-relational mapping (ORM) it is easy for SQL queries to become unnecessarily large.

He is right in a way. Part of CakePHP’s magic is in its use of ORM and the way that it groups different database table relations together. By default, CakePHP automatically selects any related ‘Belongs To’, ‘Has One’ and ‘Has Many’ data, and this can lead to very large SQL queries. These queries may not be a concern when you are initially developing an application, but after six months of collecting live data, you may find the application becomes very slow, and in some cases crashes if the queries aren’t optimized.

I look out for two things when auditing an existing website. Firstly, has the default recursive level been changed? By default, CakePHP sets the recursive level to 1, which in my opinion is too high. I always set it to -1 and then use the containable behavior to get any related models.

That leads to the second thing I look for - has the Containable behavior been used? I often have new clients come to me and say that CakePHP is slow. The reason is almost always because Containable hasn’t been used! A good CakePHP programmer will optimize their SQL queries regardless of how much “auto-magic” is done behind the scenes.

The containable behavior wasn’t added until CakePHP 1.2, but boy has it made a difference?! Be sure to use containable as much as possible, as it is such an effective way to optimize your SQL. For more information on how to implement and use the Containable behavior, click here.

Common Mistake #3: Keeping Business Logic in Controllers Instead of Models

Good CakePHP code will have the logic in the model files. This takes a bit to get used to, but once mastered there is no looking back! A controller file should be used for what it is intended for in the MVC pattern - controlling! So use your controller file to handle user actions, while letting the business logic go in the model file.

A good example of this would be a simple CRUD - an everyday action! Let’s take the add posts function from a blog tutorial as an example. The default add function is as follows:

public function add() {
    if ($this->request->is('post')) {
        $this->Post->create();
        if ($this->Post->save($this->request->data)) {
            $this->Session->setFlash(__('Your post has been saved.'));
            return $this->redirect(array('action' => 'index'));
        }
        $this->Session->setFlash(__('Unable to add your post.'));
    }
}

This controller action is fine for a simple add, but what would happen if you wanted to do things such as send an email to the admin when a post was added, or update another model association when a post was added. This is additional logic, but this logic shouldn’t go into our controller file.

Instead we would write a function for this in our Post.php model. Perhaps something like this:

public function addPost($data = array(), $emailAdmin = true) {
    $this->create();
    $this->save($data);

    // update any other tables

    // send the email to the admin user
    if ($emailAdmin) {
    
    }

    // if all is successful
    return true;
}

This would then result in a small change to the controller action as follows:

public function add() {
    if ($this->request->is('post')) {
        if ($this->Post->addPost($this->request->data)) {
            $this->Session->setFlash(__('Your post has been saved.'));
            return $this->redirect(array('action' => 'index'));
        }
        $this->Session->setFlash(__('Unable to add your post.'));
    }
}

As you can see, the new action is actually one less line, because the $this->Post->create() has been moved to the model file.

This is a perfect, everyday example of where moving logic to the model file is a good idea - and it certainly makes for a much cleaner code base!

Common Mistake #4: Adding Too Much Complexity to the Code, Instead of Returning Often and Early

This is always a bit of an ongoing debate, but returning often, and returning early certainly does make for much cleaner looking code. This applies to the model methods more than anything else.

But what exactly do I mean? Well, let’s take a look at the method we added in the CakePHP tutorial above:

public function addPost($data = array(), $emailAdmin = true) {
    $this->create();
    $this->save($data);

    // update any other tables

    // send the email to the admin user
    if ($emailAdmin) {
    
    }

    // if all is successful
    return true;
}

To return often, and return early means that as we run through our function, we check to make sure the everything is OK on a regular basis. If it isn’t, then we return false, or return a CakePHP error.

It might be easiest to show this with an example. There are two ways the above function could be written:

public function addPost($data = array(), $emailAdmin = true) {
    if ($data) {
        $this->create();
        $result = $this->save($data);

        if ($result) {
            // update any other tables

            // send the email to the admin user
            if ($emailAdmin) {
                // send the admin email
            }
        } else {
            // problem saving the data
            return false;
        }

        // if all is successful
        return true;
    } else {
        // no data submitted
        return false;
    }
}

See how the code quickly becomes unreadable? There are ifs and elses all over the place, and the function quickly becomes one big indentation. Don’t get me wrong, I love clean indentation, but watch how the function looks if it written with the return often, return early principle.

public function addPost($data = array(), $emailAdmin = true) {
    if (!$data) {
        // no data submitted
        return false;
    }

    $this->create();
    $result = $this->save($data);

    if (!$result) {
        // problem saving the data
        return false;
    }

    // update any other tables

    // send the email to the admin user
    if ($emailAdmin) {
        // send the admin email
    }

    // if all is successful
    return true;
}

Straight away, in this small example, you can see the code only has a single indentation and is much more readable. The logic actually makes more sense - let the logic run through line by line, and if there is any issue along the way, return the error and don’t proceed to the next line.

This allows a CakePHP programmer to write the same way that we read - reading code from left to right, top to bottom, rather than in different blocks, which can quickly get confusing!

Common Mistake #5: Not Using the DRY Principle

DRY stands for Don’t Repeat Yourself, and it is a philosophy which should be followed when coding in CakePHP. With object-oriented code, there is no excuse for repeating the same block of code twice!

Here are few CakePHP tips to ensure you don’t repeat yourself:

  • As mentioned above, aim to put logic in model files so you can share the logic.

  • In your view files, if you are repeating views, create the view code as an Element, or even a custom helper.

  • Set up some configuration settings - the app/Config/bootstrap.php file is a great place for this. This helps make sure you aren’t hard coding things like the application name and the main email address. The last thing you want to do is go through hundreds of files just because the client has asked to update an email address in an application.

  • Always ask yourself, “If I am repeating code, is there a better way to write this code, and am I putting this code in the right place?” Chances are, if you need to repeat code, it could be written better.

Common Mistake #6: Not Commenting the Code

The last point I will make is in regards to comments. Firstly, doc blocking. A doc block is when you document a method or an action. It takes only a minute to record a little about what a function is doing, but it makes such a difference in terms of readability of code.

CakePHP Doc Blocks need to go against the left margin of the page. So a simple example using the code from above.

/**
 * Adds & saves a post as well as emails the admin to let them know the post has been added.
 * Also performs some saving to another table
 *
 * @param   array $data The post data
 * @param   bool $emailAdmin If set to true, will email the website admin
 * @return  bool Returns true if successful
 */
public function addPost($data = array(), $emailAdmin = true) {

As you will see, it doesn’t take long to write a doc block, but it makes a huge difference in terms of longevity of the code. Ultimately, it means the code can live on past you as the developer.

Likewise with in-line comments. Don’t be scared to explain what your code is doing and why! It makes it a lot easier in the long run to understand your code, especially if another developer is looking at it!

Wrap-up

CakePHP is an extensive, full-featured framework. Given it follows convention over configuration, CakePHP is more strict than other PHP based frameworks, in the sense that a user is “forced” to follow a certain way of laying out the code. This can be controversial, but in my experience it leads to a code base which is more consistent, readable and understandable - rather than letting a developer “choose” how the code should be written, a development team will write consistent code by following Cake’s conventions.

By following this CakePHP tutorial and ensuring your code is well written, applications can stand the test of time. Code should always be written for tomorrow - so that if another developer is looking at a particular code block years later, he will understand the code, and stick to the expected standards. CakePHP is no different and hopefully this guide will help correct some bad habits.

About the author

Michael Houghton, Ireland
member since March 6, 2014
With twelve years of back-end development in PHP combined with a background in business, Michael brings a great balance of technical and business expertise to the table. He has experience with vanilla PHP websites as well as CakePHP, Zend, CodeIgniter, PhalconPHP, and Laravel frameworks. He's also gained project management experience, leading teams and working directly with clients to build projects from start to finish. [click to continue...]
Hiring? Meet the Top 10 Freelance CakePHP Developers for Hire in December 2016

Comments

Acep Saepudin
great!
Ebooky.CZ
Mistake 4 - Is OK add send email to model logic? THX
Marcus Vinicius
It's not just Cake PHP mistakes. This mistakes appears on all frameworks manipulated by bad or newbies programmers.
Andy Carter
I'd say that #3 is perhaps suggesting to replace one common mistake with another. The sending of email shouldn't be happening in the model as it isn't really working with the database. Instead an event should be triggered by the addition of the post. Then the email can be sent from an event listener. The Events system has been part of Cake since 2.1 now, but a lot of people don't seem to work with it.
Ebooky.CZ
Nic i dont know Event system in CakePHP .-) THX http://book.cakephp.org/2.0/en/core-libraries/events.html
CPasGagné
#4, can you add example about // update any other table because I need to validate and save datas from an other model. It's easy in the controller but I don't really see how to do in a model.
Martin Schenk
very good!
Benny Bernard
Mistake 1#: Using Cakephp (Codeigniter x 1000 > CakePhP)
Said Bakr
No, Using CI (I'm talking about ver 2), easily and simply, leads to a Spaghetti code.
Said Bakr
For mistake #3, I think that callbacks are invented for that goal.
Paul Hughes
I know this comment is a year old, but this is a very important point; to take the example, it is going to get very hard to [elegantly] stop the e-mailing functionality if, say, you're on a dev environment, or (this would get really annoying) are running unit tests. Sure, you could add a conditional to check for the global environment, but then we're really putting logic in the model that belongs in a listener. I'm new to CakePHP, but coming from other frameworks and languages, this one screamed out as "yikes" to me. ;-) Anyway, just wanted to add my "Hear, hear" to your point. :) EDIT: Enclosed in [ ]. The addition is to make clear that "sure it is easier", but as soon as you have several behaviors like this scattered in the models, it's going to get ugly quick.
polbaysa
Oh please tell me you're joking.
Zekri Anouar-Charif
for #3, i think using events are better in his example...
Phattius
Mistake #1 is Chicken$$$$. So long as the coding conventions are consistent throughout your project, it barely matters how many spaces go between the "if" and the "(". Mistake #3 is exactly what you get in the default files when you use the version 2 Cake Bakery. So what did you expect beginners to do? Mistakes #4, #5 and #6 are long-standing principles that were not invented in CakePHP, nor were they invented in Object Oriented programming. Even Assembly language programmers are familiar with "DRY", even if the acronym had not been invented yet.
comments powered by Disqus
Subscribe
The #1 Blog for Engineers
Get the latest content first.
No spam. Just great engineering and design posts.
The #1 Blog for Engineers
Get the latest content first.
Thank you for subscribing!
You can edit your subscription preferences here.
Trending articles
Relevant technologies
About the author
Michael Houghton
PHP Developer
With twelve years of back-end development in PHP combined with a background in business, Michael brings a great balance of technical and business expertise to the table. He has experience with vanilla PHP websites as well as CakePHP, Zend, CodeIgniter, PhalconPHP, and Laravel frameworks. He's also gained project management experience, leading teams and working directly with clients to build projects from start to finish.