如何扩展 CodeIgniter 数据库实用程序类

Posted

技术标签:

【中文标题】如何扩展 CodeIgniter 数据库实用程序类【英文标题】:How to extend the CodeIgniter Database Utility Class 【发布时间】:2015-01-22 20:12:13 【问题描述】:

问题

当我更新我的 CodeIgniter 2.2.0 应用程序以使用 mysqli 数据库驱动程序时,它破坏了 CodeIgniter 的 backup function of the Database Utility Class。我曾经成功获得数据库备份的地方,现在却出现错误...

您正在使用的数据库平台的功能不受支持。

该错误仅表示数据库实用程序类中的 CodeIgniter 备份功能不支持mysqli。根据在线文档,仅支持 MySQL。

但是,我不想使用已弃用的 mysql 数据库驱动程序。


可能的解决方法(不允许)

我想我可以通过简单地扩展 CodeIgniter 的 Database Utility 类来解决这个问题。但是,CodeIgniter does not allow this as per documentation...

注意:数据库类不能扩展或替换为您自己的类。


另一种解决方法(致命错误)

编辑:my answer 和 the accepted answer 基于此解决方法。

此 GitHub 页面描述了一种通过创建 MY_Loader 类来扩展核心来扩展数据库类的方法。

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

但是,当我尝试此解决方案时,我收到了这个致命错误...

文件名:core/MY_Loader.php,行号:49

致命错误:在第 217 行调用 /home/account/codeigniter/system/libraries/Session.php 中未定义的方法 CI_DB_mysqli_driver::where()

第 49 行是:$db =& new $my_driver(get_object_vars($db));

我使用的 MY_Loader 与上面链接中描述的完全一样,MY_DB_mysqli_utility 看起来像这样......

<?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
        .....
    


(我不完全确定这个 GitHub 解决方法是否失败是因为它已经过时,我忽略了一些东西,或者是因为我试图在 CI_DB_mysqli_utility 而不是 CI_DB_mysqli_driver 上使用它。 )

编辑:此解决方法失败了,因为它仅用于扩展 _driver 而不是 _utility... 两个完全不同的功能。 p>


可行的解决方案(不理想)

我找到的唯一可行的解​​决方案是编辑 CodeIgniter 系统文件。出于显而易见的原因,我不想这样做。

位于system/database/drivers/mysqli/mysqli_utility.php的“坏掉”备份函数如下...

function _backup($params = array())

    // Currently unsupported
    return $this->db->display_error('db_unsuported_feature');

有一个 Ellis Lab 线程显示了一个有效的函数......

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

我通过使用新的_backup 函数编辑核心系统文件使其工作。

function _backup($params = array())

    // the working backup function is here
    .....


那么我还能/应该在这里做什么?

mysqli 驱动程序不支持 CodeIgniter 的备份功能,并且不允许我扩展 CodeIgniter 数据库实用程序,让我别无选择,只能编辑核心系统文件。我似乎被卡住了,我来这里看看我是否遗漏了什么,或者除了编辑核心系统文件,我还能做些什么。


编辑:请注意,CodeIgniter v3 中的数据库实用程序类完全支持mysqli

【问题讨论】:

如果mysqldump 在您的系统上可用,如果我是您,我会考虑向它发出系统调用。 【参考方案1】:

由于内存和脚本超时,使用 php 进行数据库备份在某种程度上受到限制。 用 mysqldump 创建一个 cronjob 来做备份怎么样?

但是,如果这不是一个选项,this 可能会有所帮助

【讨论】:

谢谢,但问题不在于 PHP、超时或内存,我已经有一个可用的 mysqli 备份功能。问题是如何在不编辑 CodeIgniter 核心文件的情况下扩展/修复 CodeIgniter 驱动程序? 我不确定是否真的需要这样做来实现目标。也许这在 CI v3 中已修复? CodeIgniter v3 还没有正式发布,即便如此,需要检查和改变的东西太多了。换句话说,这不仅仅是上传一个新的系统文件集的问题。【参考方案2】:

