【thinkphp3.2】插件开发实现

这两天写项目用到插件这块了 作为个新手不太了解

官方文档给的参考也不是很多

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');

 

转载于:https://my.oschina.net/u/2367105/blog/995046

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值