/***                 phpall技術(shù)交流群:75345798

                英文原文:http://net.tutsplus.com/tutorials/php/6-codeigniter-hacks-for-the-masters/
                翻譯原文:http://www.phpall.cn/forum/read.php?tid=389
          ***/
      Codeigniter是一個(gè)簡潔而又強(qiáng)大的開源web應(yīng)用框架。今天,我們將會(huì)使用一些核心的技巧來對這個(gè)框架做一些小的改變并提高它的性能。
在這過程之中,你將會(huì)對框架得到一個(gè)更好的理解。
作者:burak guze


      他是一個(gè)住在亞利桑那州的全職php web開發(fā)者,從伊斯坦布爾來的。他獲得了計(jì)算機(jī)科學(xué)與工程的學(xué)士學(xué)                 位。他擁有8年的phpmysql工作經(jīng)驗(yàn)。你能閱讀他的更多的文章在PHPandStuff.com,他的twitter
here


聲明

1.不推薦在已經(jīng)存在的項(xiàng)目中使用這些技巧。因?yàn)樗麄兏淖兞?/font>ci的核心功能,可能會(huì)使已經(jīng)寫的代碼崩潰。
2.我寫這篇文章的時(shí)候,ci1.7.2版本是最新的發(fā)行版本,這些技巧對以前的版本沒有作用。
3.盡管ci是被設(shè)計(jì)php4兼容的。但是這些技巧需要你安裝php5.
4.當(dāng)你對cisystem文件做的任何更改,你都應(yīng)該對這些改變做好記錄,供以后參考。下次當(dāng)你升級ci的時(shí)候,你可能需要重新再處理這些變化。

1.大師的6個(gè)codeigniter技巧——(1)自動(dòng)加載models——php5風(fēng)格


這個(gè)技巧希望達(dá)到的目標(biāo)是:

      在左邊,你會(huì)看到在controller里面通常加載model的方法。使用這個(gè)技巧以后,我們將能夠直接創(chuàng)建這個(gè)model對象。
這個(gè)代碼是簡潔的并且容易理解對象。
    使用這個(gè)技巧以后會(huì)有2個(gè)影響。首先你不再需要繼承model類了。


這個(gè)技巧

我們需要做的就是添加一個(gè)php5風(fēng)格的 autolader 函數(shù)

添加這些代碼到system/application/config/config.php:
<?php  
// ...  
function __autoload($class) {  
    if (file_exists(APPPATH."models/".strtolower($class).EXT)) {  
        include_once(APPPATH."models/".strtolower($class).EXT);  
    }  
}  
?>
如果你也有興趣運(yùn)用這個(gè)技巧到controller,你只需要添加以下代碼來代替上面的代碼。

<?php  
// ...  
function __autoload($class) {  
    if (file_exists(APPPATH."models/".strtolower($class).EXT)) {  
        include_once(APPPATH."models/".strtolower($class).EXT);  
    } else if (file_exists(APPPATH."controllers/".strtolower($class).EXT)) {  
        include_once(APPPATH."controllers/".strtolower($class).EXT);  
    }  
}  
?>
任何時(shí)候,你試著使用一個(gè)沒有定義的類時(shí)候,這個(gè)__autoload函數(shù)將會(huì)被調(diào)用,它將會(huì)加載這個(gè)類文件。

2.大師的6個(gè)codeigniter技巧——(2)防止model-controller名字沖突

使用這個(gè)技巧要達(dá)到的目標(biāo):

一般來說,模型和控制器你都不會(huì)有相同的類名字。讓我先創(chuàng)建一個(gè)取名為postmodel
class Post extends Model {  

    // ...  

}
現(xiàn)在你就不能有一個(gè)像這樣的url
http://www.mysite.com/post/display/13
這個(gè)原因是因?yàn)槟阋残枰幸粋€(gè)名字為postcontroller,如果創(chuàng)建了這樣的一個(gè)類的話將會(huì)引起致命錯(cuò)誤。
但是使用了這個(gè)技巧一般,一切皆有可能。那個(gè)url的控制器看起來是這樣的:

// application/controllers/post.php  
class Post_controller extends Controller {  

    // ...  

}
注意這個(gè)“__controller”后綴
技巧:

為了避免這個(gè)問題,通常大多數(shù)人都是添加‘_model’后綴到model名字(例如命名Post_model)。
在所有的應(yīng)用程序Model對象都被創(chuàng)建和引用,所以在所有的model名字后面跟上‘_model’有些無聊。
我認(rèn)為最好的辦法就是在controller上來添加后綴,因?yàn)樵诖a中controller的名字幾乎從來不會(huì)被引用。
首先我們需要繼承Router class。創(chuàng)建這樣一個(gè)文件:"application/libraries/MY_Router.php"
class MY_Router extends CI_Router {  
    var $suffix = '_controller';  

