Tag: CakePHP

SmartRedirect Plugin for CakePHP

When adding, editing, or deleting records in a web application, it is common to return the user to where they originated. That is what they typically expect. The SmartRedirect plugin allows just that, without any coding in your models, controllers, or views.

You can grab the plugin using git or by zip from the SmartRedirect Plugin project page on GitHub.

All you need to do is extract the file and drop the smart_redirect folder into your app/plugins directory. After that, add SmartRedirect.AutoReturn to your components list. Something like this:

var $components = array('SmartRedirect.AutoReturn');

Now when you add, edit, or delete records in your application, you’ll be returned to the page you were on before.

The plugin does use a custom view, so may conflict with other plugins such as Debug Kit.

Reusing controller views in CakePHP

CakePHP makes it easy to reuse your small blocks of presentation code throughout your application by using Elements. You can read more about them here:

http://book.cakephp.org/view/97/Elements

Sometimes though you want to reuse a regular controller view without moving the code to an element. In fact, if the view code is specific to the controller, it is good practice to keep it in the controller view.

Fortunately this is fairly simple. Just create the view and then reference it like this:

<?php echo $this->element('../projects/menu'); ?>

In the example above, I’m accessing the following file: /views/projects/menu.ctp

As always, the element will have access to all existing view variables (the ones typically passed using $this->set()).

CakePHP: One core, many apps

CakePHP allows you to use one set of core files while maintaining multiple applications. It only takes a few steps, but may not be completely straightforward the first time you try. In my example, I have my workspace in ~/dev. I would setup my project in ~/dev/client_name/project_name. I place my cake core files in separate folders for each version in ~/dev/lib/cakephp.

The basics

  1. Download and install the latest version of CakePHP in a good location.
    Examples:
    • Linux: /usr/lib/cakephp/cake_1.2.2.8120
    • Windows: C:\lib\cakephp\cake_1.2.2.8120
  2. Copy the contents of the app folder to your project root. This is typically your webserver root or a folder within.
  3. Edit the following constants in webroot/index.php:
    1. ROOT
      You’ll want to change it so the root is one level back (your project root)
      	if (!defined('ROOT')) {
      		define('ROOT', dirname(dirname(__FILE__)));
      	}
      
    2. APP_DIR
      This one just gets set to blank since your root is also your app folder
      	if (!defined('APP_DIR')) {
      		define('APP_DIR', '');
      	}
      
    3. CAKE_CORE_INCLUDE_PATH
      Set the path to your cake core files. This can either be relative (../../core) or absolute (/path/to/core)
      	if (!defined('CAKE_CORE_INCLUDE_PATH')) {
      		define('CAKE_CORE_INCLUDE_PATH', '..'.DS.'..'.DS.'..'.DS.'lib'.DS.'cakephp'.DS.'cake_1.2.2.8120');
      	}
      

      or

      	if (!defined('CAKE_CORE_INCLUDE_PATH')) {
      		define('CAKE_CORE_INCLUDE_PATH', DS.'usr'.DS.'lib'.DS.'cakephp'.DS.'cake_1.2.2.8120');
      	}
      

It may take a little work to get the paths right, but it is well worth it. If you try to access your project and you get PHP errors, it probably means something is wrong with the core path above. The next project you start, just copy the app folder again as above, and copy the same index.php into any new projects you start.

Different paths for dev and live
The above example only covers one server configuration. Some developers may be developing in Windows while their production server runs Linux. In that case you will need to account for each server. A simple if/else statement will take care of this. In my case, I have “localdev” as the hostname for my local development server. Here is what my CAKE_CORE_INCLUDE_PATH configuration looks like:

	if (!defined('CAKE_CORE_INCLUDE_PATH')) {
		if ($_SERVER['SERVER_NAME'] == 'localdev') {
			define('CAKE_CORE_INCLUDE_PATH', '..'.DS.'..'.DS.'..'.DS.'lib'.DS.'cakephp'.DS.'cake_1.2.2.8120');
		} else {
			define('CAKE_CORE_INCLUDE_PATH', DS.'usr'.DS.'lib'.DS.'cakephp'.DS.'cake_1.2.2.8120');
		}
	}

Upgrading CakePHP
Upgrading CakePHP is pretty easy. Just install the latest version of CakePHP as described above. Then when you are ready to upgrade your app, change the core path again and start testing. If you run into issues with the latest version, it is really easy to switch back.

Letting multiple CakePHP apps talk

CakePHP is getting really popular, so naturally, there are quite a few sites out there using it. If you’ve been using CakePHP long enough, sooner or later you will want to have 2 or more of those apps talk to each other. Setting CakePHP up to act as a webservice is pretty easy. Teaching the other apps to talk to that webservice takes a little more work. Jesse (over at TechnoGeeks) and I have been working on just that.

So far we have one app authenticating against the other. This can be very useful if you have a central user database, and don’t want to maintain users across every application you create. We used XML as the transport, so this could easily be used for applications that aren’t written in CakePHP. You can get all the details in Jesse’s article: Authenticating a CakePHP App Against a CakePHP Webservice.

We hope to extend it and allow standardized CRUD functionality across the applications. During that time, we may move the code into a datasource. But who knows.

Speeding up count queries with counterCache

Today while working in a CakePHP application, I needed to hide some records based on the number of associated records they had. I basically needed to get a count of associated records. Fortunately, CakePHP has a feature called counterCache that makes this really easy. It saves the record count in the database and updates the count any time you do a save or delete. The details can be found here:  http://book.cakephp.org/view/490/counterCache-Cache-your-count

Basically you do the following:

  1. Create an INT field on the parent table called <childmodelname>_count
  2. In the $belongsTo array of the child model, add “‘counterCache’ => true” to the parent array
  3. Enjoy!

This works great for new installations. However, if you want to add it to an existing site, you’ll need to run through all the records and save the current count. Here is a sample method for doing just that.

function admin_update_counters() {
$this->Category->recursive = 0;
$categories = $this->Category->find('all');
foreach ($categories as $category) {
$question_count = $this->Category->Question->find('count', array('conditions' => array('Question.category_id' => $category['Category']['id'])));
if ($question_count) {
$this->Category->create();
$this->Category->id = $category['Category']['id'];
$this->Category->saveField('question_count', $question_count);
}
}

echo "Counters updated"; exit;
}