Archive: July, 2011

Setup debugging for Netbeans + CakePHP

Update (7/22/2011): dogmatic69 pointed out that you can do the same with Chrome by installing the xdebug extension. See his comment for details.

For all the Netbeans users out there, if you don’t have debugging enabled, this little “how-to” should get you stared pretty easily.

First prerequisite is to make sure you have xdebug installed and enabled for PHP.

In the php.ini you should have the following settings:

xdebug.remote_enable=1
xdebug.remote_mode="req"
xdebug.remote_handler="dbgp"
xdebug.remote_host="localhost" #or try 0.0.0.0
xdebug.remote_port=9000

Make sure that the xdebug extension is enabled, of course.
(Under the [XDebug] section of php.ini, zend_extension=[path to your php_xdebug lib]).
Don’t forget to restart your web server ;)

Next we’ll install the Netbeans Fire Fox add-on.
It can be downloaded from here: https://addons.mozilla.org/en-US/firefox/addon/easy-xdebug/
As you can guess this means that FF should be your default browser, because it will need to open up once you start running the debugger.

Let’s switch to Netbeans, right click on the app of interest and navigate to “Properties”.
In the project properties window select “Run configuration”.
Project URL: http://yourhost.example.local/ (the local host name from which your app is running).
Index File: index.php (easy enough).

Double check some options in Netbeans…
Tools -> Options -> PHP tab
“PHP Interpreter” should point to the correct location of your PHP executable.
“Debugger Port” should be the same as the setting in your php.ini (xdebug.remote_port=9000)
You might want to “uncheck” the “Stop at First Line” box.

This should be it, as far as the setup goes…

You can now run a quick test:
Open app/webroot/index.php.
Add a breakpoint at some line.
(You might want to add xdebug_break(); at the bottom of the file, just to be sure).
Hit Ctrl+F5 (or whatever is the command on your OS to debug the project).

If all goes well FF should open up and you should see the code execution stop at the line where you’ve set the breakpont with some debug info in the Netbeans console.
Congrats!

p.s. Setting up other IDE’s should be similar in the overall approach… but, as always, your mileage may vary.

Offload read queries to a replica DB for better performance

In most web application, which require a lot of find()’s especially if more than a couple of models are involved, you should probably consider offloading those operations to read-only replica of your DB. This is typically achieved by having a master/slave or master/master configuration. In high traffic application you might have a cluster of databases, but for the purpose of this example we’ll only use two data sources: “default” and “replica”.

Therefore our basic database.php will look something like this:

public $default = array(
    'driver' => 'mysql',
    'persistent' => false,
    'host' => 'production.example.com',
    'login' => 'user',
    'password' => 'password',
    'database' => 'production',
    'prefix' => '',
    'encoding' => 'utf8'
  );
 
  public $replica = array(
    'driver' => 'mysql',
    'persistent' => false,
    'host' => 'readonly.example.com',
    'login' => 'user',
    'password' => 'password',
    'database' => 'readonly',
    'prefix' => '',
    'encoding' => 'utf8'
  );

This prepares our application to use two data sources, as needed.

Next, let’s imagine we have a good ol’ blog and need to grab various information to build a list of posts.
In our Posts Controller, we’ll have some method that gets the required information:

$this->Post->getListofPosts();

The method above will have to involve additional models to get all of the needed info (Author, Tag, (PostsTag for the join table), PostRating… and maybe a few other models). The point is that this is enough operations already to consider offloading them to our read-only DB server.

The actual process is quite simple.
First, we’ll create a generic method in our App Model:

protected function _switchDataSource($models, $datasource = 'default') {
    if (is_array($models)) {
      foreach ($models as $model) {      
        ClassRegistry::init($model)->setDataSource($datasource);
      }
    }
  }

I hope this code is simple enough, but the implementation example is coming up…
It’s worth to note that ClassRegistry::init() will cache your model information (object instance, to be more precise) in memory, therefore in a more complex case (where you might have multiple find()’s) the newly switched data source will persist until switched back. Therefore it is important to remember to “reset” your data source once you are done with the read operation(s).

Now, here’s the basic usage sample (this snippet would be inside of our getListofPosts() method):

//let's switch our DS to replica
$this->_switchDataSource(array(
  'Post', 'PostsTag', 'Author', 'PostRating'
), 'replica');

//now we can execute our find with all of the above
//model data coming from the read-only DB
$posts = $this->find('all', array(
  'contain' => array(
  //include our models here
  ),
  'limit' => 35
));

//don't forget to switch the DS back to default
$this->_switchDataSource(array(
  'Post', 'PostsTag', 'Author', 'PostRating'
));

return $posts;

As you see the implementation is pretty simple. The only thing to keep in mind is that if you are getting some SQL errors, chances are you have not included all of the required models for the operation, the most common case is forgetting the join table model. To troubleshoot and see the results the debug kit is very helpful, because it will show you which data source is being used to run a particular set of queries.
Another hint, if you use the same set of models over and over you might as well assign them to a property in your model, so that if you need to add or change something you’d only do it in one place.
Using our example we can modify the code like so:

public $postQueryModels = array('Post', 'PostsTag', 'Author', 'PostRating');

....

$this->_switchDataSource($this->postQueryModels, 'replica');