15 Essential CakePHP Tips

1. Save() does not work!
Sometimes it happens that save() fails without any obvious reason. Your data array looks fine and you’ve build the form correctly, etc., etc., but no query was executed. It is very possible that save had failed due to validation errors. Maybe you are updating some model and while the current fields in the form pass the validation, there is a chance that some “other ones” are causing the validation rules to fail. An easy (and helpful) way to see what’s going on with validation is to do pr($this->validationErrors); in your view. By employing this method you’ll see exactly what’s happening with your model’s validation. The other option is to pass false as a second parameter to save(); in order to disable the validation. However, the latter method does not give much of hint and should not be used to fix a failing problem, but rather to purposely avoid validation.

2. Save() still does not work!
Do you have beforeSave(); in your model or app model? Always double-check for this method, and even more importantly, ensure that it returns true.

3. Validating on create or update
CakePHP has an ‘on’ key to be used in your $validate array. It allows you to specify whether the rule should be enforced during a new record creation or during an update of an existing record. For example, if you only want to check for a unique email address when you are creating a new User account, you’d add ‘on’ => ‘create’ to your $validate array. Therefore, this rule will be ignored when you are updating/editing some user.

4. Mind your cache
You’ve made some changes to your tables, but you app “ignores” them… You’ve moved some things around, bur your app doesn’t seem to “notice” that…
Clear the cache. Delete the files from your app/tmp/cache. Be sure to only delete the files and not the directory structure.
Basically if you notice some strange behavior in your app, just keep in mind that it could be caused by the cache.

5. I’m losing the extra URL parameters when paginating
You need to retain some extra URL parameters during pagination. For example the URL is something like /products/view/45. Yet, when you build the pagination the ID (45) is lost… Well, all you need to do is add this line of code to your view: $paginator->options(array(‘url’ => $this->passedArgs));

Update: this is likely fixed in the recent builds of CakePHP, but still good to be aware of.

6. Using afterFind()
Model::afterFind() allows you to perform some data manipulation after the Model’s find method. Here’s a sample usage in the model:

function afterFind($results, $primary=false) {
  if($primary == true) {
  // do stuff to the $results
  }

  return $results;
}

$primary will be set to true after your find() method is executed and some results are returned. After you modify the $results you will return them back to your app (controller).

7. I need to know the basic information about my table
Try this: pr($this->ModelName->schema())

(Thanks, gwoo, for the hint)

8. How do I check for a non-empty field in CakePHP 1.2?
Update: cake core now has a ‘notEmpty’ rule built-in, so definitely use it instead.

For historic purposes only:
The old VALID_NOT_EMPTY constant is now deprecated and there does not seem to be a rule to replace it… Well, it’s easy enough by using: ‘rule’ => array(‘minLength’, ‘1’)

Martin Bavio pointed out that having space characters (only) as your field data will make the validation rule pass and this is probably not a desirable effect. Using this simple regex, instead, will catch an empty string with space characters: ‘rule’ => array(‘custom’, ‘/\S+/’)

9. Avoid using the $uses array
You’ve got two completely unrelated models, but you need info from one in the controller of another. The first idea is to add them to the $uses array. Hey, it’s easy and gets the job done. Well, to make the long story short, it’s bad practice. Think about your model bindings and ensure that models are really not related to one another. Sometimes your User model is definitely not related to CommentRating, but you absolutely need it in your users controller. Well, just by chance it appears that User->Post->Comment->CommentRating. It’s a deep binding that may not be obvious at first, but by employing such a chain of models you can easily avoid using the $uses array, when it’s really not necessary.

Update: if you truly need to load some random (and definitely unrelated) model in your controller, do it like so in the given action:

