-
Notifications
You must be signed in to change notification settings - Fork 5
Module Programming Guide
这是 Module 机制的第 1.2 版实现,可能尚有很多不足,欢迎大家及时提出建议并修改。此外,BaseModule
类的文档来自代码中的 PHPDoc,还没来得及翻译。
开发者可以通过编写自己的 Module 来为系统添加新的功能。
系统的所有功能都以独立模块的形式存在,保存在modules
目录下。每个 Module 均包含一个以 Module 的名称来命名的文件夹,里面需要至少包含一个名为index.php
的文件,而index.php
中必须包含一个同样以 Module 的名称来命名的类,该类继承自BaseModule
类。
例如,一个最简单的 Module(称为SayHello
)的文件结构如下:
/modules
/SayHello
index.php
其中,index.php
中包含类SayHello
,它继承自BaseModule
。
The BaseModule class is the base class that you subclass in order to implement certain services. A service takes user input that is passed to it, does some queries according to the input data, and returns the result message to user.
For example, a phone book service might take a valid name in the database and returns the phone number associated to that name.
This class must be subclassed before it can be used.
When subclassing, you must always override the following methods and use them to provide information about your module:
prepare
can_handle_input
raw_output
display_name
Prepares your module.
public function prepare()
The default implementation of this method does nothing. This method is called right after the module is loaded, which is prior to receiving user messages. If your service requires background execution, you can use this method to register action hooks.
Returns a boolean indicating whether the service can act on the input data.
public function can_handle_input(UserInput $input)
类型 | 名称 | 描述 |
---|---|---|
UserInput |
$input |
An object representing user's input. |
true
if your service can act on the specified input data or false
if it cannot.
The default implementation of this method returns false. Subclasses must override it and return true if the input data in the input
parameter can be operated by your service. Your implementation should check the contents of the object and determine if your service can act on the corresponding data.
The engine internally calls this method when determining which service to apply to user's message.
Returns a standard-compliant string as the output of your service.
public function raw_output(UserInput $input)
类型 | 名称 | 描述 |
---|---|---|
UserInput |
$input |
An object representing user's input. |
The output string (in XML format).
This method returns empty string by default. Subclasses must override this method and returns a valid XML string as per the API documentation by WeChat.
Also see WeChat API Documentation for more information.
It's recommended to use OutputFormatter
to construct the output string.
Returns the display name of your module.
public function display_name()
The human-readable name of your module (string).
This method returns the class name by default. Subclasses may override this method and returns a more human-readable name if the module has a settings page.
系统为 Module 开发者准备了一套涉及后台运行以及数据持久化的 API。这部分 API 不属于 BaseModule
类,开发者可以在任何时候直接调用相应的函数。
系统允许开发者的 Module 在不必响应用户输入(即can_handle_input
返回false
)的情况下获取系统的某些运行时数据,并据此执行相应的操作。这对于非面向用户的 Module(例如负责统计各种输入类型的百分比的 Module)来说非常有用。
系统提供了 add_action
, remove_action
, remove_all_actions
和 has_action
四个方法。
在某个事件发生时执行自定义函数。
function add_action($tag, $object, $function_to_add, $priority = 10)
类型 | 名称 | 描述 |
---|---|---|
string |
$tag |
事件的名称 |
BaseModule |
$object |
所属的模块,实际调用时总是使用$this
|
callable |
$function_to_add |
要执行的函数名称 |
integer |
$priority |
函数执行的优先级,较大的数值(高优先级)代表首先被执行 |
成功返回true
,失败(例如该函数已经被添加)返回false
。
这里的函数名称($function_to_add
)和所属的 Module 有关,不同 Module 之间的同名函数不会发生冲突。
调用函数时,系统保证按照$priority
所指定的顺序调用一个 Module 下所有已添加的函数,但是不保证这些函数是被连续调用的。
删除某个事件发生时本 Module 要执行的函数。
function remove_action($tag, $object, $function_to_remove)
类型 | 名称 | 描述 |
---|---|---|
string |
$tag |
事件的名称 |
BaseModule |
$object |
所属的模块,实际调用时总是使用$this
|
callable |
$function_to_remove |
要删除的函数名称 |
如果要删除的函数不存在,这个函数将不采取任何操作。开发者只能删除自己 Module 下的函数。
删除某个事件发生时本 Module 要执行的所有函数。
function remove_all_actions($tag, $object)
类型 | 名称 | 描述 |
---|---|---|
string |
$tag |
事件的名称 |
BaseModule |
$object |
所属的模块,实际调用时总是使用$this
|
判断某个事件发生时本 Module 是否会执行一个函数。
function has_action($tag, $object, $function_to_check)
类型 | 名称 | 描述 |
---|---|---|
string |
$tag |
事件的名称 |
BaseModule |
$object |
所属的模块,实际调用时总是使用$this
|
callable |
$function_to_check |
要判断的函数名称 |
如果该函数已被添加,返回true
,否则返回false
。
不同事件提供的参数不同,被添加函数的最大参数个数由具体事件决定,通常为 0 个到多个。被添加的函数所接收的参数可以少于相应事件所提供的参数。
目前,系统中包含的事件如下:
-
message_received
,发生于接收到用户消息时。提供 1 个参数,为UserInput
对象,包含用户输入。 -
modules_missed
,发生于所有 Module 均没被调用,即用户输入无效时。提供 1 个参数,为UserInput
对象,包含用户输入。 -
module_hit
,发生于将要调用某个 Module 之前,提供 2 个参数,分别为一个UserInput
对象(包含用户输入)以及一个string
(为被调用的 Module 的名称)。
根据文档,我们可以在系统接收到用户输入时将输入的内容打印出来:
public function prepare() {
add_action('message_received', $this, 'log_message');
}
public function log_message($input) {
print_r($input);
}
如果我们不关心用户具体输入了什么,只希望在用户输入时得到通知,则可以:
public function prepare() {
add_action('message_received', $this, 'log_message');
}
public function log_message() {
echo 'Message Received!';
}
系统包含一个轻量级的持久化存储引擎,称为 Configuration API,以 Key-Value 形式存取数据。这套 API 对于存储 Module 的设定数据是非常合适的。
备注:Configuration API 需要数据库中有configuration
数据表。
存储一个值。
function set_value($object, $key, $value)
类型 | 名称 | 描述 |
---|---|---|
BaseModule |
$object |
当前 Module 对象,使用时一般传入$this
|
string |
$key |
索引 |
mixed |
$value |
值,允许string 或array 类型 |
若成功存储,返回true
,否则返回false
。
获取一个值。
function get_value($object, $key)
类型 | 名称 | 描述 |
---|---|---|
BaseModule |
$object |
当前 Module 对象,使用时一般传入$this
|
string |
$key |
索引 |
若找到对应的值则会返回它(可能为string
或array
类型),否则返回null
。
public function log_message($input) {
if (get_value($this, 'print') == true)
print_r($input);
}
Module 可根据需要创建自己的设置页面,并自动集成到后台的 Admin Panel(/admin/index.php
)中。创建设置页面是非常简单的。
在 Module 的根目录下创建一个名为 settings.php
的文件。系统会自动检测到该文件并在后台生成相应的设置页面。
如果你想让你的 Module 的设置页面风格统一,就以一个<h2>
标题开头:
<h2>你的设置页面名称</h2>
接下来,你需要创建 HTML 表单。使用如下的代码:
<form method="POST" action="index.php">
添加表单项的方法和一般表单很类似。一个最简单的例子如下:
<input type="text" name="user-email" value="<?php echo get_option('user-email') ?>">
如果想让表单的风格和系统自带设置项的风格保持统一,请使用如下结构:
<div class="form-group">
<div class="prompt">
<label for="user-email">输出设定</label>
<p class="note">提示信息(显示在左侧,可选)</p>
</div>
<div class="control">
<input type="text" class="form-control" name="user-email" id="user-email" value="<?php echo get_option('user-email') ?>">
<p class="note">提示信息(显示在右侧,可选)</p>
</div>
</div>
用户提交表单后,所输入的值会被自动被系统储存,并可随时在settings.php
中利用get_option($option_name)
函数读取,或在 Module 的index.php
中利用get_value($this, $option_name)
函数读取。其中$option_name
即该设置项的名称,与input
标签的name
属性的值相同。两个函数均可能返回字符串或数组。
Module 开发者只需设计表单,用户提交后数据的更新由系统在后台自动完成。
目前已确定支持的有:
- 单行文本:
<input type="text">
- 单选框:
<input type="radio">
- 复选框:
<input type="checkbox">
- 下拉菜单:
<select>
- 多项下拉菜单:
<select multiple>
- 多行文本:
<textarea>
当name
为某一个值的所有复选框均没有被选中时,该字段不会被发送到服务器,因此无法更新数据。为了避免这一 bug,在每一组<input type="checkbox">
之前必须手动添加一个同名的<input type="hidden">
。例子:
<?php $in4 = get_option('in4') ?>
<input type="hidden" name="in4[]">
<input type="checkbox" name="in4[]" value="v4-1" <?php if (in_array('v4-1', $in4)) echo 'checked' ?>> Product A
<input type="checkbox" name="in4[]" value="v4-2" <?php if (in_array('v4-2', $in4)) echo 'checked' ?>> Product B
<input type="checkbox" name="in4[]" value="v4-3" <?php if (in_array('v4-3', $in4)) echo 'checked' ?>> Product C
使用如下代码来结束你的 HTML 表单:
<?php submit_button(); ?>
</form>
不指定任何参数的情况下,对submit_button()
的调用将产生如下代码:
<button type="submit" name="wx_submit" class="button submit-button"><i class="fa fa-check"></i>Submit</button>
submit_button
函数的实际原型为:
function submit_button($text = 'Submit', $class = '')
开发者可以通过指定额外的参数来自定义按钮的文字以及class
属性。
此外,开发者也可以添加一个“重设表单”按钮,来将设置项恢复为默认值。方法:
<?php reset_button('reset_form()'); ?>
该函数调用会产生如下代码:
<button class="button reset-button" onclick="reset_form();return false;">Reset</button>
其中reset_form()
为自定义 JavaScript 函数调用,需要开发者自行实现:
function reset_form() {
// reset the form
}
这样,用户点击该按钮后就会调用reset_form
函数。而reset_button
函数的实际原型为:
function reset_button($callback = '', $text = 'Reset', $class = '')
和submit_button
类似,开发者可以添加额外参数,来修改按钮的文字以及class
属性。
开发者可以重写 display_name
函数来修改 Module 在 Admin Panel 中显示的名称。
系统集成了 jQuery.Validation 插件,建议开发者直接使用该插件提供的 API 来进行表单验证。例如,要设置一个<input type="text">
为必填,只需添加一个required
属性:
<input class="form-control" type="text" name="in1" id="in1" value="<?php echo get_option('in1') ?>" required>
最后,为表单(form
元素)调用validate
方法来启用表单验证:
$("#my-form").validate();
更多用例,请参考 jQuery.Validation 的官方文档。
实例 Module 中 MessageStat 实现了一个简单的设置页面。
目前的示例 Module 包括: