### **完整的插件運行流程**
**插件安裝流程**
首先 ,我們打開Editor插件的定義類
~~~
<?php
// +----------------------------------------------------------------------
// | OneThink [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2013 http://www.onethink.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: yangweijie <yangweijiester@gmail.com> <code-tech.diandian.com>
// +----------------------------------------------------------------------
namespace Addons\Editor;
use Common\Controller\Addon;
/**
* 編輯器插件
* @author yangweijie <yangweijiester@gmail.com>
*/
class EditorAddon extends Addon{
public $info = array(
'name'=>'Editor',
'title'=>'前臺編輯器',
'description'=>'用于增強整站長文本的輸入和顯示',
'status'=>1,
'author'=>'thinkphp',
'version'=>'0.1'
);
public function install(){
return true;
}
public function uninstall(){
return true;
}
/**
* 編輯器掛載的文章內容鉤子
* @param array('name'=>'表單name','value'=>'表單對應的值')
*/
public function documentEditFormContent($data){
$this->assign('addons_data', $data);
$this->assign('addons_config', $this->getConfig());
$this->display('content');
}
/**
* 討論提交的鉤子使用編輯器插件擴展
* @param array('name'=>'表單name','value'=>'表單對應的值')
*/
public function topicComment ($data){
$this->assign('addons_data', $data);
$this->assign('addons_config', $this->getConfig());
$this->display('content');
}
}
~~~
整個插件就是一個特殊的繼承了 Addon抽象類的子類。必須實現 install和uninstall方法。 然后必須有一個自己的info屬性,作為插件自己的信息。name、titile、description、status、author、version這6個是必須的。到時候后臺列表里在未安裝時會讀取插件信息,顯示出來。status為1或者0,表示安裝插件后是否立即啟用。
install和uninstall方法用于后臺插件安裝和卸載時候調用。返回true或者false用于告訴后臺我安裝卸載的準備工作是否做好了。比如我安裝時候創建了某些表,創建成功可以安裝,不成功提示錯誤。卸載前應該將安裝時做的操作恢復到安裝前狀態。 其次,插件被安裝后才能配置插件,卸載后會同時去除鉤子處掛載的插件名,安裝會添加鉤子對應的插件名。
后臺AddonsController.class.php
~~~
/**
* 安裝插件
*/
public function install(){
$addon_name = trim(I('addon_name'));
$class = get_addon_class($addon_name);
if(!class_exists($class))
$this->error('插件不存在');
$addons = new $class;
$info = $addons->info;
if(!$info || !$addons->checkInfo())//檢測信息的正確性
$this->error('插件信息缺失');
session('addons_install_error',null);
$install_flag = $addons->install();
if(!$install_flag){
$this->error('執行插件預安裝操作失敗'.session('addons_install_error'));
}
$addonsModel = D('Addons');
$data = $addonsModel->create($info);
if(is_array($addons->admin_list) && $addons->admin_list !== array()){
$data['has_adminlist'] = 1;
}else{
$data['has_adminlist'] = 0;
}
if(!$data)
$this->error($addonsModel->getError());
if($addonsModel->add($data)){
$config = array('config'=>json_encode($addons->getConfig()));
$addonsModel->where("name='{$addon_name}'")->save($config);
$hooks_update = D('Hooks')->updateHooks($addon_name);
if($hooks_update){
S('hooks', null);
$this->success('安裝成功');
}else{
$addonsModel->where("name='{$addon_name}'")->delete();
$this->error('更新鉤子處插件失敗,請卸載后嘗試重新安裝');
}
}else{
$this->error('寫入插件數據失敗');
}
}
~~~
實例化插件類->插件info是否正確->執行install方法,預安裝操作->添加插件數據到數據庫Addons表和Hooks表
每個步驟出錯都會提示,install 方法中錯誤用 session('addons_install_error', 'error')傳遞。
**插件卸載流程**
卸載流程和安裝相反
后臺AddonsController.class.php
~~~
/**
* 卸載插件
*/
public function uninstall(){
$addonsModel = M('Addons');
$id = trim(I('id'));
$db_addons = $addonsModel->find($id);
$class = get_addon_class($db_addons['name']);
$this->assign('jumpUrl',U('index'));
if(!$db_addons || !class_exists($class))
$this->error('插件不存在');
session('addons_uninstall_error',null);
$addons = new $class;
$uninstall_flag = $addons->uninstall();
if(!$uninstall_flag)
$this->error('執行插件預卸載操作失敗'.session('addons_uninstall_error'));
$hooks_update = D('Hooks')->removeHooks($db_addons['name']);
if($hooks_update === false){
$this->error('卸載插件所掛載的鉤子數據失敗');
}
S('hooks', null);
$delete = $addonsModel->where("name='{$db_addons['name']}'")->delete();
if($delete === false){
$this->error('卸載插件失敗');
}else{
$this->success('卸載成功');
}
}
~~~
實例化插件類->執行預卸載->卸載插件所掛載過的鉤子處信息->刪除插件文件。 每個步驟出錯都會提示,install 方法中錯誤用 session('addons_uninstall_error', 'error')傳遞。
**插件運行流程**
hook函數調用Hook類的listen靜態方法觸發鉤子->獲取鉤子掛載的開啟的插件->執行對應插件實現的鉤子同名方法(這個在init_hooks函數會初始化)
代碼上就是如下的過程:
>hook('documentEditFormContent');
然后hook函數遍歷 Hook類里的$tag屬性,知道有哪些插件可被調用,接下來去讀取配置和狀態,啟用就去執行鉤子
~~~
/**
* 處理插件鉤子
* @param string $hook 鉤子名稱
* @param mixed $params 傳入參數
* @return void
*/
function hook($hook,$params=array()){
\Think\Hook::listen($hook,$params);
}
而Hook::listen方法里面
/**
* 監聽標簽的插件
* @param string $tag 標簽名稱
* @param mixed $params 傳入參數
* @return void
*/
static public function listen($tag, &$params=NULL) {
if(isset(self::$tags[$tag])) {
if(APP_DEBUG) {
G($tag.'Start');
trace('[ '.$tag.' ] --START--','','INFO');
}
foreach (self::$tags[$tag] as $name) {
APP_DEBUG && G($name.'_start');
$result = self::exec($name, $tag,$params);
if(APP_DEBUG){
G($name.'_end');
trace('Run '.$name.' [ RunTime:'.G($name.'_start',$name.'_end',6).'s ]','','INFO');
}
if(false === $result) {
// 如果返回false 則中斷插件執行
return ;
}
}
if(APP_DEBUG) { // 記錄行為的執行日志
trace('[ '.$tag.' ] --END-- [ RunTime:'.G($tag.'Start',$tag.'End',6).'s ]','','INFO');
}
}
return;
}
/**
* 執行某個插件
* @param string $name 插件名稱
* @param Mixed $params 傳入的參數
* @return void
*/
static public function exec($name, $tag,&$params=NULL) {
if(false === strpos($name,'\\')) {
// 插件(多個入口)
$class = "Addons\\{$name}\\{$name}Addon";
}else{
// 行為擴展(只有一個run入口方法)
$class = $name.'Behavior';
$tag = 'run';
}
$addon = new $class();
return $addon->$tag($params);
}
#實例化一個插件類,我們有get_addon_classs()函數,傳入插件名即可或得插件類名,然后直接new 就行了,區分大小寫
$addons_class = new get_addon_classs($addon_name);
~~~
$addon->$tag() 這個方法就是去執行鉤子處掛載的和鉤子同名的插件方法。
這個方法里可以display渲染模板,默認插件的模板就在插件目錄下,比如Editor插件類里用的$this->display('content');。
如果你想有目錄層可以傳入目錄/模板這樣的參數,這樣是不支持主題的,如果要支持主題,也可以傳入具體的模板路徑,使用T函數如T('Addons://Attachment@Article/edit')這樣,到時候想切換主題了,T函數定位模板之前C('DEFAULT_THEME','default')這樣就行了。
當然這個方法支持傳參,只允許一個,為了能實現引用。所以多個參數,請封裝成數組,傳入hook函數的第二個參數。
執行完畢,這個鉤子的某個插件前臺功能方法就運行完了。
插件被禁用,鉤子處的插件不會被執行該同名方法,并且插件后臺列表里不會出現該插件的列表。
插件不光前臺能用 ,后臺有鉤子,并且插件里實現了該鉤子,也可以用。為了前后臺編輯器插件可以配置不同的編輯器,我們復制了一份Editor插件,改名為EditroForAdmin了。
還有后臺首頁,其實是用AdminIndex 鉤子掛載了幾個插件。
后臺中,插件默認會在 插件列表里出現。默認沒有安裝過的會顯示在前面。
基本的數據字段都是讀取的插件類里的info屬性數組。插件未安裝的時候是不可以設置的。
假如插件需要url訪問,就必須插件里有Controller目錄和tp結構一樣。 只不過生成這個方法的用addons_url('插件名://控制器名/操作方法'),生成訪問url。并且訪問權限由插件去做。具體寫法,參照附件Attachment插件 里的控制器寫法。和模板里url調用。
- 準備
- 概覽
- 獲取
- 安裝
- 后臺管理
- 首頁
- 內容
- 系統
- 網站設置
- 配置管理
- 菜單管理
- 分類管理
- 模型管理
- 導航管理
- 數據備份
- 擴展
- 用戶
- 用戶信息
- 用戶行為
- 行為日志
- 權限管理
- 應用
- 架構設置
- 應用架構及目錄結構
- 獨立模型
- 插件設計
- 用戶行為設計
- 權限設計
- 文檔模型設計
- 分類設計
- 二次開發
- 命名規范與編碼規范
- 數據字典
- 公共函數和庫函數使用規范
- 模板開發指南
- 權限管理指南
- 插件開發指南
- 什么是插件?
- 什么是鉤子?
- 插件的開發流程
- 插件后臺的開發
- 插件開發注意事項
- 模型擴展開發指南
- 獨立模型擴展
- 文檔模型擴展
- 附錄
- 配置參考
- 函數庫參考
- Common函數庫
- admin函數庫
- Home函數庫
- 類庫參考