$this->load(‘MyModel’);
As soon as this line executed you’ll have an instance of MyModel available in $this->MyModel (pr($this->MyModel); to see your freshly loaded object.

Another option is to use this approach:
$MyModel = ClassRegistry::init(‘MyModel’);

Which is nice, because it allows you to do things like this:

$someData = ClassRegistry::init(‘MyModel’)->find(‘all’, array(‘conditions’ => array(‘MyModel.name LIKE’ => ‘% ‘. $name . ‘%’ ))); (the latter, chaining, example is PHP5 only)

10. Clean-up ugly HTML

It’s no secret that CakePHP often outputs some very ugly and hard to read HTML. This little trick will make it a lot cleaner.
Create a file named app_helper.php in your app’s root directory.

Next add this function to it:


function output($string) {
return parent::output($string . “\n”);
}

Take a look at your HTML now… much better.

(Thanks, TommyO, for the hint)

11. How can I access session data in the view?
Very easy. You have the $session helper available.
Just try it: pr($session)
Update: if you have already written some variables to the session, then try pr($session->read());

12. I need to save data from multiple models
Don’t even think about using loops and other trickery. There is a very nice (but not well documented) method saveAll() available. It will let you save data from multiple models at once. Granted, it takes a little time to figure it out, but once you get it working it is really a time saver. Try using it with some dummy data, and make sure that your data array is properly formatted and associations are setup correctly.

13. Static pages and routes
I really don’t like having /pages/ as part of the URL for my static pages. Well, they are static… so let’s make them .html instead (at the same time we sprinkle just a little of security by obscurity mantra).
If you had links pointing to www.example.com/pages/myPage/ they should now point to www.example.com/myPage.html and add this to your routes:

Router::connect(‘/(.*).html’, array(‘controller’ => ‘pages’, ‘action’ => ‘display’));

Sweet.

14. The fastest way to build a form in CakePHP


echo $form->create();
echo $form->inputs();
echo $form->end();

It is just a step beyond scaffolding, but really this is how easy it is to build a form in CakePHP. Just give it a go.

15. Get to know CakePHP by using Bug tracker
Update: recently CakePHP has switched to another system from Trac.

CakePHP is constantly evolving and if you are serious about developing on top of this framework it is very important to keep up with the latest and greatest and to get familiar with some of the new and upcoming features. code.cakephp.org is a great place for this:

a. You can download nightly builds from here.
b. Keep an eye on the Wiki to see current status of CakePHP project and helpful hints.
c. Use Timeline to see the latest code updates. Pick “commits” to filter the updates.
d. Take a look at the code of test files to see how a certain feature should be used
e. Submit bugs and requests for enhancements, but read this first: http://book.cakephp.org/view/759/Bugreport

  • Pingback: 2 Static » Blog Archive » 15 Essential CakePHP Tips

  • http://www.justkez.com kez

    Nice tips.

    Also worth nothing (in relation to point 4) that CakePHP will (should) flush the cache when in debug level 3.

    • Kenan

      you mean worth noting

  • teknoid

    @kez

    Thank you. Good point.

  • http://www.gigapromoters.com/blog/ Abhimanyu Grover

    Good post. Thanks.. some points were nice to know.

  • http://mbavio.com.ar Martin Bavio

    Very cool tips. One observation: ‘rule’ => array(’minLength’, ‘1′) isnt the same as VALID_NOT_EMPTY, as you can add blank spaces and validation will succeed. I´m doing this with a very simple custom regex: ‘rule’ => array(‘custom’, ‘/.+/’)

    Hope it helps.

  • http://www.andruu.com Andru

    You made a small typo on number 7

    Try this: pr($this->ModelName->_shema)

    Should be:

    Try this: pr($this->ModelName->_schema)

  • teknoid

    @Andru

    Thank you, I’ve made the correction. Actually, it is proper to use the schema() method rather than the protected variable. I have adjusted the text to reflect that.

  • teknoid

    @Martin Bavio

    Thanks, that’s a good point. I tried your regex, but it would also fail with empty string and space chars. This one seems to work: ‘rule’ => array(‘custom’, ‘/\S+/’)

    I’ve adjusted the post to reflect that.

  • Pingback: how to clear your cache | Lasts information

  • Stefanski

    Thank you teknoid! 10 and 13 is great to know for me!

    Regarding 9 could you please explain, why using $uses is “bad practice”. I thought because of cake’s lazy binding, having a “User->Post->Comment->CommentRating” will instantiate all the models between, that I don’t need and makes it slower. Maybe I understand that wrong … ?

  • teknoid

    @Stefanski

    Just a couple of thoughts…

    – $uses is not MVC-like
    – related models are loaded regardless, so take advantage of it
    – $uses will load models before they are actually needed (and you probably don’t need those models in all actions), if anything I see ClassRegistriy::init(‘SomeModel’) as a better alternative.

  • Pingback: Reiten, Schwimmen, Lesen » Blog Archive » 15 Essential CakePHP Tips

  • Frank

    Hi, Thanks for the tips very interesting. Can someone please elaborate on 9.Avoid using $uses array?

    Why is this considered bad practise, or worse than digging through the objects you have loaded already for the object that you want?

    is it just an overhead?

  • teknoid

    @Frank

    It is definitely an overhead, which can and should be easily avoided.

    Why instantiate an object (and related objects), if they are already available?

  • Pingback: CakePHP dies und das : powerbook_blog

  • Pingback: Web by Booth » 15 helpful CakePHP tips, plus a few more.

  • Pingback: Jagatsingh.com » CakePHP Quick tips

  • Martin Westin

    I have not been able to get no.13 to generate correct urls using array notation.
    if I set the url to “/some_page.html” it loads the right page using pages.
    If I set the url to array(‘controller’=>’pages’,’action’=>’display’,’/some_page’) I get a link to /(./some_page/).html

    Looks like the regexp does not work correctly for reverse lookups. If anyone knows how (I suck at both the router and regexp) it would be great for me and this excellent list of tips.

    • http://blog.rodrigorm.com.br/ Rodrigo Moyle

      @martin If you use the array notation you dont need the “/” before the page, ex:

      array(‘controller’ => ’pages’, ‘action’ => ’display’, ‘some_page’)

  • http://teknoid.wordpress.com teknoid

    @Martin Westin

    No need to use array notation here. The array notation is useful if you decide to rename your controllers, then you won’t have to go through the code and modify all URL’s. In this case it’s not applicable.

  • Martin Westin

    @teknoid
    It is not needed but it could be useful if I decide to change from that route to another later on. And also if I wanted to write all your url in array notation, just because I am a neat-freak :)
    It is not a big deal, but since array notation seem to be the promoted way to write urls these days it would be a nice “bonus”.

  • http://teknoid.wordpress.com teknoid

    @Martin Westin

    I think you are misunderstanding the purpose of that particular route :)

  • Nathan Tyler

    Great post. A question on the vague area of $uses. I have some mostly static pages but want to pull images from a database so they can be changed out without modifying html. Problem is I can’t use $this->Image->find() because Image obviously isn’t loaded into the Pages controller. I’ve tried $uses which works but this is a terrible use of it since it loads it into every static page and not just the one I need it in. Suggestions welcomed

  • http://teknoid.wordpress.com teknoid

    @Nathan Tyler

    Thank you :)

    To load the model only when you need it, use ClassRegistry::init(‘ModelName’); (see API for details on how it works).
    That being said, if you need to use some model in static pages, add it to the pages controller (which handles the display of your static pages).

    All that being said, it’s OK to use $uses, if the model is really not available to access in any other way. What I’m recommending to avoid, is loading models with $uses, which are already available to access by using $this->User->Post->someMethod();, for example.

  • http://singletonio.blogspot.com tonio

    This helped me a lot! great read especially for people starting out with CakePHP. It’s always nice to read about some gotchas before hitting on them, so it won’t be frustrating ;)

  • http://teknoid.wordpress.com teknoid

    @tonio

    Thanks, glad it helped ;)

  • Pingback: Websites tagged "bugreport" on Postsaver

  • Sudarshan

    Thanks for the great Tips. I really love no. 9. I have been looking for this for ages.

  • http://teknoid.wordpress.com teknoid

    @Sudarshan

    Cool, glad you’ve found it helpful.

  • http://www.sizzlingshop.com Hetal Sagar

    Good one. Please give more about standard variable and convention.

  • http://teknoid.wordpress.com teknoid

    @Hetal Sagar

    The conventions are covered in the CakePHP manual: http://book.cakephp.org/view/22/CakePHP-Conventions

  • tm13

    Is it possible to use Sessions in static pages? It keeps telling me:

    Undefined property: View::$Session [APP\views\pages\home.ctp, line 8]

    I have declared Session in pages_controller in controller directory, not working. Any leads?

  • http://robwilkerson.org Rob Wilkerson

    @tm13 –

    If I understand your question correctly, yes. There is a session helper for views. Just use “$session->read ( ‘variableName’ )”. You shouldn’t have to declare it anywhere. IIRC, it’s included by default.

  • http://teknoid.wordpress.com teknoid

    @Rob Wilkerson

    Thanks for your response. It seems like the issue there was capital “$S” in “$Session”…

  • http://robwilkerson.org Rob Wilkerson

    @teknoid

    Yeah, I assume he was trying to reference the Session component rather than the session helper.

  • http://godine.in/ Harsha M V

    i added this from the Tip #10

    Am getting this error

    Warning: Unexpected character in input: ‘\’ (ASCII=92) state=1 in C:\Program Files\wamp\www\dine\app\app_helper.php on line 8

    Parse error: parse error in C:\Program Files\wamp\www\dine\app\app_helper.php on line 8

  • http://godine.in/ Harsha M V

    i added this from the Tip #10

    Am getting this error

    Warning: Unexpected character in input: ‘\’ (ASCII=92) state=1 in C:\Program Files\wamp\www\dine\app\app_helper.php on line 8

    Parse error: parse error in C:\Program Files\wamp\www\dine\app\app_helper.php on line 8

  • http://godine.in/ Harsha M V

    i added this from the Tip #10

    Am getting this error

    Warning: Unexpected character in input: ‘\’ (ASCII=92) state=1 in C:\Program Files\wamp\www\dine\app\app_helper.php on line 8

    Parse error: parse error in C:\Program Files\wamp\www\dine\app\app_helper.php on line 8

  • http://godine.in/ Harsha M V

    i added this from the Tip #10

    Am getting this error

    Warning: Unexpected character in input: ‘\’ (ASCII=92) state=1 in C:\Program Files\wamp\www\dine\app\app_helper.php on line 8

    Parse error: parse error in C:\Program Files\wamp\www\dine\app\app_helper.php on line 8

  • http://teknoid.wordpress.com teknoid

    @Harsha M V

    Those quotes look suspicious. It seems like wordpress double quotes are not parsing correctly, please try to manually replace them with ” on your keyboard.

    • http://godine.in/ Harsha M V

      Thanx mate for the tips. i used to everytime view source. copy to dreamweaver n see it :D
      saved a lot of time for me.

  • Pingback: Cakephp – Beautify Html Code Output | Black Sheep Designz

  • Pingback: links for 2009-11-19 » A Blue Star - Rantings from Steven smethurst

  • http://www.milestree.com/ Abhishek

    nice work dude….

    i am reading all cakephp guideline before i begin with my new projects

  • http://blog.rodrigorm.com.br/ Rodrigo Moyle

    Great tips!!

    On the tip 1 you can use an array to choose which fields you like to save and validate, eg:

    ->save($data, true, array(‘field_1′, ‘field_2′, ‘field_3′)

  • Pingback: 10 Essential Cakephp Tips « PHP Ocean

  • demophas3

    Ah, i think my question in your ‘Paginate associated model’s data in CakePHP’ articles was answered in the point 5. Hmm, I think… :(, not tried it yet. I let you know if it works thou…

  • Pingback: CakePHP (Разобрать) | Blog XEDRA

  • Shaz

    Quick question regarding $uses; I can’t access models that are linked to each other;

    Article [hasmany] Comment [hasmany] CommentRank
    CommentRank [belongsto] Comment [belongsto] Article

    I try to use $this->Article->Comments->CommentsRanks->read() but it results in “Undefined property: AppModel::$CommentsRanks”

    I’m trying to avoid the $uses, but I fear I may not have a choice; any advice would be greatly appreciated :)

    P.S. Great Post! Constantly refer to it when developing!

  • http://teknoid.wordpress.com teknoid

    @Shaz

    Based on the line of code you posted the model names are wrong. They should be singular (i.e. CommentsRank)

    • Shaz

      Thanks for the quick reply! Strangely enough it fails (Undefined property) when i use $this->Article->Comment (singular) but works when I use $this->Article->Comments. And then adding ->CommentRanks (or CommentRank or CommentsRanks or CommentsRank) fails alltogether. Might have something to do with the model relationships, but I think I’ve set them up fine…

  • http://teknoid.wordpress.com teknoid

    @Shaz

    Double check your class names and the names in the association. File names are also important, because if cake cannot find your model (i.e. comments.php vs comment.php) it will use AppModel instance.

  • Shaz

    Thanks for that, went back over the model/controller class declarations and managed to fix a few plurals that should have been singular; but to no avail. For now I’ve set recursive = 2 just so I can access everything from the original defined array; shall have a deeper look later.

  • ian

    Genius tip #1. Its been doing my head in for 3 hours trying to figure out why my data wasn’t saving.

  • Pingback: Tweets that mention 15 Essential CakePHP Tips | nuts and bolts of cakephp -- Topsy.com

  • Kenan

    For me cache deleting was the solution to my 3 day problem! Thanks for this nice post.

  • Diogo

    I’m trying to follow tip number 10, but Cake gives me the following error:
    Fatal error: Class ‘AppHelper’ not found in /Users/…/cake/libs/view/helpers/html.php

    Is the tip outdated? I’m using Cake 1.3.10.

    Thanks! :)

  • teknoid

    @Diogo

    Did you create and name the app_helper.php correctly?
    Did you create the right class?

    • Diogo

      Yes I did. I created it in the “app” folder, is that right?

      And I just copied and pasted the code. Did I have to do something else?

      Thanks for the answer!

    • Diogo

      Oops I needed to declare the class Apphelper. Totally forgot to do that. Thanks for the help! :D

    • Diogo

      Though the code didn’t change much. :(

  • http://rockersinfo.com php devloper

    nice tips and useful also… thanks for sharing

  • Pingback: cakephp, validate error - PHP Solutions - Developers Q & A

  • http://godine.in/ Harsha M V

    Thanx mate for the tips. i used to everytime view source. copy to dreamweaver n see it :D
    saved a lot of time for me.

  • http://godine.in/ Harsha M V

    Thanx mate for the tips. i used to everytime view source. copy to dreamweaver n see it :D
    saved a lot of time for me.

  • http://godine.in/ Harsha M V

    Thanx mate for the tips. i used to everytime view source. copy to dreamweaver n see it :D
    saved a lot of time for me.