ThinkPHP5中如何加入插件功能

ThinkPHP5中如何加入插件功能

作者:稚子 时间:2016-01-26 分类:BS架构后台语言 CMS相关问题汇聚 评论:1 条 浏览:8626

最近在使用ThinkPHP5开发应用,之前习惯了一些插件开发,感觉很好且,但基于现在文档不是很完善,所以自己研究了一下基础功能。将TP3.2中的插件功能迁移了过来。

加入插件的方法:

1、在系统的index.php入口中加入如下配置

// 插件目录
define('ADDON_PATH', __DIR__ . '/../addons/');
// 开启系统行为
define('APP_HOOK', true);

2、在数据库中加入addons插件表和hooks钩子表

CREATE TABLE `addons` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(40) NOT NULL COMMENT '插件名或标识',
  `title` varchar(20) NOT NULL DEFAULT '' COMMENT '中文名',
  `description` text COMMENT '插件描述',
  `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态',
  `config` text COMMENT '配置',
  `author` varchar(40) DEFAULT '' COMMENT '作者',
  `version` varchar(20) DEFAULT '' COMMENT '版本号',
  `create_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '安装时间',
  `has_adminlist` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '是否有后台列表',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='插件表';

CREATE TABLE `hooks` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(40) NOT NULL DEFAULT '' COMMENT '钩子名称',
  `description` text NOT NULL COMMENT '描述',
  `type` tinyint(1) unsigned NOT NULL DEFAULT '1' COMMENT '类型',
  `update_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '更新时间',
  `addons` varchar(255) NOT NULL DEFAULT '' COMMENT '钩子挂载的插件 '',''分割',
  `status` tinyint(2) DEFAULT '1',
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`) USING BTREE
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

3、在ThinkPHP5的根目录中创建addons目录

www  WEB项目目录
├─composer.json         composer定义文件
├─README.md             README文件
├─LICENSE.txt           授权说明文件
├─addons                插件目录(新增)
├─application           应用目录
│  ├─common             公共模块目录(可以更改)
│  ├─runtime            应用的运行时目录(可写,可定制)
│  ├─module             模块目录
│  │  └─ ...            更多类库目录
│  ├─common.php         公共函数文件
│  ├─config.php         公共配置文件
│  ├─route.php          路由配置文件
│  └─database.php       数据库配置文件
│
├─public                WEB目录(对外访问目录)
│  ├─index.php          入口文件
│  ├─.htaccess          用于apache的重写
│  └─router.php         快速测试文件(用于PHP内置webserver)
│
├─thinkphp              框架系统目录

4、在application中的common.php公共函数里添加两个公共方法

/**
 * 获取插件类的类名
 * @param strng $name 插件名
 * @param string $ext 扩展名
 */
function get_addon_class($name, $ext = EXT)
{
    // 初始化命名空间及类名
    $class = "addons\\{$name}\\" . ucfirst($name);
    return $class;
}

/**
 * 处理插件钩子
 * @param string $hook   钩子名称
 * @param mixed $params 传入参数
 * @return void
 */
function hook($hook, $params = [])
{
    // 钩子调用
    \think\Hook::listen($hook, $params);
}

5、在application目录下创建common模块,在common模块中创建behavior行为目录,在公共行为目录中创建Hooks.php钩子行为插件,内容如下:

<?php
// +----------------------------------------------------------------------
// | zzstudio [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016 http://www.zzstudio.net All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: Byron Sampson <xiaobo.sun@gzzstudio.net>
// +----------------------------------------------------------------------
namespace app\common\behavior;

use think\Hook;

class Hooks
{
    public function run(&$param = [])
    {
        if(defined('BIND_MODULE') && BIND_MODULE === 'Install') return;
        // 动态加入命名空间
        \think\Loader::addNamespace('addons', ADDON_PATH);
        // 获取钩子数据
        $data = S('hooks');
        if(!$data){
            $hooks = M('Hooks')->getField('name,addons');
            // 获取钩子的实现插件信息
            foreach ($hooks as $key => $value) {
                if($value){
                    $map['status']  =   1;
                    $names          =   explode(',',$value);
                    $map['name']    =   ['IN', $names];
                    $data = M('Addons')->where($map)->getField('id,name');
                    if($data){
                        $addons = array_intersect($names, $data);
                        Hook::add($key, array_map('get_addon_class', $addons));
                    }
                }
            }
            S('hooks', Hook::get());
        }else{
            Hook::import($data, false);
        }
    }
}