数据库类不能扩展或替换为您自己的类。

这些类甚至不是final,所以我会忽略此通知并派生我自己的驱动程序(根据DB.php 第140-143 行):

system/database/drivers/ 中创建一个新文件夹,例如mysupersqli/ 创建一组文件mysupersqli_[driver|forge|result|utility].php 在上述每个文件中,声明一个类 CI_DB_mysupersqli_[driver|forge|result|utility] 扩展其对应的 CI_DB_mysqli_*CI_DB_mysupersqli_driver::$dbdriver should be overriden,根据您的喜好覆盖其余部分) 或者,对来自system/database/drivers/mysqli 的文件进行粗暴的复制/粘贴/搜索和替换可能会更快(它还会使您的自定义驱动程序独立于内置的 mysqli 驱动程序,这可能是也可能不是一件好事) 现在您应该可以将config/database.php 修改为您的新驱动程序了

免责声明:未经测试:)

【讨论】:

这很有趣。我宁愿不在system 中的任何地方存储任何自定义,但是您的建议仍然比修改核心文件本身要好得多。【参考方案3】:

涉及自定义加载程序 (Extending Database Drivers) 的解决方案与此相关:扩展数据库驱动程序。您不能只用 *_utility 类替换 *_driver 类。

$my_driver_file = APPPATH.'libraries/'.$my_driver.EXT; // *driver* required!!

相反,我会覆盖CI_Loader::dbutil() method。像这样的东西应该可以工作:

public function dbutil()

    /* snip for brevity */
    $class = config_item('subclass_prefix').'DB_'.$db->dbdriver.'_utility';
    $filename = APPPATH.'libraries/'.$class.EXT;
    require_once($filename);
    /* snip for brevity */
 

免责声明:未经测试:)

【讨论】:

是的,我应该更仔细地研究一下这个解决方案。感谢您指出这一点,我接下来要试试这个。 谢谢!有用。详情见我的回答。【参考方案4】:

基于accepted solution by @RandomSeed...

我从 CodeIgniter 的 Loader 类中获取了 dbutil() 函数,并将其完全复制到我的自定义 MY_Loader 扩展中。

然后它将从任何驱动程序加载默认实用程序文件,我只是将其重定向以检查位于我的 application/libraries 目录中的自定义数据库实用程序文件是否存在。如果文件存在,则使用它,否则使用默认文件。

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
        ....

我对这个解决方案非常满意,因为它完全没有影响我的 CodeIgniter 核心文件。如果我移动或忘记使用我的自定义实用程序文件,它会自动退回到默认驱动程序的实用程序文件。


编辑:请注意,CodeIgniter v3 中的数据库实用程序类完全支持mysqli,因此不需要此解决方法。

【讨论】:

你确定$class = 'CI_DB_' . $CI-&gt;db-&gt;dbdriver . '_utility'; 吗?看起来您正在实例化默认类。 @RandomSeed,是的,我确定...因为没有MY_DB_ 类...这默认@ 987654333@ 类虽然是在 MY_Loader 中自定义的。这与 dbutil() 函数逐行完全相同,除了我注入自己的实用程序文件的部分。任何其他更改都会破坏它。 我唯一使用MY_DB_ 的地方是我的自定义实用程序文件的名称。在内部,除了备用代码外,它与默认对应项相同。 我明白了。我很困惑,因为在您最初的尝试中,您定义了 class MY_DB_mysqli_utility extends CI_DB_mysqli_utility 条件require() 很聪明。为了进一步推动它,我真的会从默认实用程序类派生一个具有自定义名称的类,并在与require() 相同的条件下构建$class。如果出现错误,您将立即知道加载了哪个版本。

以上是关于如何扩展 CodeIgniter 数据库实用程序类的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 CodeIgniter 的表单验证类验证“不匹配”类型?

CodeIgniter 2:如何多次扩展 CI_Controller?

在 Codeigniter 中扩展表单验证

CodeIgniter扩展加密类

PHP CodeIgniter扩展加密类

我想创建一个 CAGradientLayer 子类/实用程序类