介绍
介绍
TFAPI开发标准模块的操作指南,通过 TFAPI 框架的最初简单版本开发一个标准的功能页面,页面包括基本的增、删、改、查功能
准备工作
基本信息
模块名称(必选):表示模块的唯一名称,示例:user
数据表(必须):用于存储模块数据的物理数据表,示例:基本信息表 user,详细信息表 user_detail
数据表结构
user
CREATE TABLE user ( userId INT NOT NULL AUTO_INCREMENT, userName VARCHAR(45) NOT NULL, userPass CHAR(32) NOT NULL DEFAULT '', regDT DATETIME NULL, logDT DATETIME NULL, logTimes INT NOT NULL DEFAULT 0, PRIMARY KEY (userId) );
user_detail
CREATE TABLE user_detail ( userId INT NOT NULL DEFAULT 0, realName VARCHAR(45) NOT NULL DEFAULT '', introduce TEXT NOT NULL DEFAULT '', PRIMARY KEY (userId) );
模块设计
对象模型
对象模型依据一张数据表一个对应模型的基本原则设计,一个数据表必须对应着一个对象模型,模型完成对数据表中的数据的读写操作
示例:包括基本信息对象 TFModel_user,详细信息对象 TFModel_userDetail
对象API
对象API用于连接对象模型对外提供资源数据的存取功能
对象API遵循RESTFul规范设计
对象API格式
接口格式
用于响应常规接口调用,返回数据格式如下
{
"status":"状态信息",
"message":"内容信息"
}
表单处理程序格式
仅用于框架表单处理使用,返回数据格式如下
{
"action":"错误信息",
"errmsg":"报错表单提示信息",
"errname":"报错表单元素名称"
}
示例:提供一个 user 资源
对象视图
对象视图用于展示模块的用户操作界面功能,通过内建 JS 组件实现功能界面,包括完整的数据表格功能,操作表单功能
内建 JS 组件依赖 VueJS 实现
示例:实现一个 user 功能页面,包括基本的增、删、改、查功能
对象模板
对象模板是对象视图的载体,用于将对象视图的用户操作界面展示到用户面前
对象模板基于 Smarty 框架实现
示例:完成一个 user 功能模板,挂载 user 视图
程序文件
对象模型
对象模型
WEB-INF/Classes/Models/user.inc.php
对象API
读取数据接口
WEB-INF/Classes/Views/api/user.inc.php
添加数据接口
WEB-INF/Classes/Views/api/user/actionAdd.inc.php
修改数据接口
WEB-INF/Classes/Views/api/user/actionMod.inc.php
删除数据接口
WEB-INF/Classes/Views/api/user/actionDel.inc.php
添加表单处理程序
WEB-INF/Classes/Views/api/user/action_add.inc.php
修改表单处理程序
WEB-INF/Classes/Views/api/user/action_mod.inc.php
删除表单处理程序
WEB-INF/Classes/Views/api/user/action_del.inc.php
对象视图
用户界面程序
WEB-INF/Classes/Views/user.inc.php
用户界面脚本
js/pages/user.js
用户界面样式表
css/pages/user.css
对象模板
用户界面模板
WEB-INF/Templates/Tpl/user.html
程序代码
路由
PC路由
WEB-INF/Classes/Controllers/Route/PC.inc.php
class PCEntry extends TFSystemHtml{
public function __construct($opts){
// init
parent::__construct($opts, "index", "index");
// meta
$this->PEO->setItem('author', (isset($opts['author'])) ? $opts['author'] : '作者信息', 'Metas');
$this->PEO->setItem('keywords', (isset($opts['keywords'])) ? $opts['keywords'] : '关键词,关键词2,关键词3...', 'Metas');
$this->PEO->setItem('description', (isset($opts['description'])) ? $opts['description'] : '网页介绍', 'Metas');
// js & css
$this->PEO->appendItem('Jses', 'extends@js/jquery/2.1.1/jquery-2.1.1.min');
$this->PEO->appendItem('Jses', 'extends@js/vue/2.5.16/vue-2.5.16.dev');
$this->PEO->appendItem('Jses', 'tfjs');
$this->PEO->appendItem('Jses', 'plugins/UI.Vue');
$this->PEO->appendItem('Jses', 'pc');
$this->PEO->appendItem('Csses', 'pc');
// system
$this->PEO->initLog();
$this->PEO->initTFCache();
// set rest default ( temp )
$restClientObj = new TFRESTClient($this->PEO, TFConfig::getV('restInternalRoot', 'UriPrefix'));
$this->PEO->setItem('rest', $restClientObj);
// set user envTFJS
$this->PEO->items['envTFJS']['env']['imgRoot'] = TFConfig::getV("imgRoot", "UriPrefix");
$this->smartyObj->setForceCompile(true);
}
protected function prepareOP(){
$myPageLoaderObj = new TFPageLoader($this->PEO, $this->smartyObj);
$myPageLoaderObj->load();
$this->PEO->title = $this->PEO->title . " - 同福网 - TONGFU.net";
}
}
API路由
WEB-INF/Classes/Controllers/Route/API.inc.php
class APIEntry extends TFSystemRest{
public function __construct($opts){
// init
parent::__construct($opts);
// system
$this->PEO->initLog();
$this->PEO->initTFDO();
$this->PEO->initTFCache();
// set rest default ( temp )
$restClientObj = new TFRESTClient($this->PEO, TFConfig::getV('restInternalRoot', 'UriPrefix'));
$this->PEO->setItem('rest', $restClientObj);
// set user envTFJS
$this->PEO->items['envTFJS']['env']['imgRoot'] = TFConfig::getV("imgRoot", "UriPrefix");
}
protected function prepareData(){
$myRESTLoaderObj = new TFRESTLoader($this->PEO);
$myRESTLoaderObj->auth(
// enable auth
true,
// rules
array(
// default auth method
'default' => "public",
// no default models
'noDefaultModels' => array(
),
// user auth methods
'matches' => array(
),
// no auth models
'noAuthModels' => array(
),
)
);
$myRESTLoaderObj->load();
return $myRESTLoaderObj->getData();
}
}
公开认证模式
WEB-INF/Classes/Controllers/Auth/public.inc.php
class TFAuth_public extends TFAuthorize{
protected function prepare($opts){
$authData = array();
// public
return $this->makeData("AUTHORIZED", "success", $authData);
}
}
对象模型
对象模型
WEB-INF/Classes/Models/user.inc.php
class TFModel_user extends TFAction{
public function __construct($PEO){
parent::__construct($PEO,
"#user#", // 数据表名称,表名称前后的#用于默认的表名称前缀和表名称后缀
"userId" // 数据表主见字段名称,关联主键通过数组传入
);
$this->setCacheName("user" // 数据缓存名称
);
$this->setCacheMode(TFActionCacheMode::T_MODE_SINGLE);
$this->setOpt('UKName', "userName"); // 设置字段userName是约束
}
}
class TFModel_userDetail extends TFAction{
public function __construct($PEO){
parent::__construct($PEO,
"#user_detail#", // 数据表名称,表名称前后的#用于默认的表名称前缀和表名称后缀
"userId", // 数据表主键字段名称,关联主键通过数组传入
TFActionPKType::T_PK_UNI // 主键类型使用UNIQUE
);
$this->setCacheName("user" // 数据缓存名称
);
$this->setCacheMode(TFActionCacheMode::T_MODE_SINGLE);
}
}
对象API
读取数据接口
WEB-INF/Classes/Views/api/user.inc.php
class TFResource_user extends TFResource{
protected function prepareTableData($opts){
$pageSize = 10;
$pageNumber = 1;
$sql = $this->model->getDBO()->GS("SELECT
u.userId, u.userName, ud.realName, u.regDT, u.logDT, u.logTimes
FROM #user# u
LEFT JOIN #user_detail# ud
ON u.userId = ud.userId
");
$datas = $this->model->getTableBySql($sql,
array(
'disableAutoSort' => false, // 关闭自动排序功能
'pageSize' => $pageSize, // 设置每页显示条目数
'pageNumber' => $pageNumber, // 设置当前页码
)
);
return $datas;
}
protected function prepareRowData($ID, $opts){
$dataRow = $sql = $this->model->getDBO()->DR("SELECT
u.userId, u.userName, u.regDT, u.logDT, u.logTimes
FROM #user# u
LEFT JOIN #user_detail# ud
ON u.userId = ud.userId
WHERE u.userId = Integer", $ID);
return $dataRow;
}
protected function prepareRowsData($IDs, $opts){
$dataRows = $sql = $this->model->getDBO()->DT("SELECT
u.userId, u.userName, u.regDT, u.logDT, u.logTimes
FROM #user# u
LEFT JOIN #user_detail# ud
ON u.userId = ud.userId
WHERE u.userId in NumericList", $IDs);
return $dataRows;
}
}
添加数据接口
WEB-INF/Classes/Views/api/user/actionAdd.inc.php
class TFResource_user_add extends TFResource{
protected function prepareAction(){
$myUserMdlObj = new TFModel_user($this->PEO);
$myUserDetailMdlObj = new TFModel_userDetail($this->PEO);
$post = $this->PEO->input->rest->data;
// do add
$dupUserId = $myUserMdlObj->getID($post['user']);
if($dupUserId > 0){
return $this->actionResultData('error', 'user_exists', array('errmsg' => "用户名已存在", 'errname' => "user"));
}
$retBase = $myUserMdlObj->add(array(
'userName'=>$post['user'],
'userPass'=>md5($post['pwd']),
'regDT'=>date("Y-m-d H:i:s"),
));
if($retBase === false){
return $this->actionResultData('error', 'user_save_failed', array('errmsg' => "系统忙碌,请稍后再试"));
}
$newAutoId = $myUserMdlObj->getLIID();
$retDetail = $myUserDetailMdlObj->add(array(
'userId'=>$newAutoId,
'realName'=>$post['realName'],
'introduce'=>$post['introduce'],
));
if($retDetail === false){
return $this->actionResultData('error', 'user_detail_save_failed', array('errmsg' => "系统忙碌,请稍后再试"));
}
return $this->actionResultData('success', 'ok', array('userid' => $newAutoId));
}
}
修改数据接口
WEB-INF/Classes/Views/api/user/actionMod.inc.php
class TFResource_user_mod extends TFResource{
protected function prepareAction(){
$myUserMdlObj = new TFModel_user($this->PEO);
$myUserDetailMdlObj = new TFModel_userDetail($this->PEO);
$post = $this->PEO->input->rest->data;
$dataId = $this->PEO->input->server->tfargv['user'];
// check current
$userInfo = $myUserMdlObj->get($dataId);
$userDetailInfo = $myUserDetailMdlObj->get($dataId);
if($userInfo === false || $userDetailInfo === false){
return $this->actionResultData('error', 'user_not_exists', array('errmsg' => "用户数据不存在", 'errname' => "user"));
}
// do modify
$retBase = $myUserMdlObj->mod($dataId, array(
'userPass'=>md5($post['pwd']),
));
if($retBase === false){
return $this->actionResultData('error', 'user_update_failed', array('errmsg' => "系统忙碌,请稍后再试"));
}
$retDetail = $myUserDetailMdlObj->mod($dataId, array(
'realName'=>$post['realName'],
'introduce'=>$post['introduce'],
));
if($retDetail === false){
return $this->actionResultData('error', 'user_detail_update_failed', array('errmsg' => "系统忙碌,请稍后再试"));
}
return $this->actionResultData('success', 'ok', array('userid' => $dataId));
}
}
删除数据接口
WEB-INF/Classes/Views/api/user/actionDel.inc.php
class TFResource_user_del extends TFResource{
protected function prepareAction(){
$myUserMdlObj = new TFModel_user($this->PEO);
$myUserDetailMdlObj = new TFModel_userDetail($this->PEO);
$post = $this->PEO->input->rest->data;
$dataId = $this->PEO->input->server->tfargv['user'];
// check current
$userInfo = $myUserMdlObj->get($dataId);
$userDetailInfo = $myUserDetailMdlObj->get($dataId);
if($userInfo === false || $userDetailInfo === false){
return $this->actionResultData('error', 'user_not_exists', array('errmsg' => "用户数据不存在", 'errname' => "user"));
}
// do delete
$retBase = $myUserMdlObj->del($dataId);
if($retBase === false){
return $this->actionResultData('error', 'user_delete_failed', array('errmsg' => "系统忙碌,请稍后再试"));
}
$retDetail = $myUserDetailMdlObj->del($dataId);
if($retDetail === false){
return $this->actionResultData('error', 'user_detail_delete_failed', array('errmsg' => "系统忙碌,请稍后再试"));
}
return $this->actionResultData('success', 'ok', array('userid' => $dataId));
}
}
添加表单处理程序
WEB-INF/Classes/Views/api/user/action_add.inc.php
class TFResource_user_add extends TFResource{
protected function prepareAction(){
$myDataValidateObj = new TFFormValidate();
$myUserMdlObj = new TFModel_user($this->PEO);
$myUserDetailMdlObj = new TFModel_userDetail($this->PEO);
$post = $this->PEO->input->post->getArray();
// set data valid rules
$myDataValidateObj->setDataValidRules(array(
'user' => array('rule' => "max:20;min:2;", 'msgs' => array('用户名最多20个字符', '用户名最少2个字符')),
'pwd' => array('rule' => "max:20;min:6;", 'msgs' => array('密码最多20个字符', '密码最少6个字符')),
'vpwd' => array('rule' => "max:20;min:6;", 'msgs' => array('两次输入的密码不一样', '两次输入的密码不一样')),
));
if(!$myDataValidateObj->dataValidationAuto($post, $errors)){
foreach($errors as $errname => $errmsg){
return $this->formResultData('error', array('errmsg' => $errmsg, 'errname' => $errname));
}
}
// check verify pwd
if($post['pwd'] != $post['vpwd']){
return $this->formResultData('error', array('errmsg' => "两次输入的密码不一样", 'errname' => "vpwd"));
}
// do add
$dupUserId = $myUserMdlObj->getID($post['user']);
if($dupUserId > 0){
return $this->formResultData('error', array('errmsg' => "用户名已存在", 'errname' => "user"));
}
$retBase = $myUserMdlObj->add(array(
'userName' => $post['user'],
'userPass' => md5($post['pwd']),
'regDT' => date("Y-m-d H:i:s"),
));
if($retBase === false){
return $this->formResultData('error', array('errmsg' => "系统忙碌,请稍后再试"));
}
$newAutoId = $myUserMdlObj->getLIID();
$retDetail = $myUserDetailMdlObj->add(array(
'userId' => $newAutoId,
'realName' => $post['realName'],
'introduce' => $post['introduce'],
));
if($retDetail === false){
return $this->formResultData('error', array('errmsg' => "系统忙碌,请稍后再试"));
}
return $this->formResultData('success', array('userid' => $newAutoId));
}
}
修改表单处理程序
WEB-INF/Classes/Views/api/user/action_mod.inc.php
class TFResource_user_mod extends TFResource{
protected function prepareAction(){
$myDataValidateObj = new TFFormValidate();
$myUserMdlObj = new TFModel_user($this->PEO);
$myUserDetailMdlObj = new TFModel_userDetail($this->PEO);
$post = $this->PEO->input->post->getArray();
$dataId = $this->PEO->input->server->tfargv['user'];
// set data valid rules
$myDataValidateObj->setDataValidRules(array(
'pwd' => array('rule' => "max:20;min:6;", 'msgs' => array('密码最多20个字符', '密码最少6个字符')),
'vpwd' => array('rule' => "max:20;min:6;", 'msgs' => array('两次输入的密码不一样', '两次输入的密码不一样')),
));
if(!$myDataValidateObj->dataValidationAuto($post, $errors)){
foreach($errors as $errname => $errmsg){
return $this->formResultData('error', array('errmsg' => $errmsg, 'errname' => $errname));
}
}
// check current
$userInfo = $myUserMdlObj->get($dataId);
$userDetailInfo = $myUserDetailMdlObj->get($dataId);
if($userInfo === false || $userDetailInfo === false){
return $this->formResultData('error', array('errmsg' => "用户数据不存在", 'errname' => "user"));
}
// do modify
$retBase = $myUserMdlObj->mod($dataId, array(
'userPass'=>md5($post['pwd']),
));
if($retBase === false){
return $this->formResultData('error', array('errmsg' => "系统忙碌,请稍后再试"));
}
$retDetail = $myUserDetailMdlObj->mod($dataId, array(
'realName'=>$post['realName'],
'introduce'=>$post['introduce'],
));
if($retDetail === false){
return $this->formResultData('error', array('errmsg' => "系统忙碌,请稍后再试"));
}
return $this->formResultData('success', array('userid' => $dataId));
}
}
删除表单处理程序
WEB-INF/Classes/Views/api/user/action_del.inc.php
class TFResource_user_del extends TFResource{
protected function prepareAction(){
$myUserMdlObj = new TFModel_user($this->PEO);
$myUserDetailMdlObj = new TFModel_userDetail($this->PEO);
$post = $this->PEO->input->post->getArray();
$dataId = $this->PEO->input->server->tfargv['user'];
// check current
$userInfo = $myUserMdlObj->get($dataId);
$userDetailInfo = $myUserDetailMdlObj->get($dataId);
if($userInfo === false || $userDetailInfo === false){
return $this->formResultData('error', array('errmsg' => "用户数据不存在", 'errname' => "user"));
}
// do delete
$retBase = $myUserMdlObj->del($dataId);
if($retBase === false){
return $this->formResultData('error', array('errmsg' => "系统忙碌,请稍后再试"));
}
$retDetail = $myUserDetailMdlObj->del($dataId);
if($retDetail === false){
return $this->formResultData('error', array('errmsg' => "系统忙碌,请稍后再试"));
}
return $this->formResultData('success', array('userid' => $dataId));
}
}
对象视图
用户界面程序
WEB-INF/Classes/Views/user.inc.php
class userPage extends TFPage{
public function load(){
}
}
用户界面脚本
js/pages/user.js
/**
* table box
*/
TFHomeUI.registerTableBox(
'user-list',
{
info: {
id: 'user-list',
list_rest_url: 'api/user',
list_params: {},
cbfield: 'userId',
actions_visible: true,
user_actions: '<a class="btn btn-default" @click="showAddDlg">新建</a>',
},
titles: [
{label: "ID", field: "userId", sort: "desc", width: 80},
{label: "名称", field: "userName", sort: "none"},
{label: "姓名", field: "realName", sort: "none", width: 80},
{label: "创建时间", field: "regDT", sort: "none", width: 100},
{label: "最后登录", field: "logDT", sort: "none", width: 80},
{label: "登录次数", field: "logTimes", sort: "none", width: 80},
{label: "操作", field: "_opers_", width: 120}
],
callbacks: {
filterData: function (d) {
$.forEach(d.data, function (item, idx) {
d.data[idx]['_opers_'] = '<a class="btn btn-white btn-xs" data-id="' + item.userId + '" onclick="TFHomeUI.getTable(\'user-list\').showModDlg(this)">修改</a> ' +
'<a class="btn btn-white btn-xs" data-id="' + item.userId + '" onclick="TFHomeUI.getTable(\'user-list\').showDelDlg(this)">删除</a> ';
});
return d;
}
}
},
{
mounted: function () {
},
methods: {
showAddDlg: function () {
TFHomeUI.loadFormBoxInDialog(
'user-add'
);
},
showModDlg: function (e) {
var userId = TFHomeUI.getRowDataId(e);
if (userId) {
$.getREST('api/user/' + userId, {}, function (d) {
TFHomeUI.loadFormBoxInDialog(
'user-mod',
null,
{
data: {
form: {
info: {
action: $.U('api/user/' + userId + '/_mod')
},
data: d
}
}
}
);
});
}
},
showDelDlg: function (e) {
var userId = TFHomeUI.getRowDataId(e);
if (userId) {
$.getREST('api/user/' + userId, {}, function (d) {
TFHomeUI.loadFormBoxInDialog(
'user-del',
null,
{
data: {
form: {
info: {
action: $.U('api/user/' + userId + '/_del')
},
data: d
}
}
}
);
});
}
}
}
}
);
/**
* form box ( user-add )
*/
TFHomeUI.registerFormBox(
'user-add',
{
info: {
title: '新建用户',
descript: '新建用户',
method: 'post',
action: $.U('api/user/_add')
},
validators: {
user: {triggers: ['blur'], rules: [{min: 2, msg: '用户名最少2个字符'}, {max: 20, msg: '用户名最多20个字符'}]},
pwd: {triggers: ['blur'], rules: [{min: 6, msg: '密码最少6个字符'}]},
vpwd: {
triggers: ['blur'], rules: [{
fun: function (form, elem, name) {
return (form.vpwd.value != form.pwd.value);
}, msg: '两次输入的密码不一致'
}]
}
},
elements: {
user: {
type: 'text',
label: '用户名',
name: "user"
},
pwd: {
type: 'password',
label: '密码',
name: "pwd"
},
vpwd: {
type: 'password',
label: '确认密码',
name: "vpwd"
},
realName: {
type: 'text',
label: '姓名',
name: "realName"
},
introduce: {
type: 'textarea',
label: '介绍',
name: "introduce"
},
submit: {
type: "submit",
name: "smt",
value: "提交"
}
}
},
{
methods: {
onSuccess: function (d) {
TFHomeUI.getTableBox('user-list').gotoPage(1);
}
}
}
);
/**
* form box ( user-mod )
*/
TFHomeUI.registerFormBox(
'user-mod',
{
info: {
title: '修改用户',
descript: '修改用户',
method: 'post',
action: $.U('api/user/_mod')
},
validators: {
pwd: {triggers: ['blur'], rules: [{min: 6, msg: '密码最少6个字符'}]},
vpwd: {
triggers: ['blur'], rules: [{
fun: function (form, elem, name) {
return (form.vpwd.value != form.pwd.value);
}, msg: '两次输入的密码不一致'
}]
}
},
elements: {
userName: {
type: 'static',
label: '姓名',
name: "userName"
},
pwd: {
type: 'password',
label: '密码',
name: "pwd"
},
vpwd: {
type: 'password',
label: '确认密码',
name: "vpwd"
},
realName: {
type: 'text',
label: '姓名',
name: "realName"
},
introduce: {
type: 'textarea',
label: '介绍',
name: "introduce"
},
submit: {
type: "submit",
name: "smt",
value: "保存"
}
}
},
{
mounted: function () {
this.form.elements.user.value = this.form.data.userName;
this.form.elements.realName.value = this.form.data.realName;
this.form.elements.introduce.value = this.form.data.introduce;
},
methods: {
onSuccess: function (d) {
TFHomeUI.getTableBox('user-list').gotoPage(1);
}
}
}
);
/**
* form box ( user-del )
*/
TFHomeUI.registerFormBox(
'user-del',
{
info: {
title: '删除用户',
descript: '删除用户',
method: 'post',
action: $.U('api/user/_del')
},
validators: {},
elements: {
user: {
type: 'static',
label: '用户名',
name: 'user'
},
submit: {
type: "submit",
name: "smt",
value: "删除"
}
}
},
{
mounted: function () {
this.form.elements.user.value = this.form.data.userName;
},
methods: {
onSuccess: function (d) {
TFHomeUI.getTableBox('user-list').gotoPage(1);
}
}
}
);
function pageLoad() {
TFHomeUI.loadTableBox(
'user-list',
null,
{
compBoxSL: '.user-list'
}
);
}
用户界面样式表
css/pages/user.css
body{
}
对象模板
用户界面模板
WEB-INF/Templates/Tpl/user.html
<!DOCTYPE html>
<html>
<head>
<% $_TFPage->getHead() %>
</head>
<body>
<div class="wrapper">
<div class="wrapper-content">
<div class="row user-list">
</div>
</div>
</div>
</body>
</html>
<% $_TFPage->getFoot() %>
测试
API测试
添加数据测试
POST请求
POST /api/user HTTP/1.1
Content-Type: application/json
{
"user":"test1",
"pwd":"123456",
"realName":"测试1",
"introduce":"这是一个测试而已"
}
返回结果
{
"status": "success",
"message": "ok",
"userid": "1"
}
修改数据测试
PUT请求
PUT /api/user/1 HTTP/1.1
Content-Type: application/json
{
"pwd":"12345678",
"realName":"修改一下1",
"introduce":"这是测试1的修改内容"
}
返回结果
{
"status": "success",
"message": "ok",
"userid": "1"
}
删除数据测试
DELETE请求
DELETE /api/user/1 HTTP/1.1
返回结果
{
"status": "success",
"message": "ok",
"userid": "6"
}
界面测试
数据表格页面
打开网址 /user
添加表单
修改表单
删除表单