6、在application目录中创建tags.php行为配置文件,并且加入内容

<?php
// 系统行为定义
return [
    'app_init' => [
        'app\\common\\behavior\\Hooks'
    ],
    'action_begin'=> [
    ],
    'app_end'=> [
    ]
];

到此为止,插件功能就集成完毕了。

接下来我们做个简单的插件试一下:

1、在addons目录中创建一个Base.php 插件的基类

<?php
// +----------------------------------------------------------------------
// | addons [ WE CAN DO IT JUST ZZSTUDIO IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2015 http://www.zzstudio.net All rights reserved.
// +----------------------------------------------------------------------
// | Author: byron sampson <xiaobo.sun@zzstudio.net>
// +----------------------------------------------------------------------
namespace addons;

/**
 * 插件类
 * @author byron sampson <xiaobo.sun@zzstudio.net>
 */
abstract class Base{
    /**
     * 视图实例对象
     * @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();

    /**
     * 基类构造函数
     * Base constructor.
     */
    public function __construct()
    {
        $this->view         =   new \think\View();
        $this->addon_path   =   ADDON_PATH . $this->getName() . '/';
        $TMPL_PARSE_STRING = C('parse_str');
        $TMPL_PARSE_STRING['__ADDONROOT__'] = $TMPL_PARSE_STRING['__ADDONS__'] . '/' . $this->getName();
        C('parse_str', $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;
    }

    /**
     * 模板变量赋值
     * @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 . ".html";
            if(!is_file($templateFile)){
                E(L('_TEMPLATE_NOT_EXIST_') . ":$templateFile");
            }
        }
        return $this->view->fetch($templateFile);
    }

    /**
     * 获取插件名
     * @return string
     */
    final public function getName()
    {
        $class = get_class($this);
        list($space, $name, $class) = explode('\\', $class);

        return $name;
    }

    /**
     * 检查配置信息是否完整
     * @return bool
     */
    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 = [];
        if(empty($name)){
            $name = $this->getName();
        }
        if(isset($_config[$name])){
            return $_config[$name];
        }

        $map['name']    =   $name;
        $map['status']  =   1;
        $config  =   M('Addons')->where($map)->getField('config');
        if($config){
            $config   =   json_decode($config, true);
        }else{
            $config =   [];
            $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;
    }

    /**
     * 必须实现安装
     * @return mixed
     */
    abstract public function install();

    /**
     * 必须卸载插件方法
     * @return mixed
     */
    abstract public function uninstall();
}

2、在插件表(addons),钩子表(hooks)中加入相应的数据

INSERT INTO `addons` (`id`, `name`, `title`, `description`, `status`, `config`, `author`, `version`, `create_time`, `has_adminlist`) VALUES ('2', 'test', 'test插件', 'test插件简介', '1', NULL, 'byron sampson', '0.1', '1438154545', '0');

INSERT INTO .`hooks` (`id`, `name`, `description`, `type`, `update_time`, `addons`, `status`) VALUES ('21', 'demo', 'demo钩子', '1', '1384481614', 'test', '1');

3、在addons目录中创建一个test目录,且内部创建一个Test.php插件类

<?php
// +----------------------------------------------------------------------
// | test [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016 http://www.zzstudio.net All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: Byron Sampson <xiaobo.sun@gzzstudio.net>
// +----------------------------------------------------------------------
namespace addons\test;

class Test extends \addons\Base
{
    /**
     * 实现demo钩子
     * @param array $params
     */
    public function demo($params = [])
    {
        echo 'demo hook!page is ' . $params['p'];
    }

    /**
     * 安装方法
     */
    public function install()
    {
        // TODO: Implement install() method.
    }

    /**
     * 卸载方法
     */
    public function uninstall()
    {
        // TODO: Implement uninstall() method.
    }
}

4、在控制器中使用hook方法来调用钩子

hook('demo', ['p'=>'page']);

5、ok,大功告成

相关推荐
更多

  1. jencho 2018-6-5 15:36 #1 回复TA

    很棒

发表评论

电子邮件地址不会被公开。 必填项已用*标注

注意: 评论者允许使用'@user空格'的方式将自己的评论通知另外评论者。例如, ABC是本文的评论者之一,则使用'@ABC '(不包括单引号)将会自动将您的评论发送给ABC。使用'@all ',将会将评论发送给之前所有其它评论者。请务必注意user必须和评论者名相匹配(大小写一致)。

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据