日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
基于CI的事件驅(qū)動(dòng)擴(kuò)展和開(kāi)發(fā)規(guī)范

問(wèn)題

望城ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場(chǎng)景,ssl證書(shū)未來(lái)市場(chǎng)廣闊!成為成都創(chuàng)新互聯(lián)的ssl證書(shū)銷(xiāo)售渠道,可以享受市場(chǎng)價(jià)格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:18980820575(備注:SSL證書(shū)合作)期待與您的合作!

項(xiàng)目中為了追求速度和性能,數(shù)據(jù)庫(kù)的表設(shè)計(jì)往往不是滿(mǎn)足范式的。這就可能導(dǎo)致在改一個(gè)表中項(xiàng)目實(shí)體的元信息時(shí),需要同時(shí)修改其他表中的信息。比方說(shuō):我有一個(gè)一張表來(lái)表示虛擬的文件(每一行記錄表示一個(gè)文件),另一個(gè)張表用來(lái)記錄已經(jīng)發(fā)布的文件和生成的外鏈信息。可能為了少進(jìn)行一次查表,我們會(huì)把文件的一些基本信息,如(文件名,發(fā)布人的名字)記錄在外鏈的表中。當(dāng)修改了文件表中的元信息時(shí),外鏈表中的信息也需要修改。常見(jiàn)的方法是使用ORM,但如果我還需要“根據(jù)具體情況再?zèng)Q定要修改其他表中的元信息”這種情況時(shí),ORM就有點(diǎn)難搞了。

同時(shí),我希望我在對(duì)上一個(gè)問(wèn)題中提到的“文件”數(shù)據(jù)進(jìn)行操作時(shí),不需要知道任何其他相關(guān)的細(xì)節(jié)。也就是將其他的這些關(guān)系劃到其他模塊去。

系統(tǒng)的接口往往需要復(fù)合的權(quán)限控制,并且在完成基礎(chǔ)的部分的權(quán)限控制之后,不希望由于后續(xù)功能的增加而去修改基礎(chǔ)部分。同時(shí)希望后續(xù)的這些功能在不啟用時(shí),系統(tǒng)能夠恢復(fù)到基礎(chǔ)的權(quán)限控制策略。比方說(shuō),一個(gè)模擬的網(wǎng)盤(pán)文件,我在系統(tǒng)沒(méi)有增加分享這個(gè)功能時(shí),權(quán)限控制策略是“只有自己可以訪問(wèn)”,在增加了分享功能后,策略是“指定分享的好友都可以訪問(wèn)”。為了在單獨(dú)完成分享模塊代碼時(shí)不修改之前的代碼,常用的方法是使用鉤子來(lái)拋出權(quán)限信息,系統(tǒng)自動(dòng)進(jìn)行復(fù)合,下面會(huì)詳述。

當(dāng)項(xiàng)目不是太大時(shí)(沒(méi)有大到需要使用HMVC等更高級(jí)的模式),需要一種簡(jiǎn)單、弱耦合的模塊管理和開(kāi)發(fā)規(guī)范。

解決方案(以CI為基礎(chǔ)框架)

第一部分

以 問(wèn)題1和2 中的例子來(lái)說(shuō),數(shù)據(jù)變化的主體是文件,其他都是跟隨變化。很自然就讓人想到觀察者模式,只不過(guò)我這里不是把“關(guān)聯(lián)”的類(lèi)注冊(cè)到“文件”類(lèi)中監(jiān)聽(tīng)變化,而是聲明一個(gè)全局事件,每一個(gè)模塊都持有它的一個(gè)引用,都通過(guò)它來(lái)拋出事件,都通過(guò)監(jiān)聽(tīng)它的事件來(lái)進(jìn)行自己的操作。