    function MY_Router() {  
        parent::CI_Router();  
    }  
    function set_class($class) {  
        $this->class = $class . $this->suffix;  
    }  
    function controller_name() {  
        if (strstr($this->class, $this->suffix)) {  
            return str_replace($this->suffix, '', $this->class);  
        }  
        else {  
            return $this->class;  
        }  
    }  
}  
現(xiàn)在編輯"system/codeigniter/CodeIgniter.php"
153
if ( ! file_exists(APPPATH.'controllers/'.$RTR->fetch_directory().$RTR->controller_name().EXT))  
然后第158

include(APPPATH.'controllers/'.$RTR->fetch_directory().$RTR->controller_name().EXT);  

然后編輯"system/libraries/Profiler.php"的第323

$output .= "<div style="color:#995300;font-weight:normal;padding:4px 0 4px 0">".$this->CI->router->controller_name()."/".$this->CI->router->fetch_method()."</div>";  
大功告成。使用這個(gè)技巧一定需要記住的是要把‘_controller’后綴放到你的controller的類的名字后面,不是放在你的控制器文件名中。


大師的6個(gè)codeigniter技巧——(3)表單驗(yàn)證“唯一值”(如注冊用戶名email)
      Ci有一個(gè)完美的表單驗(yàn)證類。但是這個(gè)驗(yàn)證有一點(diǎn)不足,例如當(dāng)大部分用戶注冊用戶名的時(shí)候,需要驗(yàn)證用戶名沒有被占用,或者郵箱是否存在在系統(tǒng)中。
使用這個(gè)技巧,你將能夠非常容易添加這項(xiàng)驗(yàn)證規(guī)則到你的表單提交中。

注意最后一部分"unique[User.username]."這個(gè)新的驗(yàn)證規(guī)則叫做“unique”,并且?guī)Я艘粋€(gè)方框在這個(gè)中括號(hào)中,它們是“tablename.filedname.所以它將會(huì)檢測數(shù)據(jù)庫的“user數(shù)據(jù)表的“username”列確定提交的值在數(shù)據(jù)庫里面不存在。
同理,你也能利用這個(gè)規(guī)則驗(yàn)證相同的郵件地址。
$this->form_validation->set_rules('email', 'E-mail',  
        'required|valid_email|unique[User.email]');  
你的應(yīng)用程序?qū)?huì)得到以下錯(cuò)誤信息

與其說這是一個(gè)技巧而不如說是一個(gè)擴(kuò)展。雖然如此,我們將要添加一個(gè)核心ci類庫并且改善它。
創(chuàng)建 "application/libraries/MY_Form_validation.php"文件

class MY_Form_validation extends CI_Form_validation {  

    function unique($value, $params) {  

        $CI =& get_instance();  
        $CI->load->database();  

        $CI->form_validation->set_message('unique',  
            'The %s is already being used.');  

        list($table, $field) = explode(".", $params, 2);  

        $query = $CI->db->select($field)->from($table)  
            ->where($field, $value)->limit(1)->get();  

        if ($query->row()) {  
            return false;  
        } else {  
            return true;  
        }  

    }  
}
現(xiàn)在你就能使用這個(gè)“唯一”驗(yàn)證規(guī)則了。

4.大師的6個(gè)codeigniter技巧——(4)從命令行運(yùn)行codeigniter

目標(biāo):
就像這個(gè)標(biāo)題所說,我們的目標(biāo)是能夠從命令行運(yùn)行ci。對于創(chuàng)建定時(shí)任務(wù),這個(gè)是必須的,或者是運(yùn)行更多的特別的操作,
所以你沒有web腳本的資源限制,就像最大執(zhí)行時(shí)間一樣。
這就是本地windows機(jī)器上面運(yùn)行的效果

技巧
創(chuàng)建一個(gè)“cli.php”文件在ci的根目錄(即與index.php在同一目錄)
if (isset($_SERVER['REMOTE_ADDR'])) {  
    die('Command Line Only!');  
}  
set_time_limit(0);  
$_SERVER['PATH_INFO'] = $_SERVER['REQUEST_URI'] = $argv[1];  
require dirname(__FILE__) . '/index.php';

如果你在linux環(huán)境下使用,并且想要讓這代碼自動(dòng)執(zhí)行,你能添加以下代碼在cli.php文件的第一行

#!/usr/bin/php  
如果你需要一個(gè)僅僅能在命令行下使用的控制器,你能阻止web調(diào)用控制器構(gòu)造函數(shù)
class Hello extends Controller {  
    function __construct() {  
        if (isset($_SERVER['REMOTE_ADDR'])) {  
            die('Command Line Only!');  
        }  
        parent::Controller();  
    }  

    // ...  
}

