插件开发
插件开发
关键词:插件开发,二次开发一、插件的安装卸载机制介绍
OpenSNS的插件支持云市场在线安装和本地安装。
如果要能够被OpenSNS识别并允许安装卸载。开发人员需要遵守以下约定。
目录结构约定:
插件文件放置在
/Addons 下
每一个插件的目录结构如下
以 CheckIn(签到)插件为例
· CheckIn
o Controller //控制器目录,有URL访问的时候才需要,可选
§ CheckInController.class.php //插件控制器,名字可以不和插件名一样
o Model //插件的Model
§ CheckInModel.class.php
o Static
§ images //放置插件所需用到的图片
§ js // 插件js文件放置的文件夹
§ css //插件的css文件放置的文件夹
o View //插件的模版文件
§ default
§ CheckIn
§ ranking.html
§ checkin.html //插件模板页面,一般直接放在插件的目录下。这里放在了View文件夹下。
§ rank.html
o CheckInAddon.class.php //插件定义和实现的文件,必须有!!
o config.php // 插件的配置文件
插件的生命周期:
安装插件
使用插件
卸载插件
安装插件
用管理员帐号打开网站后台->云市场->插件管理->未安装;从中找到《签到》插件。
点击安装按钮进行安装。提示安装成功则表示插件已经安装成功,此时可以在已安装的选项卡中找到《签到》插件
安装成功后,钩子摆放的位子将会出现签到的组件。如下:
卸载插件
用管理员帐号打开网站后台->云市场->插件管理->已安装;从中找到《签到》插件。
点击卸载按钮提示“卸载成功”则表示插件已经成功卸载。如之后不再使用该插件可以删除插件目录下相关文件。
二、插件的开发----以签到插件为例
1、设计插件,并创建钩子。如“签到”插件所需用到的钩子有 checkIn、rank、handleAction
2、 在Addons下创建插件文件夹并命名插件名字为 CheckIn
3、创建插件的定义和实现文件,与插件名字同名,即CheckInAddon.class.php
4、编写插件信息,以及安装和卸载的方法。如下
<?php
namespace
Addons\CheckIn;
use
Common\Controller\Addon;
/**
* 签到插件
* @author 嘉兴想天信息科技有限公司
*/
class
CheckInAddon
extends
Addon
{
/**
* 插件的信息,必须。
*/
public
$info
=
array
(
'name'
=>
'CheckIn'
,
//插件的英文名
'title'
=>
'签到'
,
//插件的中文名
'description'
=>
'签到插件'
,
//插件的描述
'status'
=> 1,
//插件的状态
'author'
=>
'xjw129xjt(肖骏涛)'
,
//插件的作者
'version'
=>
'0.1'
//插件的版本号
);
/**
* 插件的安装方法。不需要创建任何表则直接return true;
*/
public
function
install()
{
$prefix
= C(
"DB_PREFIX"
);
D()->execute(
"DROP TABLE IF EXISTS `{$prefix}checkin`"
);
D()->execute(<<<SQL
CREATE TABLE IF NOT EXISTS `{
$prefix
}checkin` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`uid` int(11) NOT NULL,
`create_time` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
SQL
);
D()->execute(<<<SQL
ALTER TABLE `{
$prefix
}member` ADD `con_check` INT NOT NULL DEFAULT
'0'
,
ADD `total_check` INT NOT NULL DEFAULT
'0'
;
SQL
);
return
true;
}
/**
* 插件的卸载方法。不需删除任何表则直接返回 true。
*/
public
function
uninstall()
{
$prefix
= C(
"DB_PREFIX"
);
D()->execute(
"DROP TABLE IF EXISTS `{$prefix}checkin`"
);
D()->execute(<<<SQL
ALTER TABLE `{
$prefix
}member`
DROP `con_check`,
DROP `total_check`;
SQL
);
return
true;
}
// 接下去编写钩子的实现方法。
}
5、继续编写钩子对应的实现方法。在CheckInAddon.class.php文件中。如下
public
function
checkIn(
$param
)
{
$model
=
$this
->checkInModel();
$uid
= is_login();
$check
=
$model
->getCheck(
$uid
);
$this
->assign(
'check'
,
$check
);
$this
->assignDate();
$html
=
$this
->rank(
'today'
);
$this
->assign(
'html'
,
$html
);
$this
->display(
'View/checkin'
);
}
private
function
checkInModel()
{
return
D(
'Addons://CheckIn/CheckIn'
);
}
public
function
rank(
$type
)
{
$time
= get_some_day(0);
$rank
= S(
'check_rank_'
.
$type
.
'_'
.
$time
);
if
(
empty
(
$rank
)) {
$model
=
$this
->checkInModel();
$rank
=
$model
->getRank(
$type
);
S(
'check_rank_'
.
$type
.
'_'
.
$time
,
$rank
, 300);
}
$this
->assign(
'rank'
,
$rank
);
$this
->assign(
'type'
,
$type
);
$this
->assign(
'type_ch'
,
$type
==
'con'
?
'连签'
:
'累签'
);
$html
=
$this
->fetch(
'View/rank'
);
return
$html
;
}
private
function
assignDate()
{
$week
=
date
(
'w'
);
switch
(
$week
) {
case
'0'
:
$week
=
'周日'
;
break
;
case
'1'
:
$week
=
'周一'
;
break
;
case
'2'
:
$week
=
'周二'
;
break
;
case
'3'
:
$week
=
'周三'
;
break
;
case
'4'
:
$week
=
'周四'
;
break
;
case
'5'
:
$week
=
'周五'
;
break
;
case
'6'
:
$week
=
'周六'
;
break
;
}
$this
->assign(
'day'
,
date
(
'Y.m.d'
));
$this
->assign(
'week'
,
$week
);
}
public
function
doCheckIn()
{
$time
= get_some_day(0);
$uid
= is_login();
$model
=
$this
->checkInModel();
$memberModel
= D(
'Member'
);
$check
=
$model
->getCheck(
$uid
);
if
(!
$check
) {
$model
->addCheck(
$uid
);
$memberModel
->where(
array
(
'uid'
=>
$uid
))->setInc(
'total_check'
);
$model
->checkYesterday(
$uid
);
clean_query_user_cache(
$uid
,
array
(
'con_check'
,
'total_check'
));
S(
'check_rank_today_'
.
$time
, null);
S(
'check_rank_con_'
.
$time
, null);
S(
'check_rank_total_'
.
$time
, null);
return
true;
}
else
{
return
false;
}
}
public
function
handleAction(
$param
)
{
$config
=
$this
->getConfig();
if
(!
empty
(
$config
[
'action'
])) {
$action_info
= M(
'Action'
)->getByName(
$config
[
'action'
]);
if
(
$action_info
[
'id'
] ==
$param
[
'action_id'
]) {
$res
=
$this
->doCheckIn();
if
(
$res
) {
$param
[
'log_score'
] .=
'签到成功!'
;
return
$res
;
}
}
}
return
false;
}
6、编写对应Controller、Model、和模版。与模块相似。
与模块不同的地方有:
(1)调用Controller:模块中调用Controller用U()函数,在插件中用addons_url();
(2)调用Model:在插件中调用Model 需要在D()函数中写明资源等信息,如: D('Addons://CheckIn/CheckIn');即为实例化Addons下的CheckIn插件中的CheckInModel;
(3)模版的渲染与模块相同。
7、插件的配置文件的编写
<?php
return
array
(
'action'
=>
array
(
'title'
=>
'签到绑定行为:'
,
'type'
=>
'select'
,
'options'
=>get_option(),
)
);
/**
* 以下为调用函数。配置文件的主体为以上的数组
*/
function
get_option(){
$opt
= D(
'Action'
)->getActionOpt();
$return
=
array
(0=>
'不绑定'
);
foreach
(
$opt
as
$v
){
$return
[
$v
[
'name'
]] =
$v
[
'title'
];
}
return
$return
;
}
数组的每个键都对应一个form表单。键名就是配置里会显示的表单名。title是字段前面的标识字。type是form标准的type。然后有多个选项的会有options键和值是相应选项的数组。值里每个键是选项的value后面的值是显示的label文字。value字段是该表单项的默认值。 tip是表单项后面的提示文字。
支持Group分组 : 每个group里值options就是多个配置分组tab。然后分组显示名是其title。然后options里是每个配置的复合数组。那个写法和之前单独的配置一样。
用 同步登录插件的配置文件做展示,如下:
<?php
return
array
(
'type'
=>
array
(
'title'
=>
'开启同步登陆:'
,
'type'
=>
'checkbox'
,
'options'
=>
array
(
'Qq'
=>
'Qq'
,
'Sina'
=>
'Sina'
,
'Weixin'
=>
'Weixin'
,
),
),
'meta'
=>
array
(
//配置在表单中的键名 ,这个会是config[title]
'title'
=>
'接口验证代码:'
,
//表单的文字
'type'
=>
'textarea'
,
//表单的类型:text、textarea、checkbox、radio、select等
'value'
=>
''
,
//表单的默认值
'tip'
=>
'需要在Meta标签中写入验证信息时,拷贝代码到这里。'
),
'bind'
=>
array
(
//配置在表单中的键名 ,这个会是config[title]
'title'
=>
'是否开启帐号绑定:'
,
//表单的文字
'type'
=>
'radio'
,
//表单的类型:text、textarea、checkbox、radio、select等
'options'
=>
array
(
'1'
=>
'是'
,
'0'
=>
'否'
,
),
'value'
=>
'0'
,
'tip'
=>
'不开启则跳过与本地帐号绑定过程,建议审核时关闭绑定。'
),
'group'
=>
array
(
'type'
=>
'group'
,
'options'
=>
array
(
'Qq'
=>
array
(
'title'
=>
'QQ配置'
,
'options'
=>
array
(
'QqKEY'
=>
array
(
'title'
=>
'QQ互联APP ID:'
,
'type'
=>
'text'
,
'value'
=>
''
,
'tip'
=>
'申请地址:http://connect.qq.com'
,
),
'QqSecret'
=>
array
(
'title'
=>
'QQ互联APP KEY:'
,
'type'
=>
'text'
,
'value'
=>
''
,
'tip'
=>
'申请地址:http://connect.qq.com'
,
)
),
),
'Sina'
=>
array
(
'title'
=>
'新浪配置'
,
'options'
=>
array
(
'SinaKEY'
=>
array
(
'title'
=>
'新浪App Key:'
,
'type'
=>
'text'
,
'value'
=>
''
,
'tip'
=>
'申请地址:http://open.weibo.com/'
,
),
'SinaSecret'
=>
array
(
'title'
=>
'新浪App Sercet:'
,
'type'
=>
'text'
,
'value'
=>
''
,
'tip'
=>
'申请地址:http://open.weibo.com/'
,
)
),
),
'Weixin'
=>
array
(
'title'
=>
'微信配置'
,
'options'
=>
array
(
'WeixinKEY'
=>
array
(
'title'
=>
'微信App Key:'
,
'type'
=>
'text'
,
'value'
=>
''
,
'tip'
=>
'申请地址:https://open.weixin.qq.com/'
,
),
'WeixinSecret'
=>
array
(
'title'
=>
'微信App Sercet:'
,
'type'
=>
'text'
,
'value'
=>
''
,
'tip'
=>
'申请地址:https://open.weixin.qq.com/'
,
)
),
)
)
)
);
8、插件到这里基本就算开发完成了。去后台安装一下吧。
eg:部分内容摘自onethink 插件开发指南 : http://document.onethink.cn/manual_1_0.html#onethink_3_5
插件和钩子介绍
关键词:插件,钩子一、什么是插件
插件是用于扩展系统的功能的一些独立“组件”。
插件的定位是用于实现某些简单的显示及数据处理的功能扩展。
二、什么是钩子
讲到插件,不得不讲钩子。首先,我们之前说明了插件是一个扩展的功能实现。
既然是扩展的,那么就要很灵活、可复用,并不是像我们之前开发项目,一个功能实现了,就写死在代码里了。
项目其他地方要用了,怎么办,复制一份改个名,改的那个地方能调用实现。这样一次两次可以,次数多了就不行了。
因为后面每次开发的底层架构在不断变化。不断重复的功能版本造成人力的浪费。我们做成插件的目的就是为了方便大家扩展我们这个产品的功能。到时候形成规模,大家自由的搭建自己的站点就方便了。
那么如何让一个扩展的功能在多个地方可随意的使用呢。那就用到了我们的钩子。
为什么叫它钩子呢?因为它的作用就是如此和生活中的钩子类似。
打个比方,我们做的网站比作一个有多个功能的立式衣架。
这个衣架给什么人用就有不同的用途。
假如你专门用来挂大衣的,那就是大衣衣架。如果你专门挂袋子,那就是一个储物衣架。
当你不想要某个挂件、衣服时,取下来即可。并不会破坏原有的袋子或者衣服的功能。
你挂与不挂,钩子就在那里。
为什么能挂那么多东西呢?说明被挂的东西都符合一个标准:能挂的住。
换作你挂一个橡皮泥、或者棉花之类的。挂不了多久就会掉了。因为他们不符合要有部分封闭的可固定的这一个部分的标准。
还有挂一个太重的比如10个背包挂一个钩子上。要么架子毁了,要么钩子断了。总之就是挂不住。
因为任何一个钩子都有其承重上限。你加起来的超过了,肯定不行。
所以我们不能把插件当成万能的使,什么东西都整成插件,不管功能的大小。
任何系统都有瓶颈,你不能把个重量级的东西做成插件后挂上,说不定以后就会影响整个站点。就违背了插件的独立性原则。那些就不应该做成插件而是做成模型扩展或者应用扩展。