Using CakePHP in external PHP Systems (CMS's, Weblogs, etc.)

Posted by Felix Geisendörfer, on May 04, 2006 - in PHP & CakePHP » Core & Hacking

Deprecated post

The authors of this post have marked it as deprecated. This means the information displayed is most likely outdated, inaccurate, boring or a combination of all three.

Policy: We never delete deprecated posts, but they are not listed in our categories or show up in the search anymore.

Comments: You can continue to leave comments on this post, but please consult Google or our search first if you want to get an answer ; ).

Well CakePHP is a great PHP framework, in fact I think it is the best. But sometimes even that isn't good enough for keeping up with this really tight deadlines one might have. In those cases I tend to go with other OS systems that are already close to what I need. For now that's mostly been Drupal, but I'm also thinking about doing the same thing with WordPress on this site.

Now one might wonder what's the best way to utilize the powers of cakephp in those projects for getting the customization done as fast as possible. Now that I've tried a couple of approaches to do so (an earlier PoC can be seen here), mostly keeping the two systems in seperate folders and using customized .htaccess files to get the the two systems connected.

But today I started to work on a little bit on my Drake project again and found an even better way to go. With better I don't neccessary mean the "cakephp right way", but one that required very little code and is easy to maintain, which is my criteria.

I'll explain what I did for Drupal (and it should be just about 99% the same for any other system):

Where to put the foreign system?

Technically it would be a vendor, so one might think that's a good place to put it. But in most cases this won't work because parts of the foreign system will need to be accessible by the browser of the client. You could use .htaccess to do that, but you'd only make another folder useless that way, the webroot folder. And that's the place I decided to try out today.

Just take the whole foreign app (drupal for me) and paste it into cakephp's app/webroot folder. Now the other app is likely to already provide it's own .htacess as well as index.php. You should rename the cakephp index.php to cakephp.php before and overwrite the cakephp .htaccess one of the foreign system. Now you should be able to access the foreign system just like you would access you cakephp app normally.

How to use CakePHP in the foreign system

Now open up the cakephp.php (the original index.php of app/webroot) and comment out the following lines at the end of the file like this:

php
  1. if(isset($_GET['url']) && $_GET['url'] === 'favicon.ico')
  2. {
  3. }
  4. else
  5. {
  6. /*    $Dispatcher= new Dispatcher ();
  7.     $Dispatcher->dispatch($url);*/
  8. }

Now you can include CakePHP via require_once() in the foreign system without a page beeing directly rendered. We want it like this because that makes it possible to do as many 'requestActions' inside drupal/wordpress/whatever as you need, which is essential to fully use cakephp in those apps. Now all you need is a function called requestCakePHP() in your foreign system in order to retrieve data produced by CakePHP. This is the one I've come up with:

php
  1. function requestCakePHP($url)
  2. {            
  3.     // Sessions are done by Drupal, don't use CakePHP built in ones
  4.     if (!defined('AUTO_SESSION'))
  5.         define('AUTO_SESSION', false);
  6.  
  7.     // Set the url parameter for cakephp
  8.     $_GET['url'] = $url;
  9.    
  10.     require_once 'cakephp.php';
  11.  
  12.     // We only need this to tell the name of the database we want to use,
  13.     // user/pass can be left blank for that reason.
  14.     if (!class_exists('DATABASE_CONFIG'))
  15.     {
  16.         eval("class DATABASE_CONFIG
  17.             {
  18.                 var \$default = array('driver'    => 'mysql',
  19.                                      'connect'  => 'drupal_connection',
  20.                                      'host'     => 'localhost',
  21.                                      'login'    => 'root',
  22.                                      'password' => '',
  23.                                      'database' => 'drake',
  24.                                      'prefix'    => '');
  25.             }");
  26.     }
  27.  
  28.     // Fire up CakePHP and buffer results
  29.     ob_start();    
  30.     $Dispatcher= new Dispatcher ();
  31.     $Dispatcher->dispatch($url);        
  32.    
  33.     return ob_get_clean();
  34. }
  35.  
  36. function &drupal_connection()
  37. {
  38.     // CakePHP expects this function to return a database connection, this is the one Drupal uses
  39.     global $active_db;    
  40.     return $active_db;
  41. }

Now most of this code just takes care of making sure that cakephp uses the same database as the foreign app and does NOT try to reconnect to it. The rest of the code should be fairly easy to understand.

The only thing you need to do now is to tell your foreign app to use requestCakePHP() for content retrieval when the system itself doesn't know how to handle a path. For Drupal this would be:

php
  1. function drake_init()
  2. {
  3.    variable_set('site_404', 'drake');
  4. }
  5.  
  6.  
  7. function drake_menu($may_cache) {
  8.   $items = array();
  9.  
  10.     $items[] = array('path' => 'drake',
  11.       'title' => t('Drake'), 'access' => true,
  12.       'callback' => 'requestCakePHP', 'type' => MENU_CALLBACK,
  13.       'callback arguments' => array($_GET['q']));
  14.  
  15.   return $items;
  16. }

That's it! And as you can see it's really something that should work with almost any other php application. The only thing you need to hope for is, that the other application doesn't provide functions with the same name as cakephp does inside basics.php. But since cakephp mostly uses classes for it's stuff luck should be on your side.

I hope I'll be able to release my Drake code (that's based on this new solution) soon, I'll write a blog post as soon as it's done.

--Felix Geisendörfer aka the_undefined