你可能會(huì)說(shuō)這在某種程度上破壞了模塊的封裝,因?yàn)槟K知道了上層的細(xì)節(jié)。但是這樣做就大大降低了模塊之間的耦合。首先,基礎(chǔ)模塊(“文件”)不用知道外部如何應(yīng)對(duì)變化,也不用管理外部的監(jiān)聽(tīng)者,對(duì)自己的操作只需要拋出一個(gè)事件就夠了。對(duì)監(jiān)聽(tīng)模塊來(lái)說(shuō),只需要監(jiān)聽(tīng)系統(tǒng)統(tǒng)一約定的事件就好,設(shè)置不用關(guān)注基礎(chǔ)模塊的監(jiān)聽(tīng)方法甚至名字都不用關(guān)心。

在CI中的實(shí)現(xiàn)有兩個(gè)步驟:

1.在CI中聲明一個(gè)事件類(lèi),生成一個(gè)實(shí)例作為全局事件對(duì)象,綁定在控制器實(shí)力上。

2.使用CI的model作為模塊(為了實(shí)現(xiàn)更強(qiáng)的封裝可以把業(yè)務(wù)邏輯單獨(dú)寫(xiě)成libraries中的類(lèi)),初始化時(shí)給它綁定這個(gè)事件。同時(shí)獲取的模塊需要監(jiān)聽(tīng)的事件,將這些事件綁定到全局事件對(duì)象。

以下是代碼,Event 類(lèi)。

 
 
 
  1.  
  2. /**
  3.  * @author rainer_H
  4.  * @date 2012-6-25
  5.  * @encode UTF-8
  6.  */
  7. class Event {
  8.     private $event_array = array();
  9.     public function __construct(){
  10.     }
  11.     //$module_callback : array(module_name, callback_method)
  12.     public function bind( $event_name, $module_callback ){
  13.         if( !isset( $this -> event_array[$event_name] ) ){
  14.             $this -> event_array[$event_name] = array();
  15.         }
  16.         array_push( $this -> event_array[$event_name], $module_callback );
  17.     }
  18.     public function multi_bind( &$bindings ){
  19.         foreach( $bindings as $event_name => $module_callback ){
  20.             $this -> bind( $event_name, $module_callback );
  21.         }
  22.     }
  23.    public function trigger( $event_name ){
  24.        if( isset( $this -> event_array[$event_name] )){
  25.           foreach( $this -> event_array[$event_name] as $module_callback ){
  26.              $args = array_slice( func_get_args(), 1);
  27.                 call_user_func_array(array(  $module_callback[0],$module_callback[1]), $args);
  28.             }
  29.         }
  30.     }
  31. }
  32. ?>

MY_Controller 的構(gòu)造函數(shù)實(shí)現(xiàn):

 
 
 
  1. public function __construct(){
  2.         parent::__construct();
  3.            //初始化事件中心
  4.         $this -> load -> library("Event");
  5.         //初始化注冊(cè)模塊,這里寫(xiě)你自己的。
  6.         $modules = array('user','test');
  7.         //初始化事件中心模塊
  8.         $auths = array();
  9.         foreach( $modules as $module ){
  10.             //初始化各個(gè)模塊,將事件中心傳入以供模塊調(diào)用
  11.             $model_name = "{$module}_model";
  12.             $this -> load -> model( $model_name, $module );
  13.             $this -> $model_name -> event =  $this -> event;
  14.             //以上這句優(yōu)雅一點(diǎn)可以寫(xiě)成
  15.             //$this -> $model_name -> set_handler($this -> event);
  16.             //綁定事件
  17.             $listen = $this -> $module -> listen();
  18.             foreach( $listen as $event_name => $callback ){
  19.                $listen[$event_name] = array( $this-> $module, $callback );
  20.          }
  21.           $this -> event -> multi_bind( $listen );
  22.      }
  23.     }

以上你注意到模塊需要有一個(gè)listen方法,來(lái)返回所有自己需要監(jiān)聽(tīng)的事件。如果你不喜歡這種約定也可以在模塊獲得全局事件對(duì)象event后,自己在模塊內(nèi)通過(guò)event->bind()來(lái)實(shí)現(xiàn)綁定。

