插件安裝流程
首先 ,我們打開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'=>'用于增強(qiáng)整站長文本的輸入和顯示',
'status'=>1,
'author'=>'thinkphp',
'version'=>'0.1'
);
public function install(){
return true;
}
public function uninstall(){
return true;
}
/**
* 編輯器掛載的文章內(nèi)容鉤子
* @param array('name'=>'表單name','value'=>'表單對應(yīng)的值')
*/
public function documentEditFormContent($data){
$this->assign('addons_data', $data);
$this->assign('addons_config', $this->getConfig());
$this->display('content');
}
/**
* 討論提交的鉤子使用編輯器插件擴(kuò)展
* @param array('name'=>'表單name','value'=>'表單對應(yīng)的值')
*/
public function topicComment ($data){
$this->assign('addons_data', $data);
$this->assign('addons_config', $this->getConfig());
$this->display('content');
}
}
整個插件就是一個特殊的繼承了 Addon抽象類的子類。必須實現(xiàn) install和uninstall方法。 然后必須有一個自己的info屬性,作為插件自己的信息。name、titile、description、status、author、version這6個是必須的。到時候后臺列表里在未安裝時會讀取插件信息,顯示出來。status為1或者0,表示安裝插件后是否立即啟用。
install和uninstall方法用于后臺插件安裝和卸載時候調(diào)用。返回true或者false用于告訴后臺我安裝卸載的準(zhǔn)備工作是否做好了。比如我安裝時候創(chuàng)建了某些表,創(chuàng)建成功可以安裝,不成功提示錯誤。卸載前應(yīng)該將安裝時做的操作恢復(fù)到安裝前狀態(tài)。 其次,插件被安裝后才能配置插件,卸載后會同時去除鉤子處掛載的插件名,安裝會添加鉤子對應(yīng)的插件名。
后臺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('執(zhí)行插件預(yù)安裝操作失敗'.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('寫入插件數(shù)據(jù)失敗');
}
}
實例化插件類->插件info是否正確->執(zhí)行install方法,預(yù)安裝操作->添加插件數(shù)據(jù)到數(shù)據(jù)庫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('執(zhí)行插件預(yù)卸載操作失敗'.session('addons_uninstall_error'));
$hooks_update = D('Hooks')->removeHooks($db_addons['name']);
if($hooks_update === false){
$this->error('卸載插件所掛載的鉤子數(shù)據(jù)失敗');
}
S('hooks', null);
$delete = $addonsModel->where("name='{$db_addons['name']}'")->delete();
if($delete === false){
$this->error('卸載插件失敗');
}else{
$this->success('卸載成功');
}
}
實例化插件類->執(zhí)行預(yù)卸載->卸載插件所掛載過的鉤子處信息->刪除插件文件。 每個步驟出錯都會提示,install 方法中錯誤用 session('addons_uninstall_error', 'error')傳遞。
插件運行流程
hook函數(shù)調(diào)用Hook類的listen靜態(tài)方法觸發(fā)鉤子->獲取鉤子掛載的開啟的插件->執(zhí)行對應(yīng)插件實現(xiàn)的鉤子同名方法(這個在init_hooks函數(shù)會初始化)
代碼上就是如下的過程:
hook('documentEditFormContent');
然后hook函數(shù)遍歷 Hook類里的$tag屬性,知道有哪些插件可被調(diào)用,接下來去讀取配置和狀態(tài),啟用就去執(zhí)行鉤子
/**
* 處理插件鉤子
* @param string $hook 鉤子名稱
* @param mixed $params 傳入?yún)?shù)
* @return void
*/
function hook($hook,$params=array()){
\Think\Hook::listen($hook,$params);
}
而Hook::listen方法里面
/**
* 監(jiān)聽標(biāo)簽的插件
* @param string $tag 標(biāo)簽名稱
* @param mixed $params 傳入?yún)?shù)
* @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 則中斷插件執(zhí)行
return ;
}
}
if(APP_DEBUG) { // 記錄行為的執(zhí)行日志
trace('[ '.$tag.' ] --END-- [ RunTime:'.G($tag.'Start',$tag.'End',6).'s ]','','INFO');
}
}
return;
}
/**
* 執(zhí)行某個插件
* @param string $name 插件名稱
* @param Mixed $params 傳入的參數(shù)
* @return void
*/
static public function exec($name, $tag,&$params=NULL) {
if(false === strpos($name,'\\')) {
// 插件(多個入口)
$class = "Addons\\{$name}\\{$name}Addon";
}else{
// 行為擴(kuò)展(只有一個run入口方法)
$class = $name.'Behavior';
$tag = 'run';
}
$addon = new $class();
return $addon->$tag($params);
}
#實例化一個插件類,我們有g(shù)et_addon_classs()函數(shù),傳入插件名即可或得插件類名,然后直接new 就行了,區(qū)分大小寫
$addons_class = new get_addon_classs($addon_name);
$addon->$tag() 這個方法就是去執(zhí)行鉤子處掛載的和鉤子同名的插件方法。
這個方法里可以display渲染模板,默認(rèn)插件的模板就在插件目錄下,比如Editor插件類里用的$this->display('content');。
如果你想有目錄層可以傳入目錄/模板這樣的參數(shù),這樣是不支持主題的,如果要支持主題,也可以傳入具體的模板路徑,使用T函數(shù)如T('Addons://Attachment@Article/edit')這樣,到時候想切換主題了,T函數(shù)定位模板之前C('DEFAULT_THEME','default')這樣就行了。
當(dāng)然這個方法支持傳參,只允許一個,為了能實現(xiàn)引用。所以多個參數(shù),請封裝成數(shù)組,傳入hook函數(shù)的第二個參數(shù)。
執(zhí)行完畢,這個鉤子的某個插件前臺功能方法就運行完了。
插件被禁用,鉤子處的插件不會被執(zhí)行該同名方法,并且插件后臺列表里不會出現(xiàn)該插件的列表。
插件不光前臺能用 ,后臺有鉤子,并且插件里實現(xiàn)了該鉤子,也可以用。為了前后臺編輯器插件可以配置不同的編輯器,我們復(fù)制了一份Editor插件,改名為EditroForAdmin了。
還有后臺首頁,其實是用AdminIndex 鉤子掛載了幾個插件。
后臺中,插件默認(rèn)會在 插件列表里出現(xiàn)。默認(rèn)沒有安裝過的會顯示在前面。
基本的數(shù)據(jù)字段都是讀取的插件類里的info屬性數(shù)組。插件未安裝的時候是不可以設(shè)置的。
假如插件需要url訪問,就必須插件里有Controller目錄和tp結(jié)構(gòu)一樣。 只不過生成這個方法的用addons_url('插件名://控制器名/操作方法'),生成訪問url。并且訪問權(quán)限由插件去做。具體寫法,參照附件Attachment插件 里的控制器寫法。和模板里url調(diào)用。
更多建議: