Cakephp important facts you must know – Part 1

Mininal use of $uses variable to load models
CakePHP loads all models specified in var $uses array when a controller action is called. By loading a model cakephp creates the schema/structure of the table and also caches it for further use in the application.

Let say you specify four models in the var $uses. Now every time you call a controller action, all four models will be loaded irrespective of any of four being used by controller action or not. For example, you need only ‘User’ model inside your login() action. But as per the var $uses you had defined, other three models loaded are useless and add to slowing down of login process.

To avoid this, just call the model you need inside the controller action using :
App::import(‘model’,’User’);
$this->User = new User();

Use of mysql function inside model queries
As usual we can pass the mysql function calls as we do in normal sql queries: For example:

$this->Model->field('SUM(length)',"id = 2");

Binding models permanently
As we know we can bind a model on fly and the loaded model is unbinded automatically after a single query. In addition, we can pass a second argument ($reset = true) to bindModel() method making the binding permanent until it encounters a unbind call or the execution reaches an end.

Saving single field or selected fields
We can save a single field using:

$this->Model->saveField('field_name',$saveValue);

In general, saving data using $this->Model->save() call cakephp inserts/update all table fields available in the $this->data[‘Model’] data set. To make the save selective we can pass $fieldList as a third argument to save() function. For example:

$this->Model->save($this->data,true,$fieldsToSave);

where fieldsToSave contains an array of fields which will be save.

White list and blacklist for save() funtion
Furthermore, it may it may look tedious to mention all fields excepting a less number of fields. To do this we can pass a blacklist to a small chunk of code which in return would pass required white list to the save function. For example:

$blackList = array('protected', 'fields', 'here');  
$this->Model->save($this->data, true, array_diff(array_keys($this-> Model->schema()), $blackList);

Thanks to post Don’t change the meaning of parameters by cakebaker and Blacklist your model fields for save()… by teknoid

Use of Router::url
This useful function can be used to get url inside controller or component class. Router::url() will print a combination of controller and action. Router::url(‘/’) will print the root url of your cakephp application. Router::url(null,true) will print full url. See function url() in cake/libs/router.php for more details.

Easily creating static pages
You don’t need to create a controller action every time you want to add a new static page. For example, if you want to create a static page with “about us” content just create a view about_us.ctp inside views/pages directory and call if like http://yoursite/pages/about_us. Just keep note that you don’t have any pages_controller.php in your app/controllers directory. You also have to modify the cake/libs/views/layouts/default.ctp layout file to suit your site content.

Skipping model validation on save() call
While saving data by using $this->Model->save() method we can instruct whether or not to run a validation on the data set. The save($data, $validate, $fieldList) method have two optional parameters $validate and $fieldList where true/false $validate refer to yes/no to validations.

Skipping foreign key matching while binding model
If you bind a model to another model it performs the joins based on foreignkey. For example, for “id” in users table it relates it to “user_id” in profile table. Now what, if you want to bind Profile table to Comments table where user id is stored as in profiles table i.e. “user_id” only. Simply put in conditions Profile.user_id = Comment.user_id and foreign key=’0’. ‘’ around is vital here as it too more that two hours to find it out.
Example:

$this->AlbumSong->bindModel(array('belongsTo' =>array("Album", "Song", "Artist"=>array("foreignKey"=>"0"))), false);
$this->paginate = array('limit' => 20,"conditions"=>"Artist.id=Song.artist_id");
$this->set('album_songs',$this->paginate('AlbumSong',"Album.id=$album_id"));

Inserting multiple rows in a go
In one of my projects i had to save() multiple rows inside my controller function. The function code looked something like this:

function somename() {
//some lines of code...
    foreach($dataset as $row) {
       // "$row" contains and array of  $row['team_a'],$row['team_b'],$row['result'] strings
       $this->Model->save($row);
    }
}

Everything in the code looked correct. When calling the function, it saved only one row of data and that last one. After a bit of digging i found that after calling save() it stored last inserted “id” into $this->Model->id. In other words, after the first call to save() it stored first inserted “id” to $this->Model->id and kept updating that row in next calls. To avoid this i just added $this->Model->id = null; after $this->Model->save($row); and it worked like a charm!

Use of name attribute in ajax form element
In cake 1.2.x when using $ajax->form() creation element, it does not accepts “name” attribute. A simple hack to this issues is to place name attribute as normal and replace “unset($htmlOptions[$key]);” near 328 lines in ajax.php helper with “if($key!=”name”) unset($htmlOptions[$key]);”.

We can get sum, average etc. by using field function as sum(field) etc. EX:

2 thoughts on “Cakephp important facts you must know – Part 1

  1. My version of cakephp must be different to yours above, with regards to the “Use of name attribute in ajax form element”, I don’t actually have a line saying unset($htmlOptions[$key]); Instead, what I have done is add the following immediately after the $htmlDefaults array found around line 327:

    if(!empty($options[‘name’])) {$htmlDefaults[‘name’] = $options[‘name’];}

    This simply adds the name to the array of html defaults to be output. :)

Leave a Reply