thinksns 核心架构及目录结构
术语解释
核心:源自ThinkPHP框架,为系统提供MVC分离、底层数据库支持等核心功能,并提供诸多便捷的类库和函数库供系统其他部分使用。位于/core/目录。
服务:一组全局通用的类库,实现对特定功能的封装。位于/addons/services/目录,如邮件发送(Mail)、用户认证(Passport)等。
公共Model:一组全局通用模型。位于/addons/models/目录,如附件模型(AttachModel)、地区模型(AreaModel)等。
插件:为实现某种功能而增加的程序文件。位于/addons/plugins/目录,包括第三方平台登陆插件和勋章两种。
Widget:一组可以在任意HTML页面调用的代码块。位于/addons/widgets/目录,包括评论(Comment)、选择好友(SelectFriend)等。
第三方类库:其他开源的第三方类库。位于/addons/libs/目录,如phpmailer等。
应用:实现特定功能的独立模块,基于上述的系统结构构建。位于/apps/目录,如日志(Blog)、相册(Photo)等。
API:应用程序编程接口(Application Programming Interface)。位于/api/目录,如微博API、用户资料API等。
--------------------------------------------------------------------------------------------------------------------------------------
微博
微博虽然也是以系统独立应用的身份出现(如图1所示),但它还肩负着系统核心应用的责任。许多系统元素完全构建于微博应用之上,如微博Widget(即“分享”功能)是直接操作微博,而WAP应用则是完全使用微博API架构。
漫游平台
系统应用中另一个特例是漫游应用。漫游应用来源于康盛的漫游平台,由于漫游平台的URL根据UCHome的目录结构生成,这与ThinkSNS的目录结构完全不同,而且还需兼顾到漫游平台的可移植性,所以集成的漫游应用不走标准的ThinkSNS2.0核心,而是使用漫游应用内部已实现的一个最简版框架。
如果您是模版开发人员,那您得特别留意!因为您在公共目录下修改完头部和左侧的页面后,还要修改漫游下的头部和左侧
(位于/apps/myop/themes/classic/目录)。
------------------------------------------------------------------------------------------------------------------------------------------
目录结构
ThinkSNS2.0
├─ _runtime ------------- 运行时缓存
├─ addons ------------- 扩展库
│ ├─ libs ------------- 第三方类库
│ ├─ models ------------- 公共Model
│ ├─ plugins ------------- 插件
│ │ ├─ login ------------- 第三方平台登录插件
│ │ ├─ Medal ------------- 勋章
│ │ └─ Tags ------------- 标签
│ ├─ services ------------- 系统服务
│ └─ widgets ------------- 系统Widget
├─ api ------------- API库
├─ apps ------------- 系统应用
│ ├─ admin ------------- 管理后台
│ ├─ home ------------- Home应用
│ ├─ myop ------------- 漫游应用
│ ├─ wap ------------- 手机WAP端
│ └─ weibo ------------- 微博应用
├─ core ------------- 核心
│ ├─ sociax ------------- 系统核心文件
│ ├─ ThinkPHP ------------- ThinkPHP核心
│ └─ sociax.php ------------- 核心引导文件
├─ data ------------- 站点数据
├─ install ------------- 系统安装文件
├─ public
│ ├─ admin ------------- 管理后台的样式
│ ├─ js ------------- 系统JS库
│ └─ themes ------------- 系统模板
├─ access.php ------------- 节点权限控制文件
├─ cleancache.php ------------- 缓存清理文件
├─ config.inc.php ------------- 站点配置文件
├─ index.php ------------- 站点入口文件
├─ shorturl.php ------------- 短地址文件
└─ thumb.php ------------- 自动缩略图生成文件
------------------------------------------------------------------------------------------------------------------------------
应用架构及目录结构
应用的目录位置及结构:
ThinkSNS2.0
├─ apps
├─ app
├─ Appinfo ------------- 安装信息、安装卸载执行文件、图标
├─ Common ------------- 函数库common.php
├─ Conf ------------- 项目配置config.php
├─ Language ------------- 通知、动态的语言包
├─ Lib
│ ├─ Action ------------- 操作类库
│ ├─ Model ------------- 模型类库
│ └─Widget ------------- 插件库
└─ Tpl ------------- 模板、css、js文件
入口文件
ThinkSNS2.0只有一个公共入口文件,即ThinkSNS目录下的index.php.
URL 模式
URL的访问方式是index.php?app=APP_NAME&mod=Action&act=function
函数库
应用自身的函数库放在该应用目录下的Common/common.php 里即可,这里面的函数会随该应用一起加载,可在该应用内随意调用。系统函数库请参阅附录的“函数库”。
模板
[……]
10 / 32
应用的样式文件统一存放在的Tpl 下的Public/目录,通过../Public/xxx.css引用,应用的JS文件统一放到应用项目下的Tpl/下的Public/js/目录,通过../Public/js/xxx.js引用。
--------------------------------------------------------------------------------------------------------------------
开发指南
3.1命名规范与编码规范
参考ThinkPHP的命名与编码规范:http://thinkphp.cn/Manual/20
3.2使用函数库、类库和Widget
使用系统函数库
系统函数位于/core/sociax/functions.php和/core/sociax/extend.php文件,为全局有效函数,可以直接调用。
如获取用户昵称的方法:$uname = getUserName($uid);
使用服务
服务位于/addons/services/目录下,通过service('serviceName')->method ($param); 来使用服务。
如验证用户是否登录的方法:$is_logged = service('Passport')->isLogged();
使用公共Model
公共Model位于/addons/models/目录下,通过model('modelName')->method ($param);来使用公共Model。
如获得地区列表的方法:$area_list = model('Area')->getAreaList();
使用Widget
Widget位于/addons/widgets/目录下,通过W('widgetName',array('param'=> 'value'))来调用Widget。一般Widget是用在页面中,所以调用方法为:{:W('widgetName',
11 / 32
array('param'=>'value'))}。
如在页面中展示可能认识的人的方法:{:W('RelatedUse',array('uid'=>'1'))}
使用第三方类库
第三方类库一般放置在/addons/libs/目录下,使用前通过include_once等函数将文件引入即可。
3.3使用弹出窗、提示消息、编辑器
在ThinkSNS2.0的世界里,jQuery库是我们默认的JS框架,它在页面头部自动载入。ThinkSNS2.0在jQuery的基础上对弹出窗、提示消息和KISSY编辑器进行了封装,本节主要介绍它们的使用方法(jQuery库官方文档:http://docs.jquery.com/Main_Page)。
弹出窗
图2 弹出窗效果图
如图2所示,弹出窗至少包含标题、关闭按钮和内容三部分,为保证用户操作的连贯性,一般会在内容部分添加“确定”和“取消”按钮。
弹出窗的调用方法:
function yourFunc() {
ui.box.load(your_url, {title:'这里是标题'});
}
在your_url中放置弹出窗的内容。注意:“确定”和“取消”按钮也是内容的一部分!
关闭弹出窗:
function close() {
ui.box.close();
}
12 / 32
提示消息
图3 提示消息效果图
调用方法:
function success() {
ui.success("更新完成");
}
function error() {
ui.error("新Email已存在");
}
编辑器
编辑相关的JS在页面头部自动载入,只需要调用E = KISSY.Editor("idOfTextarea"); 即可完成编辑器的加载。如:
$(document).ready(function(){
E = KISSY.Editor("idOfTextarea");
});
3.4 ThinkPHP开发指南
ThinkPHP官方文档– 开发指南:http://thinkphp.cn/Manual/50
ThinkPHP官方文档– 模板指南:http://thinkphp.cn/Manual/194
3.5应用开发
看了前面的介绍和说明,相信大家已经蠢蠢欲动。本章以开发礼物应用为例为大家展示开发一个应用的全过程。如果你是ThinkPHP 开发高手,你会发现开发一个应用其实就是创建一个新的项目,这也是ThinkSNS2.0 的魅力所在:应用独立化。
13 / 32
开发流程
ThinkSNS2.0应用开发的一般流程:
1. 创建数据库和数据表(没有数据库操作可略过)
2. 项目命名并创建项目目录
3. 创建控制器类
4. 创建模型类
5. 创建模板文件
6. 运行和调试
开发需求和开发目标
我们的礼物应用需要实现以下的功能:
1. 用户可以给关注的人或粉丝发送礼物
2. 用户可以看到自己送出去的全部礼物
3. 用户可以看到别人送给自己的全部礼物
4. 用户可以回赠礼物给好友
5. 用户发送礼物时能同时发送通知信息
6. 用户发送礼物成功后可发送微博分享消息
7. 管理员可在后台增加,修改,删除礼物及礼物种类
8. 管理员可在后台配置礼物的积分消费种类:积分?经验?
9. 实现完善的积分消费功能,如果用户积分不足则不能赠送
创建数据表
根据上面的需求分析可知,我们需要设计三张数据表,一个用来保存礼物的分类信息,另一个用来保存礼物的信息,还有一张用来保存用户之间的送礼记录。增加数据表请注意表的命名格式:数据库表前缀+表名,其中数据库表前缀在config.inc.php里的DB_PREFIX 常量已经定义。
增加礼物分类表:
字段
类型
说明
id
int
name
varchar
分类名
status
tinyint
是否启用0禁用1启用(默认)
cTime
int
创建时间
增加两个默认分类:热门礼物、最新上架
增加礼物信息表:
字段
类型
说明
id
int
categoryId
int
分类ID,对应上面的分类表的ID
name
varchar
礼物名
num
int
库存
14 / 32
price
int
价格
img
varchar
礼物图片
status
tinyint
是否启用0 禁用1 启用(默认)
cTime
int
创建时间
在这里我们当然也要预先准备好部分礼物,即初始化的礼物信息。
增加送礼记录表:
字段
类型
说明
id
int
fromUserId
int
送礼人ID
toUserId
int
送礼对象
giftPrice
int
价格
giftImg
varchar
礼物图片
sendInfo
text
附加信息
sendWay
tinyint
赠送的方式:1 公开2 私下3 匿名
cTime
int
创建时间
到此,数据表设计完毕。
在应用程序目录下的/gift/Appinfo/文件夹里的install.sql文件包含了上述建表和插入预定义数据的sql语句。
创建应用目录
图4 应用目录结构
如上图所示,我们先在/apps/目录下增加礼物目录gift,然后在/apps/gift/目录下创建上图所示的目录(请注意大小写)。
应用程序目录Lib:
应用程序目录下存放的是Action控制器和Model模型的文件。
应用模板目录Tpl:
由于本次礼物应用只有一套模板,因此我们直接在Tpl/目录创建默认模板目录default/,然后在default/目录下添加我们需要的Index 模板和一个公共模板目录Public/。
公共函数目录Common:
这里可以存放本次应用的公共函数,文件名为common.php,该文件会在执行过程中自动加载,这些函数在Action/ 和Model/目下的文件里可以直接使用,无需再次引入文件。同时我们还可以直接使用ThinkSNS2.0里的公共函数,这些函数保存在
15 / 32
/core/sociax/文件夹下的fuctions.php和extend.php里,它包括我们最常用的数据处理或者数据获得,如h()、t()过滤函数,getUserName()函数(在模板文件的调用方法为: {$userId|getUserName})、getUserFace()函数和friendlyDate()函数(用法同getUserName())。以上的几个函数推荐大家使用。
应用配置目录Conf:
如果应用里有需要修改系统默认的常量或者在里面添加项目需要的一些配置参数,就需要在项目的Conf/目录下面,创建一个名称是config.php 的配置文件,该文件也会自动加载。公共函数目录和应用配置目录非必需的目录,视应用开发决定是否需要。本次礼物开发中只用到公共函数文件夹。
语言目录Language:
用以保存应用的系统通知模板和动态模板。本次礼物开发中将用到系统通知模板。在Language/目录下创建中文语言包目录cn/,然后添加通知模板文件notify.php (动态是同样的道理,只是文件名为:feed.php)。
安装包目录Appinfo:
用于在ThinkSNS后台的应用安装/卸载操作,必须包含info.php文件(用以获取应用信息),如果含有install.php或uninstall.php文件,则会在应用安装、卸载时自动调用。
开始编程
公共函数层
在Common/目录下,新建common.php文件(注意文件名的大小写),写入所需函数,如获取应用配置参数的函数:
function getConfig($key=NULL){
[……]
}
详细代码请参见该文件。
这个文件里的函数在Action/ 、Model/ 和Tpl/目录下的文件都可以直接使用。
MODEL层
在Lib/Model/目录下,新建三个文件GiftCategoryModel.class.php,GiftModel.class.php 和UserGiftModel.class.php,分别创建代码如下:
class GiftCategoryModel extends Model{ }
class GiftModel extends Model{ }
class UserGiftModel extends Model{ }
通过以上步骤,我们现在已将数据库表和模型类建立了关联关系。在项目的Action 类和Model 类中,已可以直接对数据库进行相关操作。
有些人习惯在Model 类里封装一些方法,这样更符合MVC 规范,也有一些人习惯把方法都写在Action 里,方便程序的阅读,这主要看个人习惯。本次开发将基本方法写进入Model 层里。详细代码请参见相应文件。
ACTION层
在Lib/Action/目录下,建立IndexAction.class.php,并创建代码如下:
class IndexAction extends Action{ }
详细代码参加该文件。
模板层
16 / 32
我们在Tpl/default/目录下需要两个文件夹:Index和Public。Index文件夹名是与IndexAction.class.php文件对应,表示Index文件夹下面的文件都是IndexAction.class.php文件所需要的全部模板。应用的公共文件我们一般放到Tpl/default/Public/目录下,比如礼物应用的礼物图片、JS文件、CSS文件、应用头文件_mainNav.html等。当然,这些目录的设置完全由开发者自己决定,只要保证调用文件的路径正确就可以了。
我们先来看看ThinkSNS2.0 模板文件的一般结构,开发人员引入本应用自己的样式文件和JS 文件后可直接在画布层里增加相应的显示代码即可:
[……]
详细内容请参阅具体代码。下面介绍模板文件中几处有学习价值的代码。
1. ThinkSNS2.0 全面使用jQuery 技术,jQuery 是一个不错的轻量级的JS框架,能帮助我们快速的开发JS 应用,并在一定程度上改变了我们写JavaScript代码的习惯。ThinkSNS2.0 在头文件里已经引入jQuery 库,开发人员不必重复引入。
2. Tpl/default/Index/目录下的index.html文件,这是礼物中心的模板,里面选择发送好友的功能用到好友选择widget,只需要在模板里增加{:W("SelectFriend")},然后用$_POST['fri_ids']就可以获得选择的好友ID.
3. 因为我们是用findPage()方式获取收到和送出的礼物列表,故返回的数据已经有分页的变量了,只要在模板合适的地方增加如下的代码即可:
17 / 32
增加积分消费功能
上面的程序基本完成了礼物的全部操作,接下来我们要增加积分消费功能。至于礼物消费的积分类型,是积分或者还是经验,可以在后台设置,详细请看后台程序说明。首先在发送礼物页面增加显示当前用户所拥有多少积分的功能,我们只要在IndexAction.class.php文件的index()方法里增加以下程序即可:
//获取当前用户的积分
$money = X('Credit')->getUserCredit($this->mid);
$moneyType = getConfig('credit');
$this->assign('money',$money[$moneyType]);
在发送礼物的模板里增加以下一行代码:
我目前拥有的 {$money.alias}是:{$money.credit}
然后在发送礼物的函数里(UserGiftModel.class.php 的sendGift()方法)增加扣除所选礼物的相应积分程序:
//扣除相应积分
$giftPrice = intval($giftInfo['price']);
$prices = $userNum*$giftPrice;
$moneyType = getConfig('credit');
//积分操作
$setCredit = X('Credit');
//检测积分是否足够
$userCredit = $setCredit->getUserCredit($fromUid);
if($userCredit[$moneyType]['credit']
return $userCredit[$moneyType]['alias'].'不足,赠送失败~';
}
$setCredit->setUserCredit($fromUid,array($moneyType=>$prices),-1);
这里调用了公共类库services中的积分操作类,即X('Credit')。
到这里积分消费功能增加完毕。
增加发通知功能
首先需要增加礼物的通知模板。在Language/目录下创建一个文件夹cn,再在cn文件夹下创建通知模板文件notify.php,代码如下:
return array(
'gift_send' => array(
'title' => '{actor}给您送了一个礼物',
'body' => $img.'
'.$sendback.'
'.$content.'
去看看
18 / 32
',
),
);
?>
在发送礼物成功后增加以下程序:
//给接收人发送通知
$this->__doNotify($toUser,$sendInfo,$giftInfo,$fromUid,$appId);
__doNotify() 方法的实现请参阅具体代码。
这里调用了公共类库services中的系统通知类,即X('Notify')。
到这里发通知功能完成了。
增加发送动态功能
发送动态的机制与发送通知的机制完全相同,区别只有如下两点:
通知使用/Language/cn/feed.php,而动态使用/Language/cn/notify.php
通知服务使用X('Notify')或service('Notify'),而动态使用X('Feed')或service('Feed')
由于礼物应用没有用到动态,这里也不再赘述。
增加微博分享功能
首先我们需要在“管理后台-内容- 模板管理”增加一个礼物赠送的模板:
19 / 32
在组装通知数据前,初始化一个获赠对象变量:
// 赠送的对象名称 用于公开赠送微博
$toUserName = NULL;
在组装公开赠送的通知信息中添加如下代码,用以@ 到各个获赠用户:
// 赠送对象名称
$toUserName .= '@'.getUserName($fid).' ';
在通知信息组装结束后,添加如下代码,将微博信息暂存于SESSION中:
// 公开则发微薄
if($toUserName){
$_SESSION['gift_send_weibo'] = urlencode ( serialize ( array(
'user' => $toUserName,
'title' => $giftInfo['name'],
'content' => $data['content'],
'url' => U('gift/Index/index', array(
'uid' =>$fid,
'type' =>1,
'type_data'=>realityImageURL($giftInfo['img']))),
)));
}
在Lib/Index/ IndexAction.class.php文件里的sendbox()函数内添加如下代码:
//判断是否有公开赠送信息,存在,则赋值给模板,用于发微薄if(isset($_SESSION['gift_send_weibo'])&&!empty($_SESSION['gift_send_weibo'])){
$this->assign('tpl_data',$_SESSION['gift_send_weibo']);
unset($_SESSION['gift_send_weibo']);
}
在Tpl/default/Index/目录下送出的礼物sendbox.html模板文件里,添加WeiboWidget引用(只有发送微博的信息存在时才加载),如下:
{:W('Weibo',array(
'tpl_name'=>'gift_send_weibo',
'button_title'=>'分享',
))}
到这里公开赠送发微博功能完成了。
增加应用后台
ThinkSNS2.0 为应用增加管理后台的方法很简单,直接在应用的Action/目录下增加AdminAction.class.php文件,然后导入并继承AdministratorAction类即可完成权限管理:
20 / 32
//引入后台管理类
import('admin.Action.AdministratorAction');
class AdminAction extends AdministratorAction {
function _initialize(){
// 管理权限判定
parent::_initialize();
[……]
}
[……]
}
?>
注意:在_initialize函数里,首先要执行parent::_initialize(),进行管理权限判定。
更多详细代码请见具体文件。
接着我们增加对应的管理页面的模板,Tpl/default/目录下增加Admin/目录,然后在该目录下增加_header.html, _footer.html, _tab.html, index.html, giftlist.html, category.html, edit_gift_tab.html, edit_category_tab.html几个模板文件。模板开发方式同前台的模板一样,在此不再重复。
制作安装/卸载包
在应用的目录下增加安装信息目录,命名为Appinfo,然后在该目录下增加应用图标(ico_app.gif、ico_app_large.gif)、应用配置文件(info.php)、应用安装文件(install.php)、应用数据库文件(install.sql)和应用卸载文件(uninstall.php)。
配置文件内容:
if (!defined('SITE_PATH')) exit();
return array(
// 应用名称[必填]
'NAME' => '礼物',
// 应用简介[必填]
'DESCRIPTION' => '礼物赠送',
// 托管类型[必填](0:本地应用,1:远程应用)
'HOST_TYPE' => '0',
// 前台入口[必填](格式:Action/act)
'APP_ENTRY' => 'Index/index',
// 应用图标[必填]
'ICON_URL' => SITE_URL . '/apps/gift/Appinfo/ico_app.gif',
// 应用图标[必填]
'LARGE_ICON_URL' => SITE_URL . '/apps/gift/Appinfo/ico_app_large.gif',
// 后台入口[选填]
'ADMIN_ENTRY' => 'Admin/index',
// 统计入口[选填](格式:Model/method)
21 / 32
'STATISTICS_ENTRY' => 'GiftStatistics/statistics',
[……]
);
?>
注意:其中的SITE _URL是站点根目录网址,如果直接使用它本身的话程序会自动解释成绝对网址,还有一个好处就是网站转移的时候这些信息都不需要修改,程序会自动解释出新的网址赋值给它。当然,你也可以使用绝对网址。
安装文件内容:
数据库操作的语句均统一放在数据库文件install.sql中,install.php的功能就是执行该文件:
if (!defined('SITE_PATH')) exit();
header('Content-Type: text/html; charset=utf-8');
$sql_file = APPS_PATH.'/gift/Appinfo/install.sql';
//执行sql文件
$res = M('')->executeSqlFile($sql_file);
if(!empty($res)){//错误
echo $res['error_code'];
echo '
';
echo $res['error_sql'];
//清除已导入的数据
include_once(APPS_PATH.'/gift/Appinfo/uninstall.php');
exit;
}
?>
数据库文件内容:
首先,写入该应用三张数据表的添加语句;然后,再加入应用系统配置信息和微博模板的插入语句,若有设定积分规则的应用,也加上积分规则的插入语句,可以参见日志、相册等应用的数据库文件,代码如下:
SET FOREIGN_KEY_CHECKS=0;
[……三张数据表及其预设信息的sql语句]
#添加ts_system_data数据
REPLACE INTO `ts_system_data` (`uid`,`list`,`key`,`value`,`mtime`)
VALUES
(0, 'gift', 'credit', 's:5:"score";', '2010-12-24 11:22:17');
#模板数据
DELETE FROM `ts_template` WHERE `name` = 'gift_send_weibo';
INSERT INTO `ts_template` (`name`, `alias`, `title`, `body`, `lang`, `type`, `type2`, `is_cache`, `ctime`)
22 / 32
VALUES
('gift_send_weibo', '礼物赠送', '','我送给{user} 一份礼物:【{title}】{content} 参与送礼{url}', 'zh', 'gift', 'weibo', 0, 1290417734);
这里可以直接使用由工具导出的sql文件和语句。
卸载文件内容:
删除应用的数据表、应用系统配置信息和微博模板。若应用还设置了积分规则,则也要同时删除其积分规则,可以参见日志、相册等应用的卸载文件。
if (!defined('SITE_PATH')) exit();
$db_prefix = C('DB_PREFIX');
$sql = array(
// gift数据
"DROP TABLE IF EXISTS `{$db_prefix}gift`;",
"DROP TABLE IF EXISTS `{$db_prefix}gift_category;",
"DROP TABLE IF EXISTS `{$db_prefix}gift_user;",
// ts_system_data数据
"DELETE FROM `{$db_prefix}system_data` WHERE `list` = 'gift'",
// 模板数据
"DELETE FROM `{$db_prefix}template` WHERE `name` = 'gift_send_weibo';",
);
foreach ($sql as $v)
M('')->execute($v);
?>
至此,安装卸载包制作完成。
登录后台后进入“应用->应用管理->添加应用”点击“安装”应用就可以了。然后更新一下系统缓存就可以在前台的应用列表中看到我们的礼物应用了。
调试
要调试我们的有程序,有很多种方法,在此我们推荐几种常用的调试方法。
用ThinkPHP 自带的dump()方法把过程变量打印出来,看是是否与预想的结果一样
使用ThinkPHP 的getLastSql()方法取得最后的SQL语句并用dump()打印出来,检查SQL语句是否正确
在Conf/config.php文件里增加DEBUG_MODE常量并赋值为true,即把ThinkPHP 的调试模式打开(注:修改后需要清理缓存)