ECJiaWiki:如何快速创建一个插件
第一篇:通用插件入门
1、什么是插件?插件能做什么?
插件是一种外挂于主应用的程序,具有可扩展性,不能独立与主应用运行。
插件层是EC+的业务的扩展,根据业务的不同场景下的需求不同,可以轻松通过插件对应用的扩展进行业务逻辑补充。后台可轻易安装、卸载、移除插件。
2、插件位置
插件存放在 plugins
目录下,新建插件需要在这个目录下进行创建。
3、插件种类介绍?
有system、captcha、cron、platform、payment、shipping、sms、connect八大类:
类型名 | 类型前缀 | 简单描述 | 示例 |
---|---|---|---|
system | 无 | 系统 | calculator(计算器) |
captcha | captcha | 验证码 | captcha_royalcms(ROYALCMS验证码) |
cron | cron | 计划任务 | cron_bill_day(商家结算帐单按日生成) |
platform | mp | 公众平台 | mp_dzp(大转盘) |
payment | pay | 支付方式 | pay_alipay(支付宝) |
sms | sms | 短信 | sms_alidayu(阿里大于短信) |
shipping | ship | 配送方式 | ship_sf_express(顺丰速运) |
connect | sns | 第三方登陆 | sns_qq(QQ帐号登录) |
4、插件目录命名规范
插件目录命名规范:插件类型前缀 + 插件名 |
举例子:新建一个微信公众平台插件,插件名为 test
:
在 plugins
目录下新建 mp_test
目录:
5、如何定义插件
定义一个插件需要为插件新建一个插件入口主文件
,并必须遵循插件定义规范,插件入口主文件
是处理插件定义、注册、安装、卸载等最基本功能的文件,必须有。
举例子:定义 test
微信公众平台插件:
在
mp_test
目录下新建一个mp_test.php
命名规范:插件类型前缀_ + 插件名.php
(重点)插件描述信息是通过注释来定义的,下面为范例(注释不可或缺):
<?php /* Plugin Name: 测试插件 Plugin URI: http://www.ecjia.com/plugins/ecjia.mp_tests/ Description: 用于测试的插件。 Author: ECJIA TEAM Version: 1.18.0 Author URI: http://www.ecjia.com/ Plugin App: platform */ // 代码省略 // 。。。
Plugin Name:插件名称
Plugin URI:插件URL
Description:插件描述
Author:开发者
Version:版本号
Author URI:开发者地址
Plugin App:插件类型(必须指定一种插件种类,未指定无法使用插件)
在注释的下面新建一个类,类的命名必须遵守规范,里面的方法格式不建议改动:
类的命名规范: plugin_ + 插件目录名
下面为范例:
//类名:plugin_mp_test class plugin_mp_test { //安装插件方法 public static function install() { // 定义配置文件 $config = include(RC_Plugin::plugin_dir_path(__FILE__) . 'config.php'); $param = array('file' => __FILE__, 'config' => $config); return RC_Api::api('platform', 'plugin_install', $param); } //卸载插件方法 public static function uninstall() { // 定义配置文件 $config = include(RC_Plugin::plugin_dir_path(__FILE__) . 'config.php'); $param = array('file' => __FILE__, 'config' => $config); return RC_Api::api('platform', 'plugin_uninstall', $param); } }
6、插件注册、安装、卸载
在之前定义的类下面,添加一个继承方法来定义一个用于注册插件的文件:
需要注意继承的值为
插件目录名
,返回值也是插件目录名
,这里定义mp_test.class.php
为管理该插件的文件(后面章节会介绍管理插件文件的作用和开发方法)Ecjia_PluginManager::extend('mp_test', function() { require_once RC_Plugin::plugin_dir_path(__FILE__) . 'mp_test.class.php'; return new mp_test(); });
在继承方法下添加安装和卸载的方法:
需要注意注册的值为
plugin_ + 插件目录名
// 注册 test 微信公众平台插件 RC_Plugin::register_activation_hook(__FILE__, array('plugin_mp_test', 'install')); // 卸载 test 微信公众平台插件 RC_Plugin::register_deactivation_hook(__FILE__, array('plugin_mp_test', 'uninstall'));
7、插件配置文件介绍
每个插件的配置文件内容的项都是不同的,下面以微信公众平台插件为例:
在该插件根目录下新建一个config.php
文件
<?php
defined('IN_ECJIA') or exit('No permission resources.');
/**
* 微信公众平台配置菜单
*/
return array(
// 插件名称
'ext_code' => 'mp_test',
// 插件图标
'ext_icon' => 'images/icon_goods.png',
// 默认关键字
'commands' => ['test', '测试'],
// 子命令
'sub_code' => ['subfoo' ],
//仅支持微信公众平台
'support_platform' => 'wechat',
// 支持微信所有类型公众号
'support_platform_type' => ['service', 'unauthorized', 'subscribe', 'test'],
// 支持商家和平台
'support_type' => Ecjia\App\Platform\Plugin\PlatformAbstract::TypeAdmin | Ecjia\App\Platform\Plugin\PlatformAbstract::TypeMerchant,
// 表单配置项
'forms' => array(
),
);
// end
参数说明
- ext_code:插件名称,必须和插件目录一致
- ext_icon:插件图标,插件目录相对路径)
- commands:默认关键字。
- sub_code:子命令。
- support_platform:支持微信公众平台
- support_platform_type:支持微信公众号类型,可多选
- support_type:支持商家或平台
- forms:表单配置项(可选,可为空)
8、插件配置表单定义和验证、获取值
表单定义
编辑 config.php
配置文件,添加或修改 forms
字段
<?php
defined('IN_ECJIA') or exit('No permission resources.');
return array(
// ......
// 上省略
'forms' => array(
array('name' => 'test_value', 'type' => 'text', 'value' => ''),
array('name' => 'test_radio', 'type' => 'radio', 'value' => ''),
),
// 下省略
// ......
);
// end
参数说明
- name:配置项名称
- type:配置项类型(表单类型)
- text: 文本域
- password: 密码字段
- radio: 单选按钮
- checkbox: 复选框
- textarea: 文本域
- select: 下拉选项列表
- value:配置项默认值,注意:radio和checkbox无效。
要设置radio
和checkbox
的值,需要编辑语言包文件:
|
<?php
/**
* 测试语言文件
*/
defined('IN_ECJIA') or exit('No permission resources.');
return array(
// 将表单 name 'test_value' 本地化为‘测试文本框:’
'test_value' => '测试文本框:',
// 将表单 name 'test_radio' 本地化为‘测试单选:’
'test_radio' => '测试单选:',
'test_radio_range' => array(
// '表单值' => '显示值'
'86400' => '24小时',
'3600' => '1小时',
'60' => '1分钟',
),
);
表单获取
只需要一句话即可获取,以下为范例:
获取配置文件的test_value
的值
// 获取配置文件的test_value的值,存到$test_value变量
$test_value = $this->getConfig('test_value');
第二篇:公众平台插件开发
1、插件主类继承对象和实现方法
目录下新建一个 mp_test.class.php
文件,必须实现以下方法。
<?php
/**
* 微信测试
*/
defined('IN_ECJIA') or exit('No permission resources.');
// 新建mp_test类继承PlatformAbstract
class mp_test extends PlatformAbstract
{
/**
* 获取插件代号
*
* @see \Ecjia\System\Plugin\PluginInterface::getCode()
*/
public function getCode()
{
// 获取插件代号值应插件种类而异,微信公众平台插件代号为"ext_code"
return $this->loadConfig('ext_code');
}
/**
* 加载配置文件
*
* @see \Ecjia\System\Plugin\PluginInterface::loadConfig()
*/
public function loadConfig($key = null, $default = null)
{
// 加载"config.php"配置文件
return $this->loadPluginData(RC_Plugin::plugin_dir_path(__FILE__) . 'config.php', $key, $default);
}
/**
* 加载语言包
*
* @see \Ecjia\System\Plugin\PluginInterface::loadLanguage()
*/
public function loadLanguage($key = null, $default = null)
{
$locale = RC_Config::get('system.locale');
return $this->loadPluginData(RC_Plugin::plugin_dir_path(__FILE__) . '/languages/'.$locale.'/plugin.lang.php', $key, $default);
}
/**
* 获取iconUrl
* {@inheritDoc}
* @see \Ecjia\App\Platform\Plugin\PlatformAbstract::getPluginIconUrl()
*/
public function getPluginIconUrl()
{
// 获取iconUrl值因插件类型而异,部分插件没有图标,微信公众平台插件图标iconUrl为"ext_icon"
if ($this->loadConfig('ext_icon')) {
return RC_Plugin::plugin_dir_url(__FILE__) . $this->loadConfig('ext_icon');
}
return '';
}
/**
* 事件回复
* 注意:微信公众平台特有方法,用于事件回复,并且事件回复的出口必须写在这里。
* {@inheritDoc}
* @see \Ecjia\App\Platform\Plugin\PlatformAbstract::eventReply()
*/
public function eventReply() {
// 回复数据
$articles = array(
// 图文信息标题
'Title' => '测试插件',
// 图文信息正文
'Description' => '这是一个测试插件',
// 点击图文详细后跳转的链接
'Url' => '',
// 图文信息图片(获取images文件下wechat_thumb_pic_success.png图片)
'PicUrl' => RC_Plugin::plugin_dir_url(__FILE__) . '/images/wechat_thumb_pic_success.png',
);
return WechatRecord::News_reply($this->getMessage(), $articles['Title'], $articles['Description'], $articles['Url'], $articles['PicUrl']);
}
}
特别注意
getCode
方法获取插件代号值应插件种类而异,微信公众平台插件代号为"ext_code"getPluginIconUrl
方法获取iconUrl值因插件类型而异,部分插件没有图标,微信公众平台插件图标iconUrl为"ext_icon"eventReply
方法为微信公众平台特有方法,用于事件回复,并且事件回复的出口必须写在这里。
2、公众平台插件回复内容
|
/**
* 事件回复
* {@inheritDoc}
* @see \Ecjia\App\Platform\Plugin\PlatformAbstract::eventReply()
*/
public function eventReply() {
// 回复数据
$articles = array(
// 图文信息标题
'Title' => '测试插件',
// 图文信息正文
'Description' => '这是一个测试插件',
// 点击图文详细后跳转的链接
'Url' => '',
// 图文信息图片(获取images文件下wechat_thumb_pic_success.png图片)
'PicUrl' => RC_Plugin::plugin_dir_url(__FILE__) . '/images/wechat_thumb_pic_success.png',
);
return WechatRecord::News_reply($this->getMessage(), $articles['Title'], $articles['Description'], $articles['Url'], $articles['PicUrl']);
}
3、插件安装
平台后台点击 控制面板
,然后点击 插件管理
:
这时候找到制作的插件,点击 安装
:
如果一切顺利,可以看到:
4、插件开通关闭
进入公众平台管理界面
,点击插件管理
,这时候看到了我们在下方插件库
看到了测试插件:
点击测试插件
,点击开通
二次确认后即可开通
如果一切顺利,这时候返回插件库,可以看到提示已经安装了
停止反之,点击测试插件
,点击关闭
二次确认后即可关闭,
5、插件表单设置和获取
设置插件表单
点击测试插件
,可以看到配置表单。
尝试输入Hello ECjia!
,点击更新
按钮,即可保存该值。
获取插件表单
在上面的实例中添加了 test_value 这个配置项,并设置为 Hello ECJIa! 那么如何获取呢:
使用getConfig
方法即可获取,以下为范例:
// 获取配置文件的 test_value 的值,存到$test_value变量。
$test_value = $this->getConfig('test_value');
// 此时 $test_value 的值为 Hello ECJIa
6、使用公众平台测试工具调试插件返回内容
ECJia到家公众平台测试工具地址
https://testapi.ecjia.com/sites/wetest/
站点截图预览:
其中左边为配置区域:
配置名称 | 配置介绍 |
---|---|
加密调试 | 调试模式。有明文模式,兼容模式,安全模式 |
appID | 微信公众平台的appID |
appsecret | 微信公众平台的appsecret |
URL | 开发者填写URL,调试时将把消息推送到该URL上 |
Token | 微信公众平台设置的Token |
消息类型 | 各种消息事件,包含关注取消关注 |
发送用户 | 发送方帐号(一个OpenID) |
接受用户 | 开发者微信号 |
内容 | 消息类型(文本消息内容) |
发送消息 | 发送信息的内容,包含XML代码 |
接收消息 | 接受返回的内容,包含XML代码 |
右边为仿真的微信对话效果。
测试返回内容
举例子:测试 test插件
关键字回复的内容。
将左侧的加密调试设置为明文模式
,消息类型设置为文本
,内容为test
。
点击 检查问题
按钮,如果一切正常,会返回一个图文消息。
第三篇:插件高级配置
1、如何让插件仅支持平台或者商家
编辑插件配置文件 config.php
,修改 support_type
字段:
<?php
defined('IN_ECJIA') or exit('No permission resources.');
return array(
// ......
// 上省略
// 只支持平台
'support_type' => Ecjia\App\Platform\Plugin\PlatformAbstract::TypeAdmin,
// 下省略
// ......
}
support_type 可配置项:
- 只支持平台:Ecjia\App\Platform\Plugin\PlatformAbstract::TypeAdmin,
- 只支持商家:Ecjia\App\Platform\Plugin\PlatformAbstract::TypeMerchant,
- 支持平台和商家:Ecjia\App\Platform\Plugin\PlatformAbstract::TypeAdmin | Ecjia\App\Platform\Plugin\PlatformAbstract::TypeMerchant,
2、如何让插件支持公众平台类型
编辑插件配置文件 config.php
,修改 sub_code
字段:
<?php
defined('IN_ECJIA') or exit('No permission resources.');
return array(
// ......
// 上省略
// 仅支持微信服务号
'support_platform_type' => ['service'],
// 下省略
// ......
}
support_platform_type 可配置项:
- service:服务号
- unauthorized:未认证的服务号
- subscribe:订阅号
- test:测试号
配置项可多选,若要支持所有公众平台类型:
// 支持微信所有类型公众号
'support_platform_type' => ['service', 'unauthorized', 'subscribe', 'test'],
3、插件内如何判断商家或平台
获取类型是商家和平台可以通过 getStoreType
方法来获取:
// 获取类型
$type = $this->getStoreType();
// 如果为平台
if ($type = self::TypeAdmin) {
// 处理平台绑定用户
$content = $this->handleAdminBindUser();
}
// 如果为商家
else if ($type = self::TypeMerchant) {
// 处理商家绑定用户
$content = $this->handleMerchantBindUser();
}
返回值:
- self::TypeAdmin:平台
- self::TypeMerchant:商家
4、插件内如何转发请求到另一个插件
转发命令十分简单,已经封装成一句话:
// 转发到 mp_userbind 插件
return $this->forwardCommand('mp_userbind');
5、如何判断是否绑定用户
// ......
// 上省略
// 如果未绑定
if (! $this->hasBindUser()) {
// 转发到 mp_userbind 插件
return $this->forwardCommand('mp_userbind');
// 如果已绑定
} else {
// 代码块省略
// ......
}
// 下省略
// ......
6、子命令介绍与配置
子命令介绍
有时候某些功能大体都是一致的,区别很小,建议使用子命令,子命令可以让一个插件支持多个功能。
mp_goods
这个微信公众平台插件是个典型的例子,他支持五个子命令,一个插件拥有5种功能。
- best:精品商品
- hot:热门商品
- new:最新商品
- recommend:推荐商品
- promotion:促销商品
子命令配置
编辑管理配置文件mp_test.class.php
,修改eventReply
方法
/**
* 事件回复
* {@inheritDoc}
* @see \Ecjia\App\Platform\Plugin\PlatformAbstract::eventReply()
*/
public function eventReply() {
// 获取命令实例
$commandInstance = $this->getCommandInstance();
// 返回
return $commandInstance->handleEventReply();
}
新建getCommandInstance
方法,通过getSubCodeCommand
方法来获取子命令。
protected function getCommandInstance()
{
// $this->getSubCodeCommand()获取子命令
if ($this->getSubCodeCommand()) {
switch ($this->getSubCodeCommand()) {
// 子命令subfoo
case 'subfoo':
// 加载子命令管理配置文件
require_once RC_Plugin::plugin_dir_path(__FILE__) . 'mp_test_subfoo.class.php';
// 设置子命令对象参数
$subCommand = $this->subCommand(new mp_test_subfoo());
break;
// 其他子命令
// 默认命令
default:
$subCommand = $this->subCommand($this);
break;
}
// 返回子命令数据
return $subCommand;
} else {
return $this;
}
}
新建mp_test_subfoo.class.php
文件,下面为示例:
注意事项:子命令类继承主插件类,这里为mp_test |
<?php
// 导入命名空间
use Ecjia\App\Wechat\WechatRecord;
defined('IN_ECJIA') or exit('No permission resources.');
// 注意继承主管理配置文件类 mp_test
class mp_test_subfoo extends mp_test
{
/**
* 子命令事件回复
*/
protected function handleEventReply()
{
// 简单的回复示例
$articles = [
'content' => '测试子命令'
];
return WechatRecord::News_reply($this->getMessage(), $articles['content']);
}
}
// end
第四篇:插件页面控制器
1、介绍插件页面控制器
控制器是处理该插件有关逻辑的php文件,一般我们都创建一个默认为init
的控制器为该应用的主控制器;当然你可以根据需要的情况以init_
为前缀创建多个控制器。
2、控制器的命名规则介绍
RC_Uri::url('platform/plugin/show',array('handle' => 'mp_test/init',) 'openid' => openid, 'uuid' => uuid)
一般情况下,前面部分不需要改变,
代表平台插件地址,后面的参数将影响访问的插件地址:
- 【handle】:插件名称【mp_test】/ 文件名
- 【openid】:传递openid
- 【uuid】:传递uuid
3、控制器的创建及示例
在 test
插件下新建 init.php
,
在插件跟目录新建一个 init.php
文件,加入以下继承类:
use Ecjia\App\Platform\Frameworks\Contracts\PluginPageInterface;
use Ecjia\App\Platform\Frameworks\Controller\PluginPageController;
然后新建一个 mp_zjd_init
类,注意继承:
类名命名规则:插件名 + 文件名 |
class mp_php_init extends PluginPageController implements PluginPageInterface
新建两个function:
public function init()
{
//设置插件目录
$this->setPluginPath(__FILE__);
//加载插件js资源
$this->assginPluginStyleUrl('test_js', 'js/test.js');
$this->assginPluginStyleUrl('jquery_js', 'js/jquery.js');
//代码省略,一般设置插件目录和设置资源URL
}
public function action()
{
//初始化资源URL加载
$this->init();
// 下省略
// ......
}
4、控制器内加载资源和调用模板
加载资源
|
编辑页面控制器 init.php
文件,加载资源:
注意事项: |
public function init()
{
//设置插件目录
$this->setPluginPath(__FILE__);
// 加载插件js资源
// 第一个参数为smarty变量名,第二个参数为文件相对路径
$this->assginPluginStyleUrl('test_js', 'js/test.js');
$this->assginPluginStyleUrl('jquery_js', 'js/jquery.js');
// 设置插件css资源
// 第一个参数为smarty变量名,第二个参数为文件相对路径
$this->assginPluginStyleUrl('test_css', 'css/test.css');
$this->assginPluginStyleUrl('bootstrap_css', 'css/bootstrap.css');
// 设置图片资源
// 第一个参数为smarty变量名,第二个参数为文件相对路径
$this->assginPluginStyleUrl('test_png', 'images/test.png');
}
public function action()
{
//初始化资源URL加载
$this->init();
// 下省略
// ......
}
调用模板
插件根目录下新建一个 templates
文件夹,然后在 templates
文件夹下新建一个 test_index.dwt.php
文件
test_index.dwt.php
为网站模板页,如果你需要多个访问页面可以新建多个:
然后只需要编辑页面控制器 init.php
文件,加入一行代码即可引用此页面:
// 引用templates目录下test_index.dwt.php模板页
ecjia_front::$controller->display($this->getPluginFilePath('templates/test_index.dwt.php'));
5、页面禁止微信客户端外打开
编辑页面控制器 init.php
文件,在 init
方法加入以下代码:
public function init()
{
// ......
// 上省略
// 禁止微信客户端外打开
if (!ecjia_is_weixin()) {
$uuid = trim($_GET['uuid']);
$url = with(new Ecjia\App\Wechat\Authorize\WechatAuthorize($uuid))->getAuthorizeUrl(RC_Uri::current_url());
$this->redirect($url);
}
// 下省略
// ......
}
第五篇:高级技巧
1、插件抽象方法介绍
获取iconurl:
abstract public function getPluginIconUrl()
插件返回数据统一接口:
abstract public function eventReply();
加载语言包:
public function loadLanguage($key = null, $default = null);
$key:key值
$default:默认值
加载配置文件:
public function loadConfig($key = null, $default = null);
$key:key值
$default:默认值
获取插件代号:
public function getCode()
2、插件类常用方法介绍
获取子命令数组
public function getSubCode()
获取默认插件使用命令
public function getDefaultCommands()
设置消息
public function setMessage($message)
$message:消息
获取消息
public function getMessage()
获取 store_id
public function getStoreId()
获取 openid
public function getOpenId()
设置商家类型(平台,商家)
public function setStoreType($store_type)
$store_type:商家类型。可选参数:TypeAdmin,TypeMerchant
获取商家类型(平台,商家)
public function getStoreType()
设置公众号类型
public function setPlatformTypeCode($platform_type)
$platform_type:公众号类型
获取公众号类型
public function getPlatformTypeCode()
设置关键字
public function setKeyword($keyword)
$keyword:关键字
获取关键字
public function getKeyword()
获取该命令是否支持公众号
public function hasSupport($store_type)
$store_type:商家类型
获取公众平台插件支持平台公众号
public function hasSupportTypeAdmin()
转发命令,这里直接使用插件代号
public function forwardCommand($ext_code, $sub_code = null)
$ext_code:插件代号
$sub_code:插件子命令
3、插件类动态方法介绍
检测公众平台粉丝是否绑定用户
public function hasBindUser()
获取ECJIA user的user_id快捷方法
public function getEcjiaUserId()
获取WechatUser对象
public function getWechatUser()