Hi Derek,
I whipped this up in an afternoon, so I imagine there are some bugs in it, but this is what I’ve got:
These modifications make CI look for libraries in the following places (based on a config setting ‘custom_lib_path’):
* APPPATH/libraries/$custom_lib_path/
* APPPATH/libraries/
* BASEPATH/libraries/$custom_lib_path/
* BASEPATH/libraries/
You can put either complete classes (core library replacement) or subclasses in any of the directories along the way, and the first one found in each location will be used.
I added this function in codeigniter/Common.php:
function i3_load_class($class) {
// Get the class name
$class = str_replace(EXT, '', $class);
$prefix = config_item('subclass_prefix');
$paths = array(APPPATH, BASEPATH);
$dirs = array(config_item('custom_lib_path'), 'libraries/');
$base_file = FALSE;
// We'll test for both lowercase and capitalized versions of the file name
foreach (array(ucfirst($class), strtolower($class)) as $class)
{
$has_subclass = FALSE; // will be true if we are including a class extension
$is_duplicate = FALSE; // will be true if class is already loaded
foreach (array($class, $prefix.$class) as $cur_class)
{
foreach ($paths as $path)
{
foreach ($dirs as $dir)
{
$file = $path.$dir.$cur_class.EXT;
if (file_exists($file))
{
// make sure path is absolute so we can compare to get_included_files()
$file = realpath($file);
if (in_array($file, get_included_files()))
{
$is_duplicate = TRUE;
// break foreach (array($class, $prefix.$class) as $cur_class)
break 3;
}
else
{
include($file);
}
if ($cur_class == $prefix.$class) // class extension?
{
$has_subclass = TRUE;
}
else // no, it's a base class instead
{
$base_file = $file;
}
break 2; // break foreach ($paths as $path)
}
}
}
}
if ($base_file || $has_subclass || $is_duplicate)
{
break;
}
}
return array($base_file, $has_subclass, $is_duplicate);
}
and then changed load_class() in the same file:
function &load_class($class, $instantiate = TRUE)
{
static $objects = array();
// Does the class exist? If so, we're done...
if (isset($objects[$class]))
{
return $objects[$class];
}
// If the requested class does not exist in the application/libraries
// folder we'll load the native class from the system/libraries folder.
list($base_file, $is_subclass, $is_duplicate) = i3_load_class($class);
if ($instantiate == FALSE)
{
$objects[$class] = TRUE;
return $objects[$class];
}
if ($is_subclass == TRUE)
{
$name = config_item('subclass_prefix').$class;
$objects[$class] =& new $name();
return $objects[$class];
}
$name = ($class != 'Controller') ? 'CI_'.$class : $class;
$objects[$class] =& new $name();
return $objects[$class];
}
and _ci_load_class() in libraries/Loader.php:
function _ci_load_class($class, $params = NULL)
{
// Get the class name
$class = str_replace(EXT, '', $class);
list($base_file, $has_subclass, $is_duplicate) = i3_load_class($class);
if ($is_duplicate)
{
log_message('debug', $class." class already loaded. Second attempt ignored.");
return;
}
if ($base_file)
{
$this->_ci_classes[] = $base_file;
if ($has_subclass)
{
return $this->_ci_init_class($class, config_item('subclass_prefix'), $params);
}
else
{
return $this->_ci_init_class($class, '', $params);
}
}
// If we got this far we were unable to find the requested class.
log_message('error', "Unable to load the requested class: ".$class);
show_error("Unable to load the requested class: ".$class);
}
It seems to work okay in my (non-exhaustive) testing. I’ll be trying it out a bit more in the next few days and I’ll post back here if I find any problems with it.