One More Tip For Speeding Up CakePHP Apps

Posted by Matt on Thu, Apr 16 2009

I somehow completely failed to mention the whole $uses/ClassRegistry/loadModel/chained models thing in my 8 Ways to Speed Up CakePHP Apps post. That's like doing a post on the top 5 adult film stars who hit rock bottom, had it video taped and posted on YouTube, and failing to mention the epic Chasey Lain video (part 2). If you think that link is even remotely SFW, go re-read the description again.

Don't Use $uses Unless You Really, Absolutely Have To

$uses is a controller attribute that allows you to access additional models to the default one. Say you have a blog application and one of the controllers is posts. By default you have access to the Post model. If you wanted to also have access to the Comment model you could do (but shouldn't):

<?php
class PostsController extends AppController {
  var $name = 'Posts';
  var $uses = array('Post', 'Comment');
}
?>

Model Chains

Since Comment is associated to Post through a HasMany relationship you can access the Comment model through Post. Like this:

$comments = $this->Post->Comment->findAllByPostId($id);

The relation chain extends infinitely, including all models down the line.

Controller::loadModel and ClassRegistry::init

Great, but sometimes you do legitimately need access to a model that isn't anywhere in the relation chain. If you are going to use the model throughout the controller go ahead and include it in $uses, but if you only need it in one action there are better ways. They are Controller::loadModel() and ClassRegistry::init().

//the loadModel way
$this->loadModel('Comment');
$comments = $this->Comment->findAllByPostId($id);

//the ClassRegistry way
$Comment = ClassRegistry::init('Comment');
$comments = $Comment->findAllByPostId($id);

Controller::loadModel, not to be mistaken for the deprecated loadModel function, creates an instance of the model and assigns it to the controller. You can then access it the same way as you would as if it was loaded through $uses. ClassRegistry returns an instance of the model. Gwoo prefers the loadModel approach over ClassRegistry. Good enough for me.

Approximate Increase

The dreaded: "it depends." Having one or two extra models in your controller's $uses probably isn't going to kill your app. I added one extra model to my test app and there was about a 4% increase in how long the page took. Then I added seven extra models and there was approximately a 40% increase. So roughly 4-6% for every additional model.

Posted in CakePHP

7 Comments

Baz L said on Apr 16, 2009
Now I'm confused. What ever happened to:
App::import('Model', 'MyModel');
?
Miles J said on Apr 16, 2009
@Baz - App::import() is called automatically within loadModel() and ClassRegistry.

Also another point when doing a $uses. The controller paginate() method requires the model to be within the $uses array, if you have added it to the $paginate property. This is quite annoying when the model can be found within another models association, but you still have to load it anyways for the pagination.
Matt said on Apr 16, 2009
paginate() does check for first level model associations.
http://api.cakephp.org/view_source/controller/#line-951.

For anything farther down the chain you can use loadModel as noted below.
skiedr said on Apr 16, 2009
@Miles
$uses is not necessery for pagination. Controller::loadModel can be used in this case.
Mariano Iglesias said on Apr 16, 2009
$uses is like shaving yourself with a knife. You CAN do it, but that doesn't mean that you should. Use a razor!

So if you end up lost in an island somewhere in the pacific, then you should use $uses. Otherwise stick to model chaining.
Nick said on Apr 17, 2009
I prefer ClassRegistry::init('Model') over $this->loadModel('Model') because if I'm at the point of dynamically loading a model, I'm usually only doing a one liner model function and I can chain the function (find or other) directly off the ClassRegistry::init.
Matt said on Apr 17, 2009
Hey Nick,
Yea, I always did it this way too...I didn't even know about loadModel until I read Gwoo's comment.

Add new comment