成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

基于CI的事件驅(qū)動擴(kuò)展和開發(fā)規(guī)范

開發(fā) 架構(gòu)
最近在做一個網(wǎng)盤的項(xiàng)目,得到了很多經(jīng)驗(yàn)和教訓(xùn)。總結(jié)了一些常見的問題,于是寫了下面這樣一個小東西來解決。

問題

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

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

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

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

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

第一部分 

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

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

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

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

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

以下是代碼,Event 類。

  1.  <?php 
  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_nameas $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. ?> 

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

  1. public function __construct(){ 
  2.         parent::__construct(); 
  3.            //初始化事件中心 
  4.         $this -> load -> library("Event"); 
  5.         //初始化注冊模塊,這里寫你自己的。 
  6.         $modules = array('user','test'); 
  7.         //初始化事件中心模塊 
  8.         $auths = array(); 
  9.         foreach$modules as $module ){ 
  10.             //初始化各個模塊,將事件中心傳入以供模塊調(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)可以寫成 
  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.     } 

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

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

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

第二部分

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

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

由于一個api可能會有多個模塊聲明自己的驗(yàn)證規(guī)則,所以提供一個ignore字段來表示需要明確忽略掉的規(guī)則。在validate指向的函數(shù)值,函數(shù)自己通過post或這個get獲取參數(shù)并進(jìn)行驗(yàn)證。這里有點(diǎn)讓人感覺不舒服的地方就是上層的模塊需要知道基礎(chǔ)模塊的權(quán)限驗(yàn)證細(xì)節(jié),以便使用ignore來去掉和自己沖突的規(guī)則。好在這種情況應(yīng)該不會太多,大部分可以通過“將沖突的api拆成不同的api”來解決。而且這種方法可以使你在增加功能時完全不再修改之前的權(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.        //初始化注冊模塊 
  8.        $modules = array('user','test'); 
  9.       //初始化事件中心模塊 
  10.        $auths = array(); 
  11.        foreach( $modules as $module ){ 
  12.            //初始化各個模塊,將事件中心傳入以供模塊調(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ì)算出來的權(quán)限驗(yàn)證數(shù)組放在了自己的auth_array屬性中,用戶在繼承了該控制器之后,通過$this -> auth_validate() 就能開始執(zhí)行驗(yàn)證。

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

另外貼出兩個具體的model:

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

原文鏈接:http://www.cnblogs.com/sskyy/archive/2012/06/27/2565294.html

 

【編輯推薦】

 

 

責(zé)任編輯:彭凡 來源: 博客園
相關(guān)推薦

2023-11-02 08:01:22

2024-06-28 10:19:02

委托事件C#

2023-03-16 15:18:16

2021-08-01 23:47:54

通用模型驅(qū)動

2009-12-31 08:49:15

模型驅(qū)動開發(fā)

2023-12-28 07:57:27

2013-03-26 14:17:21

架構(gòu)架構(gòu)設(shè)計(jì)事件驅(qū)動

2009-07-02 09:56:24

導(dǎo)入事件驅(qū)動技術(shù)JSP Servlet

2009-06-29 16:19:57

JSP Servlet

2021-07-27 08:01:22

CICD平臺

2009-10-20 14:58:15

Javascript事

2021-11-23 23:39:19

微服務(wù)開發(fā)架構(gòu)

2023-02-07 07:25:36

Spring事件驅(qū)動

2012-08-24 09:02:36

IBMdW

2025-02-13 08:53:10

WinForm事件驅(qū)動編程模型開發(fā)

2020-04-16 21:02:35

前端命名規(guī)范html規(guī)范

2019-04-19 21:06:23

事件驅(qū)動架構(gòu)VANTIQ

2015-12-02 14:56:07

Docker開發(fā)模式持續(xù)集成

2023-08-31 08:21:42

KubernetesKADA驅(qū)動

2009-06-25 14:05:08

Ajax JSF
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 中文字幕一区在线 | 成人国产精品免费观看视频 | 久久亚洲一区 | 精品亚洲一区二区 | 日美女逼逼 | av在线影院 | 欧美精品在线一区二区三区 | 久久这里只有精品首页 | 天天操天天干天天曰 | 午夜免费电影院 | 欧美黄色性生活视频 | 99亚洲综合 | 亚洲国产精久久久久久久 | 国产视频一区二区在线观看 | 成人福利影院 | 日韩电影免费在线观看中文字幕 | 中文字幕在线观看视频网站 | 亚洲久草| 久久久久久国产 | 亚洲综合视频 | 亚洲精品99 | 黑人精品xxx一区一二区 | 狠狠躁天天躁夜夜躁婷婷老牛影视 | 欧美精品一区二区三区在线播放 | 国内精品一区二区三区 | 日本免费一区二区三区 | 91精品国产91久久久久久最新 | 久久不卡 | 啪视频在线| 精品一区二区免费视频 | 日本成人午夜影院 | 手机av在线 | 国产91丝袜在线播放 | 久久偷人 | 欧美成人在线网站 | 一区久久 | 男女羞羞免费网站 | 一级黄色片在线免费观看 | 成人在线观 | 在线免费看黄 | 盗摄精品av一区二区三区 |