5.大師的6個(gè)codeigniter技巧——(5)添加Doctrine orm 到codeigniter
(Doctrine orm是一個(gè)比較復(fù)雜的東西,我們將會(huì)繼續(xù)出一些相關(guān)教程
目標(biāo)
Doctine是一個(gè)流行的php的關(guān)系對象映射(orm)。添加它到ci里面以后,你將會(huì)一個(gè)更加強(qiáng)大的模型層。

技巧:
其實(shí)安裝Doctrine不是那么難,就像安裝插件一樣。然后一旦安裝成功,你的model類將需要繼承Doctrine基類,而不是繼承cimodel類。這將會(huì)完全改變model層的工作方式。你建立的對象將會(huì)有持久的數(shù)據(jù)庫連接并且也將能有其他對象的數(shù)據(jù)庫關(guān)系。
按照以下幾步:
1. 建立文件夾:application/plugins
2. 創(chuàng)建文件夾:application/plugins/doctrine
3. 下載文件(1.2版本的)
4. Doctrine復(fù)制“lib”文件夾到“application/plugins/doctrine
5. 創(chuàng)建“application/plugins/doctrine_pi.php

// system/application/plugins/doctrine_pi.php  
// load Doctrine library  
require_once APPPATH.'/plugins/doctrine/lib/Doctrine.php';  
// load database configuration from CodeIgniter  
require_once APPPATH.'/config/database.php';  
// this will allow Doctrine to load Model classes automatically  
spl_autoload_register(array('Doctrine', 'autoload'));  
// we load our database connections into Doctrine_Manager  
// this loop allows us to use multiple connections later on  
foreach ($db as $connection_name => $db_values) {  
    // first we must convert to dsn format  
    $dsn = $db[$connection_name]['dbdriver'] .  
        '://' . $db[$connection_name]['username'] .  
        ':' . $db[$connection_name]['password'].  
        '@' . $db[$connection_name]['hostname'] .  
        '/' . $db[$connection_name]['database'];  
    Doctrine_Manager::connection($dsn,$connection_name);  
}  
// CodeIgniter's Model class needs to be loaded  
require_once BASEPATH.'/libraries/Model.php';
// telling Doctrine where our models are located
Doctrine::loadModels(APPPATH.'/models');  

然后,編輯‘application/config/autoload.php’自動(dòng)加載Doctrine插件
$autoload['plugin'] = array('doctrine');
你也要確定在“application/config/database.php的數(shù)據(jù)庫配置好了,”
就這樣,現(xiàn)在你就能使用ci應(yīng)用程序創(chuàng)建Doctrine模型了。閱讀更多的資源在這里

6.大師的6個(gè)codeigniter技巧——(6)運(yùn)行多個(gè)站點(diǎn)
目標(biāo):
這個(gè)技巧將會(huì)使安裝一個(gè)codeigniter就能運(yùn)行多個(gè)站點(diǎn)成為可能,每個(gè)站點(diǎn)有它自己的application文件夾,但是他們共享這相同的系統(tǒng)文件夾。

技巧
安裝ci服務(wù)器的任何位置。然后將application文件夾從system文件夾拿出來。放在外面,請看上面的圖片。
現(xiàn)在復(fù)制index.php文件到每個(gè)站點(diǎn)的跟目錄下面(即圖中的application_site1application_site2等)
然后編輯它:
在第26行,給出system文件夾的完整路徑
$system_folder = dirname(__FILE__) . '../codeigniter/system';  
在第43行,給出application文件夾的文章路徑
$application_folder = dirname(__FILE__) . '../application_site1';  
現(xiàn)在你就能使用獨(dú)立的application文件夾來建立不同的站點(diǎn)了,而只是共享同一個(gè)system文件夾
這里有一個(gè)相似的操作在ci用戶手冊



7.大師的6個(gè)codeigniter技巧——(7)允許所有類型的文件上傳
目標(biāo):
當(dāng)使用ci的上傳類的時(shí)候,你必須指明哪些文件類型允許上傳。

復(fù)制代碼
  • $this->load->library('upload');   $this->upload->set_allowed_types('jpg|jpeg|gif|png|zip');

如果你沒有指明特定的上傳類型,你將會(huì)從ci那里得到一個(gè)錯(cuò)誤信息"Youhave not specified any allowed file types."
所有,默認(rèn)的方式,將沒有辦法允許所有的文件上傳。我們需要做一些小的改變來處理這個(gè)限制。我們設(shè)定“*”將能夠運(yùn)行所有類型的文件上傳。

復(fù)制代碼
  • $this->load->library('upload');   $this->upload->set_allowed_types('*');
技巧:
我們需要修改上傳文件類。
創(chuàng)建文件:application/librarys/My_upload.php
class MY_Upload extends CI_Upload {  
    function is_allowed_filetype() {  
        if (count($this->allowed_types) == 0 OR ! is_array($this->allowed_types))  
        {  
            $this->set_error('upload_no_file_types');  
            return FALSE;  
        }  
        if (in_array("*", $this->allowed_types))  
        {  
            return TRUE;  
        }  
        $image_types = array('gif', 'jpg', 'jpeg', 'png', 'jpe');  
        foreach ($this->allowed_types as $val)  
        {  
            $mime = $this->mimes_types(strtolower($val));  

            // Images get some additional checks  
            if (in_array($val, $image_types))  
            {  
                if (getimagesize($this->file_temp) === FALSE)  
                {  
                    return FALSE;  
                }  
            }  
            if (is_array($mime))  
            {  
                if (in_array($this->file_type, $mime, TRUE))  
                {  
                    return TRUE;  
                }  
            }  
            else  
            {  
                if ($mime == $this->file_type)  
                {  
                    return TRUE;  
                }  
            }  
        }  
        return FALSE;  
    }