Reducing requestAction() use in your CakePHP sites with fat models
Aug 15 2008
When bakers first start using CakePHP there is a tendency to use requestAction() more often than it should be. Often requestAction() gets used to pull in common elements like recent posts or new comments, or to make menus. This makes sense in a way as it keeps the comments code in the CommentsController and all is well. However, you start to hit a snag when your awesome application starts getting traffic. For all that is good about requestAction(), it has one disadvantage, its slow really slow. If you have never looked at what requestAction() is doing, it basically hits your site with another page request, minus the bootstrapping. And while you can negate much of this overhead by using caching effectively, using requestAction can lead to bad practices.
A better way
Personally I think that almost every where that requestAction is used the following is a more useful and efficient approach. There are still cases where requestAction() is needed but they are rare. This idea builds on the fat model, skinny controller approach in that it pairs fat model functions to elements to be used throughout your application. A quick example would be
- /**
- * Get the most Recent Comments
- *
- * @param int $limit The number of comments you want
- * @return Array
- **/
- public function recent($limit = 6) {
- $this->recursive = 1;
- 'limit' => $limit, 'order' => 'Comment.created DESC'));
- return $comments;
- }
This simply pulls up the most recent comments and returns them. If you are crafty with your model relations you should be able to easily get to your Comment model from anywhere in your application, failing relationships you can always use $uses to access the model you need. We then ‘pair’ this model function with an element. And by pair, they work well together but are not tightly coupled as the MVC structure in CakePHP keeps it loose.
Lets see some results
Now that we have a model function and know how to get at it we can call it in our controller.
Show Plain Text- $comments = $this->Post->Comment->recent();
- $this->set('recentComments', $comments);
In our view wherever we want to show our recent comments we can simply include our element, which just so happens is expecting a list of comments.
Show Plain TextOur element looks something like this.
Show Plain Text- <div class="recent-comments">
- <ul>
- <?php foreach($recentComments as $comment) : ?>
- 'controller' => 'posts', 'action' => 'view', $comment['Post']['id'])
- );</li>
- <?php endforeach; ?>
- </ul>
- </div>
Take note that we specify both the controller and the action in the url array, this will help keep our links pointing to the right place. This technique of model-element pairs will help lighten your controllers and reduce the amount of requestAction()’s that get used in your application. Another advantage of adopting a fat model / skinny controller approach is that it forces you to push more code into the model, this benefits you the developer as you create more reusable code.
Search
Categories
Recent Posts
- Using bindModel to get to deep relations
- New home, new sideproject
- Using bitmasks to indicate status
- AclExtras Shell
- Getting a new Oven, Migrating from CakePHP 1.1 to 1.2
- Code Completion for CakePHP in Eclipse
- CakePHP RC3 released and CakePHP 1.1 new release
- Book Review: CakePHP Application Development
- Providing Contextual Form Help with Mootools
- Creating gracefully degrading javascript and enabling progressive enhancement
Comments
Martin Bavio on 15/8/08
Mmmm but then you are tied to set all the variables that you need for a (for example) navbar in all the actions of all the controllers!
I agree with the Fat Models Skinny Controllers advice, but I dont see the point here.
I think the real solution to avoid using requestAction is AD7six Mini-Components.
Cheers,
mbavio
brian on 16/8/08
we need to get lots of these little elements in the pages controller for certain pages, and I didn’t really want to load up $uses in this controller, but maybe it is the best idea… anyone?
mark story on 22/8/08
brian: You don’t necessarily have to load up
$usesyou can always use your model relationships to get to the data you need. This may not be the best approach for including lots of elements on the built-in PagesController. In that circumstance requestAction() might be easier.rafaelbandeira3 on 23/8/08
were your feeds moved? my reader wasn’t updated since last two posts… anyway… I think that’s the time to rethink a lot on data sharing and non-app-bussines-logic data access on cakephp apps, because this topic was the most blogged this week and was very commented and discussed in debbugable.com, cakebaker.42dh.com, teknoid.wordpress.com, and it was blogged before. Many approaches were shown, but nobody feels comfortable about using them, because there’s no core development team position on the issue, and people don’t wan’t to make unsupported code… I think you as a cakephp member, could try to bring a solution to the community, or at least approve an approach.
Andy’s approach is the most popular, but the post itself says it’s not a clean approach.
It’s not just a philosophical discussion, it would be very good for newbies to start baking without things they will only know as harmful when they really RTFM and go around skilled blogs as the ones i mentioned before – we all know they don’t do that.
rafaelbandeira3 on 23/8/08
maybe I wasn’t very clear, but I meant that every discussion about requestAction and fatModelsSkinnyControllers end up in a real world approach, where one view use bits of data from a not-related-to-the-main-data source – widgets for example. Now you can read and actually understand the comment above.
mark story on 23/8/08
rafaelbandeira3: Keep in mind that both Andy, and Felix are on the core team and are probably as or more qualified to give an ‘authoritative’ direction. But with this particular case I don’t think there is single right solution. Both Felix’s and Andy’s solutions are excellent alternatives to my approach and the standard requestAction. Kim’s alternative method also is a promising approach.
At the end of the day there is no right way, and it is up to each developer to choose the method that works best for him/her in each case.
I don’t think my feeds have moved. They should still be at http://mark-story.com/posts/rss
rafaelbandeira3 on 25/8/08
mark, I know Andy and Felix are part of the core team, and notice that Felix didn’t show any solution, he just defended fatModels[…], what’s nice because the word is more spreaded around now. Kim’s solution is a bit hacky as Teknoid’s one…
But after all you answered it well, there wont be a default/prefered way, and that’s it, and that’s ok, actually that was my doubt. I think I’ll post my solution too, but first I need to get rid of all dirty tricks O’ve put there ;-)
zahid on 27/8/08
Thanks dude,
It helps to make custom queries
http://blog.decentmart.com
braveh4rt on 9/10/08
i use some request action and use elemnt to and implement fat model skinny controller and using cake 1.x
is there any diferent ??
Rahil on 16/10/08
Hi Mark,
I’m having trouble following your example and understanding which code goes where.
Let’s say on my home page of my website, I want data from multiple controllers (ie events, posts, comments). I understand that I have to create an element for each, and most beginners (including myself) are using requestAction within their elements.
So where do I write functions to grab data from the different controllers? I’m really lost!
Graydon 1 day, 4 hours ago
Would it just be easier to setup some basic functions in app/app_controller.php?
I find this makes life much easier for grabbing data from multiple models wherever I need it.
Have Something to say?