这两天写项目用到插件这块了 作为个新手不太了解
官方文档给的参考也不是很多
http://document.thinkphp.cn/manual_3_2.html#behavior_extend
看了几遍也不是很懂 想到oneThink就是插件机制 于是乎下载最新的oneThink
研究了一番 有点看懂了 然后在自己的项目中开始做
首先创建目录以及文件
./App/Common/Behavior/InitHookBehavior.class.php
<?php
namespace Common\Behavior;
use Think\Behavior;
use Think\Hook;
// 初始化钩子信息
class InitHookBehavior extends Behavior {
// 行为扩展的执行入口必须是run
public function run(&$content){
$hooks = M('Hooks')->getField('name,addons');
foreach ($hooks as $key => $value) {
if($value){
$map['status'] = 1;
$names = explode(',',$value);
$map['name'] = array('IN',$names);
$data = M('Addons')->where($map)->getField('id,name');;
if($data){
$addons = array_intersect($names, $data);
Hook::add($key,$addons);
}
}
}
}
}
新建文件./App/Common/Conf/tags.php
<?php
return array(
'app_init'=>array('Common\Behavior\InitHookBehavior')
);
这个文件呢是用来初始化我们的插件的 官方文档中有说明:
app_init 应用初始化标签位
path_info PATH_INFO检测标签位
app_begin 应用开始标签位
action_name 操作方法名标签位
action_begin 控制器开始标签位
view_begin 视图输出开始标签位
view_parse 视图解析标签位
template_filter 模板内容解析标签位
view_filter 视图输出过滤标签位
view_end 视图输出结束标签位
action_end 控制器结束标签位
app_end 应用结束标签位
新建文件./App/Common/Common/function.php
<?php
//定义插件目录
const ONETHINK_ADDON_PATH = './Addons/';
/**
* 处理插件钩子
* @param string $hook 钩子名称
* @param mixed $params 传入参数
* @return void
*/
function hook($hook,$params=array()){
\Think\Hook::listen($hook,$params);
}
/**
* 获取插件类的类名
* @param strng $name 插件名
*/
function get_addon_class($name){
$class = "Addons\\{$name}\\{$name}Addon";
return $class;
}
/**
* 获取插件类的配置文件数组
* @param string $name 插件名
*/
function get_addon_config($name){
$class = get_addon_class($name);
if(class_exists($class)) {
$addon = new $class();
return $addon->getConfig();
}else {
return array();
}
}
新增配置./App/Common/Conf/config.php
'AUTOLOAD_NAMESPACE' => array('Addons' => ONETHINK_ADDON_PATH), //扩展模块列表
新建目录文件./App/Common/Controller/Addon.class.php(此文件为oneThink直接拿过来的 有兴趣的可以深入研究一下)
<?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 Common\Controller;
/**
* 插件类
* @author yangweijie <yangweijiester@gmail.com>
*/
abstract class Addon{
/**
* 视图实例对象
* @var view
* @access protected
*/
protected $view = null;
/**
* $info = array(
* 'name'=>'Editor',
* 'title'=>'编辑器',
* 'description'=>'用于增强整站长文本的输入和显示',
* 'status'=>1,
* 'author'=>'thinkphp',
* 'version'=>'0.1'
* )
*/
public $info = array();
public $addon_path = '';
public $config_file = '';
public $custom_config = '';
public $admin_list = array();
public $custom_adminlist = '';
public $access_url = array();
public function __construct(){
$this->view = \Think\Think::instance('Think\View');
$this->addon_path = ONETHINK_ADDON_PATH.$this->getName().'/';
$TMPL_PARSE_STRING = C('TMPL_PARSE_STRING');
$TMPL_PARSE_STRING['__ADDONROOT__'] = __ROOT__ . '/Addons/'.$this->getName();
C('TMPL_PARSE_STRING', $TMPL_PARSE_STRING);
if(is_file($this->addon_path.'config.php')){
$this->config_file = $this->addon_path.'config.php';
}
}
/**
* 模板主题设置
* @access protected
* @param string $theme 模版主题
* @return Action
*/
final protected function theme($theme){
$this->view->theme($theme);
return $this;
}
//显示方法
final protected function display($template=''){
if($template == '')
$template = CONTROLLER_NAME;
echo ($this->fetch($template));
}
/**
* 模板变量赋值
* @access protected
* @param mixed $name 要显示的模板变量
* @param mixed $value 变量的值
* @return Action
*/
final protected function assign($name,$value='') {
$this->view->assign($name,$value);
return $this;
}
//用于显示模板的方法
final protected function fetch($templateFile = CONTROLLER_NAME){
if(!is_file($templateFile)){
$templateFile = $this->addon_path.$templateFile.C('TMPL_TEMPLATE_SUFFIX');
if(!is_file($templateFile)){
throw new \Exception("模板不存在:$templateFile");
}
}
return $this->view->fetch($templateFile);
}
final public function getName(){
$class = get_class($this);
return substr($class,strrpos($class, '\\')+1, -5);
}
final public function checkInfo(){
$info_check_keys = array('name','title','description','status','author','version');
foreach ($info_check_keys as $value) {
if(!array_key_exists($value, $this->info))
return FALSE;
}
return TRUE;
}
/**
* 获取插件的配置数组
*/
final public function getConfig($name=''){
static $_config = array();
if(empty($name)){
$name = $this->getName();
}
if(isset($_config[$name])){
return $_config[$name];
}
$config = array();
$map['name'] = $name;
$map['status'] = 1;
$config = M('Addons')->where($map)->getField('config');
if($config){
$config = json_decode($config, true);
}else{
$temp_arr = include $this->config_file;
foreach ($temp_arr as $key => $value) {
if($value['type'] == 'group'){
foreach ($value['options'] as $gkey => $gvalue) {
foreach ($gvalue['options'] as $ikey => $ivalue) {
$config[$ikey] = $ivalue['value'];
}
}
}else{
$config[$key] = $temp_arr[$key]['value'];
}
}
}
$_config[$name] = $config;
return $config;
}
//必须实现安装
abstract public function install();
//必须卸载插件方法
abstract public function uninstall();
}
修改官方文件./ThinkPHP/Library/Think/Hook.class.php中的执行某个插件方法
/**
* 执行某个插件
* @param string $name 插件名称
* @param string $tag 方法名(标签名)
* @param Mixed $params 传入的参数
* @return void
*/
static public function exec($name, $tag,&$params=NULL) {
if('Behavior' == substr($name,-8) ){
// 行为扩展必须用run入口方法
$tag = 'run';
}
if(false === strpos($name,'\\')) {
$name = "Addons\\{$name}\\{$name}Addon";
}
$addon = new $name();
return $addon->$tag($params);
}
至此 我们缺少东西 在做的过程中 我们涉及到两张数据表
oneThink 官方手册当中有 http://document.onethink.cn/manual_1_0.html#onethink_3_3
在开始的时候没有理解钩子与插件直接的关系
钩子是什么 百度了一堆 没有什么实质性的能立马就能理解的
插件和钩子到底有什么区别
照着thinkphp官方文档做了一遍
当时理解的 插件写好了 用钩子去调用 话是没错 但是以一个小白的理解 还是没有搞懂
当时以为一个钩子只能调用一个插件 然后就否定了自己的这个想法 因为如果10个插件 我们就要写10个钩子吗 那这样和调用方法有啥区别 所以肯定是不对的
后来看到一篇浅谈onethink 插件
http://www.thinkphp.cn/topic/6860.html
这篇文章虽然不长 而且将的不是很深入
但是看这个文章 加上各种折腾
终于稍微理解了一点
个人感觉 钩子 就是写在某个固定的地方 比如模板中 一个方法中 这个钩子有个名字
你可以吧你的插件 挂在这个钩子上 只要执行这个钩子 那么钩子上挂载的插件都会执行(小白的理解 不知道用官方语言应该怎么写)
至此
我们就可以写我们的插件了
新建文件./Addons/Test/TestAddon.class.php
<?php
namespace Addons\Test;
use Common\Controller\Addon;
/**
* 测试插件
*/
class TestAddon extends Addon{
public $info = array(
'name'=>'Test',
'title'=>'标题',
'description'=>'描述',
'status'=>1,//状态
'author'=>'作者',
'version'=>'版本'
);
public function install(){
return true;
}
public function uninstall(){
return true;
}
//实现的钩子方法
public function defaultfun($param){
echo "test";
}
}
记得 在数据库加上这个插件
自己看数据表结构 以及初始化插件方法 去添加 不是很难
模板调用
{:hook('defaultfun')}
控制器调用
hook('defaultfun');