以下是listen返回的事件監(jiān)聽(tīng)數(shù)組,也是事件格式:

 
 
 
  1. public function listen(){
  2.     return array(
  3.         //事件名 => 觸發(fā)的函數(shù)名
  4.         "user logged in" => "react_user_login"
  5.     );
  6. }

第二部分

對(duì)于事件的復(fù)合我采用了一個(gè)簡(jiǎn)單的鉤子模式,就是讓模塊約定聲明一個(gè)auth方法,返回自己要進(jìn)行權(quán)限控制的api和自己進(jìn)行控制的方法。示例如下:

 
 
 
  1. public function auth(){
  2.        return array(
  3.            //api名稱(chēng)
  4.            'main/index' => array(
  5.                //權(quán)限規(guī)則名稱(chēng)
  6.                'user_login' => array(
  7.                    //對(duì)同一api需要忽略掉的規(guī)則
  8.                    'ignore' => array( 'text_login' ),
  9.                    //自己的驗(yàn)證函數(shù)
  10.                    'validate' => 'login_validate'
  11.                )
  12.            )
  13.        );
  14.    }

由于一個(gè)api可能會(huì)有多個(gè)模塊聲明自己的驗(yàn)證規(guī)則,所以提供一個(gè)ignore字段來(lái)表示需要明確忽略掉的規(guī)則。在validate指向的函數(shù)值,函數(shù)自己通過(guò)post或這個(gè)get獲取參數(shù)并進(jìn)行驗(yàn)證。這里有點(diǎn)讓人感覺(jué)不舒服的地方就是上層的模塊需要知道基礎(chǔ)模塊的權(quán)限驗(yàn)證細(xì)節(jié),以便使用ignore來(lái)去掉和自己沖突的規(guī)則。好在這種情況應(yīng)該不會(huì)太多,大部分可以通過(guò)“將沖突的api拆成不同的api”來(lái)解決。而且這種方法可以使你在增加功能時(shí)完全不再修改之前的權(quán)限設(shè)置。

那么如何進(jìn)行合并?這里改造了一下MY_controller。代碼如下:

 
 
 
  1. class MY_Controller extends CI_Controller{
  2.    protected $auth_array = array();
  3.    public function __construct(){
  4.        parent::__construct();
  5.        //初始化事件中心
  6.        $this -> load -> library("Event");
  7.        //初始化注冊(cè)模塊
  8.        $modules = array('user','test');
  9.       //初始化事件中心模塊
  10.        $auths = array();
  11.        foreach( $modules as $module ){
  12.            //初始化各個(gè)模塊,將事件中心傳入以供模塊調(diào)用
  13.            $model_name = "{$module}_model";
  14.            $this -> load -> model( $model_name, $module );
  15.            $this -> $model_name -> event =  $this -> event;
  16.              //綁定事件
  17.            $listen = $this -> $module -> listen();
  18.            foreach( $listen as $event_name => $callback ){
  19.                $listen[$event_name] = array( $this-> $module, $callback );
  20.            }
  21.            $this -> event -> multi_bind( $listen );
  22.          //獲取模塊的權(quán)限信息
  23.            if( method_exists( $this -> $module , "auth") ){
  24.                $auths[$module] = $this -> $module -> auth() ;
  25.            }
  26.        }
  27.                //得到整合后的權(quán)限數(shù)組
  28.        $this -> auth_array = $this -> map_auth_array( $auths );
  29.    }
  30.    private function map_auth_array( $auth_array ) {
  31.        $output = array();
  32.        foreach( $auth_array as  $module_name => $auths_content ){        
  33.            foreach( $auths_content as $route => $auths ){
  34.               if( !isset( $output[$route] ) ){
  35.                    $output[$route] = array();
  36.                    $output[$route]['ignore'] = array();
  37.                } 
  38.                foreach( $auths as $auth_name => $auth ){
  39.                    $auths[$auth_name]['module'] = $module_name;
  40.                    if( isset( $auth['ignore'] ) ){
  41.                        if( !is_array( $auth['ignore'])){
  42.                            $auth['ignore'] = array( $auth['ignore'] );
  43.                        }
  44.                        $output[$route]['ignore'] = array_merge($output[$route]['ignore'],$auth['ignore']);
  45.                        array_unique( $output[$route]['ignore'] );
  46.                    }
  47.                } 
  48.                $output[$route] += $auths;
  49.            }
  50.        }
  51.           foreach( $output as $route => $auths){
  52.            if( !empty( $auths['ignore'] ) ){
  53.                foreach( $auths['ignore'] as $ignore ){
  54.                    unset( $output[$route][$ignore] );
  55.                }
  56.            }
  57.            unset( $output[$route]['ignore']);
  58.        }
  59.       return $output;
  60.    }
  61.    public function auth_validate(){
  62.        //獲取當(dāng)前路徑
  63.        $route = 'main/index';
  64.        if( $this -> auth_array[$route] && !empty( $this -> auth_array[$route] ) ){
  65.            foreach( $this -> auth_array[$route] as $auth ){
  66.                $this -> $auth['module'] -> $auth['validate']();
  67.            }
  68.        }
  69.    }

控制器將最后計(jì)算出來(lái)的權(quán)限驗(yàn)證數(shù)組放在了自己的auth_array屬性中,用戶(hù)在繼承了該控制器之后,通過(guò)$this -> auth_validate() 就能開(kāi)始執(zhí)行驗(yàn)證。

如果你不喜歡這種控制器與權(quán)限合并的方式或者你的控制器很復(fù)雜時(shí),你也可以將權(quán)限單獨(dú)提出到一個(gè)類(lèi)中。另外你可以再權(quán)限合并函數(shù)中記錄日志幫助調(diào)試。

另外貼出兩個(gè)具體的model:

 
 
 
  1. /**
  2.  * @author rainer_H
  3.  * @date 2012-6-26
  4.  * @encode UTF-8
  5.  */
  6. class User_model extends CI_Model{
  7.     //聲明自己的權(quán)限控制規(guī)則
  8.     public function auth(){
  9.         return array(
  10.             //api名稱(chēng)
  11.             'main/index' => array(
  12.                 //權(quán)限規(guī)則名稱(chēng)
  13.                 'user_login' => array(
  14.                     //對(duì)同一api需要忽略掉的規(guī)則
  15.                     'ignore' => array( 'text_login' ),
  16.                     //自己的驗(yàn)證函數(shù)
  17.                     'validate' => 'login_validate'
  18.                 )
  19.             )
  20.         );
  21.     }
  22.    public function __construct(  ){
  23.         parent::__construct( );
  24.     }
  25.      //聲明自己需要監(jiān)聽(tīng)的對(duì)象
  26.     public function listen(){
  27.         return array(
  28.         );
  29.     }
  30.     public function login_validate(){
  31.         echo "user login_validate";
  32.     }
  33.    public function login(){
  34.         $this -> event -> trigger( "user logged in", "hahaha" );
  35.     }
  36. }
  37. ?>
  38. /**
  39.  * @author rainer_H
  40.  * @date 2012-6-26
  41.  * @encode UTF-8
  42.  */
  43. class Test_model extends CI_Model{
  44.     public function __construct(  ){
  45.         parent::__construct(  );
  46.     }
  47.     public function auth(){
  48.         return array(
  49.             'main/index' => array(
  50.                 'text_login' => array(
  51.                     'validate' => 'login_validate'
  52.                 )
  53.             )
  54.         );
  55.     }
  56.     public function listen(){
  57.         return array(
  58.             "user logged in" => "react_user_login"
  59.         );
  60.     }
  61.     public function login_validate(){
  62.         echo "test login_validate";
  63.     }
  64.      public function react_user_login( $user = false ){
  65.         echo "{$user} user logged in react from Test.";
  66.     }
  67. }
  68. ?>

標(biāo)題名稱(chēng):基于CI的事件驅(qū)動(dòng)擴(kuò)展和開(kāi)發(fā)規(guī)范
分享鏈接:http://m.5511xx.com/article/coepphi.html