LazyModel plugin Used to build CakePHP model chains when then they are actually used. This COULD increase the speed of your application and decrease it's memory usage significantly. It will be done fully transparent and will take only a single line of code in your application. Facts: - 100% compatible with CakePHP 1.2 and 1.3 (all model core tests pass). - Works on PHP 5.2 and 5.3. - Only loads models when they are needed. - Works fine with Containable and OneQuery (and probably Linkable). Setup: 1. Clone the plugin to your APP/plugins directory (or as a git submodule in that folder). 2. Put the following code in APP/app_model.php: <?php App::import('Lib', 'LazyModel.LazyModel'); class AppModel extends LazyModel { } ?> 3. See the magic happen. Q&A: Q: I have this page and it isn't really faster, doesn't it work? A: It probably does, but the speed increase can vary a lot. The more models and associations you have and the less you use them, the higher the speed increase will be. If you use every model, they will be instantiated just like CakePHP itself would do. Therefor it is important to use Containable or any other behavior that limits the number of models that is used. Using 'recursive' isn't advised. Q: What were you thinking when you made a Model as a Lib? A: This is by design. When importing a Model using App::import() CakePHP will automagically load AppModel for you. This is fine when loading a normal model, but if you want to apply this model to AppModel it will be causing an endless loop. This Model essentially is designed to be applied on every model and therefore implemented as a Lib. (See: http://github.com/cakephp/cakephp/blob/1.3/cake/libs/configure.php#L1154) The libs folder was introduced in CakePHP 1.3, but it was already possible to use Libs in CakePHP 1.2. It all boils down to some Inflector magic which was implemented earlier. Q: My HABTM isn't completely lazy loaded, is this a bug? A: No, full lazy loading for HABTM never works, because CakePHP needs to fill all sorts of settings in the associations and it needs at least the join model for that. You can optimize this though. It will be only half loaded when you set the 'with', 'associationForeignKey' and 'joinTable' keys in your HABTM association. In this case CakePHP will only load the join model. See the test cases for details on how to set it up. You will notice it will make a bit of a mess. So I suggest you only do this when you really need to. It is probably not even worth it. Another way to speed up HABTM is to not use it at all. You can split things up as hasMany and belongsTo associations. More on this can be found in the book under heading "What to do when HABTM becomes complicated?". (See: http://book.cakephp.org/view/1034/Saving-Related-Model-Data-HABTM) Q: ACL breaks on CakePHP 1.2, is this a bug? A: Yes, but not one of this plugin. It has to do with the PHP4 compatibility of CakePHP. The problem is fixed in CakePHP 1.3 though. So if you can, upgrade fast! If you can't, just copy the ACL behavior to your application, find the line of the problem (see the error) which says: $model->{$type} =& ClassRegistry::init($type); Change it to: if (PHP5) { $model->{$type} = ClassRegistry::init($type); } else { $model->{$type} =& ClassRegistry::init($type); } This will get rid of the error. Q: When I use Model::deleteAll() on a 'with' model with only two fields directly, where the 'with' model is the primary model of the Controller, CakePHP still wants to delete records using the 'id' field. It used to work before. What can I do? A: Because CakePHP creates the models all at once by default, the primary key is set to one of the foreign IDs through the association of the parent HABTM model. LazyModel prevents the loading of those models, so the primary key isn't set. I tried to fix this, but it is unfixable without loading the other models first. There is a simple way to make it work though. Set the primary key to the right field before calling Model::deleteAll() like this: $this->Model->primaryKey = 'foreign_id'; $this->Model->deleteAll(array('foreign_id' => $id, 'other_foreign_id' => $fid)); This doesn't mean you always need to set the primary key before calling Model::deleteAll(). It only needs to be done in this specific case. Q: Hey, the 'required' classes in my forms are gone! Can I fix this? A: Duuh! The FormHelper checks whether a Model is set in the ClassRegistry or not and if it is, it will check the validation rules if it needs to add the 'required' class somewhere. So the reason the classes are gone is because the Models aren't in the ClassRegistry anymore. Fixing this is quite easy. Just call the Models you use in your action like this: public function admin_add() { $this->Model->AssociatedModel; $this->Model->OtherAssociatedModel; // Some data checking and saving. } This will instantiate the Models and place them in the ClassRegistry. Of course this will make the action slightly slower and bigger, but (in my opinion) it will still beat loading the entire model chain. Q: What the hell?! My form had a checkbox/textarea/whatever for a specific datatype and with LazyModel it has become just another text input. Where did it go? A: This issue is related to the previous one and can be fixed the same way. You can also add 'type' => 'textarea' to the options of FormHelper::input() for example to fix it. Q: Was this your own idea? A: Not really, there are more tries at this, but I couldn't really make them work like I had in mind and so started my own little project using a slightly different approach. However, I used the other attempts by Matt Curry and José Lorenzo Rodríguez as inspiration. (See: http://github.com/mcurry/lazy_loader/) (See: http://github.com/lorenzo/lazy_loader/) (See: http://bin.cakephp.org/saved/39855/)