Wednesday, March 19, 2008

Using Helpers in a Controller

For some very SPECIAL cases, you may want to use helpers in your controller. How to use them? Here is a simple code snippet below (copied from Daniel Hofstetter's blog 'How to use a helper in a controller' http://cakebaker.42dh.com/2007/08/09/how-to-use-a-helper-in-a-controller/).

class UsersController extends AppController {
function index() {
loadHelper('Html');
$html = new HtmlHelper();
debug($html->link('Cake!', 'http://cakephp.org'));
}
}

It works pretty well for most simple helpers. For some complex helpers, however, this is not sufficient. For example, helper Ajax uses helpers Html, Javascript, and Form. If you just write your code as above, you will get fatal errors, saying call a member function on a non-object, from the Ajax helper file /cake/libs/view/helpers/ajax.php. After tracing the code, I found the line in ajax.php is like below,

$this->Javascript->codeBlock($code);


To fix this, I wrote a function loadHelper() to the call AppController. This function also wraps the statement of instantiating the new helper object.


class AppController extends Controller {

function &loadHelper($helper_name) {

loadHelper($helper_name);

$helper_class_name = $helper_name.'Helper';

$helper = new $helper_class_name();

if (isset($helper->helpers) && !empty($helper->helpers)) {

foreach ($helper->helpers as $external_helper) {

$helper->$external_helper =&

$this->loadHelper($external_helper);

}

}

return $helper;

}

}

In the controller using helpers, you may use the below code to load the helper,

$ajax =& $this->loadHelper('Ajax');

and then use the variable $ajax as in views.


At last, using helpers in controllers should be the last choice since it violates the basic rules of MVC.


Thursday, March 13, 2008

Practices of Advanced Setup for CakePHP Applications

This article is for the cases that your web hosting server does not give you enough permissions to set up your CakePHP application as the simple 'Production Setup' discussed in the chapter 'Installing CakePHP' of CakePHP Manual (url: http://manual.cakephp.org/chapter/installing) or you have multiple CakePHP applications under single web hosting plan (or account) or under a single domain.

Before I start, please note that there are five places, which have both the files .htaccess and index.php. In the default structure of CakePHP package, they are /, /app, /app/webroot, and another two places (they are folders under the sub folder of /cake but they are not related to this topic. In folders / and /app, the files .htaccess and index.php have the same function, redirecting the requests to the folder webroot. The difference is that file .htaccess is for the case applying mod rewrite and the file index.php is for the case not applying mod rewrite. However, they are not useful for advanced setup. We will only concern the two files, .htaccess and index.php, under /app/webroot and every time mentioned below refer to them.

Suppose in your web hosting account you have two domains, site_a.com and site_b.net, which are developed using CakePHP and you want them to share the same CakePHP library functions. The directory structure may be like as the followings,
  • /.../www/ is the root directory of your account,
  • /.../www/site_a.com/ is the document root of domain site_a.com, and
  • /.../www/site_b.net/ is the document root of domain site_b.net.
To apply the advanced setup of CakePHP, you may add three folders under www as the followings,
  • /.../www/cakephp_lib/ is the folder where place CakePHP library functions under cake,
  • /.../www/site_a_app/ is to place the files under app for site_a.com, and
  • /.../www/site_b_app/ is to place the files under app for site_b.net.
Now let me describe the procedures step by step. Suppose your web hosting directory is set well and you got a fresh and extracted copy of CakePHP, for example cake_1.2 on your local machine. Using FTP client software, you may process the following steps to deploy,
  1. upload all folders and files under cake_1.2/app/webroot/ to site_a.com/ and site_b.net/, respectively, (here I omit /.../www/ for easy reading)
  2. remove the folder cake_1.2/app/webroot and its files and sub folders,
  3. upload the whole folder cake_1.2/app/ to site_a_app/ and site_b_app/, respectively,
  4. remove the folder cake_1.2/app and its files and sub folders,
  5. upload all folders and files left in the folder cake_1.2/ to cakephp_lib/, and
  6. remove the folder cake_1.2 for clean up.
The next step is to make the two sites ready to use by modifying the files index.php and/or .htaccess. Before modifying the files, you may understand three important constants defined for a cake application. They are ROOT, APP_DIR, CAKE_CORE_INCLUDE_PATH and the meanings of them are:
  • ROOT: the path of the root directory of the application files,
  • APP_DIR: the directory name which includes the application files under the ROOT directory, and
  • CAKE_CORE_INCLUDE_PATH: the path of the directory that includes the cake libraries.
So the values of these three constants for site_a.com are:
  • ROOT: /.../www/site_a_app,
  • APP_DIR: app, and
  • CAKE_CORE_INCLUDE_PATH: /.../www/cakephp_lib.
and the values for site_b.net are:
  • ROOT: /.../www/site_b_app,
  • APP_DIR: app, and
  • CAKE_CORE_INCLUDE_PATH: /.../www/cakephp_lib.
To ease the implementation, we may define /.../www/ as a constant, ADVANCED_CAKE_DOCUMENT_ROOT.

The code for site_a.com after removing all comments is as the following (suppose the document root is /101010/www/),

define('ADVANCED_CAKE_DOCUMENT_ROOT', DS.'101010'.DS.'www');

if (!defined('ROOT')) {
define('ROOT', ADVANCED_CAKE_DOCUMENT_ROOT.DS.'site_a_app');
}

if (!defined('APP_DIR')) {
define('APP_DIR', 'app');
}

if (!defined('CAKE_CORE_INCLUDE_PATH')) {
define('CAKE_CORE_INCLUDE_PATH',
ADVANCED_CAKE_DOCUMENT_ROOT.DS.'cakephp_lib');
}


If you still get an error with a message like "The requested URL /.../www.site_a.com/index.php was not found on this server.", you may add
RewriteBase /
to the file .htaccess.