- Website
- http://wavehack.net/
- Description
- WaveHack is a professional web developer from The Netherlands and the founder of Mineth Studios. He has a passion for (competitive online) gaming, has a predilection for Metroidvania-genre based games and is the author of the Metroid fangame Multitroid.
Extending the CodeIgniter Database Active Record class, the non-hacky way
The past few weeks I’ve been busy working with CodeIgniter. If you don’t know what CodeIgniter is, it’s basically a lightweight and open source PHP web application framework. If you’re working with PHP applications, I suggest you check it out.
One of the best features about CodeIgniter (besides being lightweight and open source) is that you can basically extend all the core classes and substitute them for your own. This makes it a highly customizable framework.
However, one core concept you cannot extend – according to the documentation, are the database classes. I wanted to extend the Active Record database class to include custom functions like insert_delayed() and insert_update() (‘INSERT INTO … ON DUPLICATE KEY UPDATE …’, see MySQL docs here). Previous attempts from other people required altering the system files (aka ‘hacking’), instead of the application files, which is ugly and doesn’t last across framework updates.
However, thanks to the articles I found here and here, I came up with my own solution.
This extension requires 1) a custom Loader class, 2) a custom DB function and 3) a custom DB_active_record class. Using our custom Loader, we load our custom DB function, which in turn is used to load our custom DB_active_record class. Simple, no?
application/core/MY_Loader.php
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); class MY_Loader extends CI_Loader { public function database($params = '', $return = FALSE, $active_record = NULL) { // Grab the super object $CI =& get_instance(); // Do we even need to load the database class? if (class_exists('CI_DB') AND $return == FALSE AND $active_record == NULL AND isset($CI->db) AND is_object($CI->db)) { return FALSE; } // Check if custom DB file exists, else include core one if (file_exists(APPPATH.'core/'.config_item('subclass_prefix').'DB'.EXT)) { require_once(APPPATH.'core/'.config_item('subclass_prefix').'DB'.EXT); } else { require_once(BASEPATH.'database/DB'.EXT); } if ($return === TRUE) { return DB($params, $active_record); } // Initialize the db variable. Needed to prevent // reference errors with some configurations $CI->db = ''; // Load the DB class $CI->db =& DB($params, $active_record); } } /* End of file MY_Loader.php */ /* Location: ./application/core/MY_Loader.php */
Copy the contents from system/database/DB.php to application/core/MY_DB.php and look for the following:
require_once(BASEPATH.'database/DB_driver'.EXT); if ( ! isset($active_record) OR $active_record == TRUE) { require_once(BASEPATH.'database/DB_active_rec'.EXT); if ( ! class_exists('CI_DB')) { eval('class CI_DB extends CI_DB_active_record { }'); } }
Change it to the following:
require_once(BASEPATH.'database/DB_driver'.EXT); if ( ! isset($active_record) OR $active_record == TRUE) { require_once(BASEPATH.'database/DB_active_rec'.EXT); // get the CI instance $CI = & get_instance(); $prefix = $CI->config->item('subclass_prefix'); if (file_exists(APPPATH.'core/'.$prefix.'DB_active_rec'.EXT)) { require_once(APPPATH.'core/'.$prefix.'DB_active_rec'.EXT); if ( ! class_exists('CI_DB')) { eval('class CI_DB extends '.$prefix.'DB_active_record { }'); } } else { if ( ! class_exists('CI_DB')) { eval('class CI_DB extends CI_DB_active_record { }'); } } }
(Thanks to robotslacker.com for the article on this one.)
Then, create your application/core/MY_DB_active_rec.php file:
<?php if (!defined('BASEPATH')) exit('No direct script access allowed'); class MY_DB_active_record extends CI_DB_active_record { public function foo() { echo 'foobar'; } } /* End of file MY_DB_active_rec.php */ /* Location: ./application/core/MY_DB_active_rec.php */
And there you have it. A custom CodeIgniter active record database class, the non-hacky way.
Once I come up with some good functions for ‘INSERT DELAYED’ and ‘INSERT INTO … ON DUPLICATE KEY UPDATE …’, I’ll post them.

