Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to extend the CodeIgniter Database Utility Class

Problem:

When I updated my CodeIgniter 2.2.0 application to use the mysqli database drivers, it broke CodeIgniter's backup function of the Database Utility Class. Where I used to successfully get a database backup, I'm now getting an error...

Unsupported feature of the database platform you are using.

The error simply means that the CodeIgniter backup function from the Database Utility Class does not support mysqli. As per the online docs, only MySQL is supported.

However, I prefer not to use the deprecated mysql database driver.


Possible Workaround (not allowed):

I thought I could solve this by simply extending CodeIgniter's Database Utility class. However, CodeIgniter does not allow this as per documentation...

Note: The Database classes can not be extended or replaced with your own classes.


Another Workaround (fatal error):

EDIT: my answer and the accepted answer are based on this workaround.

This GitHub page describes a method for extending the Database Class by creating a MY_Loader class to extend the core.

https://github.com/bcit-ci/CodeIgniter/wiki/Extending-Database-Drivers

However, when I attempted this solution, I got this fatal error...

Filename: core/MY_Loader.php, Line Number: 49

Fatal error: Call to undefined method CI_DB_mysqli_driver::where() in /home/account/codeigniter/system/libraries/Session.php on line 217

Line 49 is: $db =& new $my_driver(get_object_vars($db));

I am using the MY_Loader exactly as described at the link above, and MY_DB_mysqli_utility looks like this...

<?php class MY_DB_mysqli_utility extends CI_DB_mysqli_utility {

    function __construct($params){
        parent::__construct($params);
        log_message('debug', 'Extended DB driver class instantiated!');
    }

    function _backup($params = array())
    {
        // the working backup function is here
        .....
    }

}

(I'm not entirely sure if this GitHub workaround is failing because it's out of date, I overlooked something, or if it's because I'm trying to use it on CI_DB_mysqli_utility instead of CI_DB_mysqli_driver.)

EDIT: this workaround was failing because it was meant only for extending the _driver and not the _utility... two completely different functions.


A Working Solution (not ideal):

The only working solution I've found has been to edit the CodeIgniter System files. For obvious reasons, I'd prefer not to do this.

The "broken" backup function located at system/database/drivers/mysqli/mysqli_utility.php is as follows...

function _backup($params = array())
{
    // Currently unsupported
    return $this->db->display_error('db_unsuported_feature');
}

There is an Ellis Lab thread that shows a function that works...

https://ellislab.com/forums/viewthread/194645/

I got it working by editing the core system file with the new _backup function.

function _backup($params = array())
{
    // the working backup function is here
    .....
}

So what else can/should I do here?

CodeIgniter's backup function is not supported by the mysqli driver, and I'm not allowed to extend the CodeIgniter Database Utility, leaving me with no alternative but to edit the core system files. I seem to be stuck and I'm coming here to see if I missed anything or if there's anything else I can do instead of editing the core system files.


EDIT: Note that the Database Utility Class in CodeIgniter v3 fully supports mysqli.

like image 721
Sparky Avatar asked Mar 18 '23 19:03

Sparky


1 Answers

Based on accepted solution by @RandomSeed...

I took the dbutil() function from CodeIgniter's Loader class and copied it exactly into my custom MY_Loader extension.

Then where it would load the default utility file from whichever driver, I simply redirected it to check for the existence of my custom database utility file located in my application/libraries directory. If the file exists, use it, otherwise use the default file.

MY_Loader.php

<?php class MY_Loader extends CI_Loader {

    public function dbutil()
    {

        if (! class_exists('CI_DB'))
        {
            $this->database();
        }

        $CI =& get_instance();

        // for backwards compatibility, load dbforge so we can extend dbutils off it
        // this use is deprecated and strongly discouraged
        $CI->load->dbforge();

        require_once(BASEPATH . 'database/DB_utility.php');

        // START custom >>

        // path of default db utility file
        $default_utility = BASEPATH . 'database/drivers/' . $CI->db->dbdriver . '/' . $CI->db->dbdriver . '_utility.php';

        // path of my custom db utility file
        $my_utility = APPPATH . 'libraries/MY_DB_' . $CI->db->dbdriver . '_utility.php';

        // set custom db utility file if it exists
        if (file_exists($my_utility))
        {
            $utility = $my_utility;
            $extend = 'MY_DB_';
        }
        else
        {
            $utility = $default_utility;
            $extend = 'CI_DB_';
        }

        // load db utility file
        require_once($utility);

        // set the class
        $class = $extend . $CI->db->dbdriver . '_utility';

        // << END custom

        $CI->dbutil = new $class();

    }

}

application/libraries/MY_DB_mysqli_utility.php

<?php
    class MY_DB_mysqli_utility extends CI_DB_utility {

    // everything in here is same as default mysqli_utility
    ....

    // EXCEPT the _backup() function is my own

    function _backup($params = array())
    {
        //  my custom backup code
        ....

I'm very happy with this solution as it leaves my CodeIgniter core files completely untouched. If I move or forget to use my custom utility file, it silently falls back to the default driver's utility file.


EDIT: Note that the Database Utility Class in CodeIgniter v3 fully supports mysqli negating any need for this workaround.

like image 112
Sparky Avatar answered Mar 26 '23 02:03

Sparky