轻量级OO框架2.0
哈哈,偶可是完全重新设计的哟 :em02: !
[b:24fc2d3c49]*** 版权申明[/b:24fc2d3c49]
简单点来说,我许可任何人自由使用本文附带的代码,但必须注明作者信息。其次,任何人可以在任何地方引用本文的内容(部分或者全部),但必须注明作者信息。其他没什么了,就算有什么我也管不着,革命靠自觉!
[b:24fc2d3c49]*** 基本信息[/b:24fc2d3c49]
框架名称:PFC – PHP Foundation Class(野心有点大哦,不过要真能做到MFC那种水平可就海了去了!)
版本:2.0
[b:24fc2d3c49]*** 主要特征[/b:24fc2d3c49]
1、多个模块,每个模块多个动作
2、安全机制。可以检查用户是否能够访问模块及动作。
3、封装了应用程序、模块、动作、模版等。
[b:24fc2d3c49]*** 设计思想[/b:24fc2d3c49]
这个框架基于下面的设计思想:
一个应用程序按照功能划分为多个模块。每个模块可以执行一系列相关的动作。例如用户管理模块就可以执行建立用户、删除用户、修改用户信息等动作。整个框架封装了这一系列的东西:应用程序、模块、动作集等。
[img:24fc2d3c49]http://www.dualface.com/~dualface/pfc/pfc_doc_img_01.gif[/img:24fc2d3c49]
其次,整个框架还定义了用户和用户节点这样一种用户体系模型:
当用户输入登录信息后,框架(在Application的继承类中实线)将查询用户的信息(可能是存储在数据库中)以及用户所在节点的信息。
节点信息中至少要保存该节点对应的功能模块。例如用户support所在的节点对应了售后服务模块。那么support登录以后,框架就会自动生成售后服务模块并执行。目前的实现是每个用户对应一个节点,而且节点是平面的。但是也可以扩展成单用户对应多节点以及树形节点结构(我已经在另一个项目中实际应用了)。
[b:24fc2d3c49]*** 运行流程[/b:24fc2d3c49]
搞清楚了设计思想,再看流程就很简单了。
[code:1:24fc2d3c49]
1、浏览器发送请求,通过index.php创建Application对象并执行;
2、如果没有通过URL指定模块名,那么使用在配置文件中定义的默认模块名;
3、创建一个ModuleFactory对象,然后检查模块名($module_name)是否有效;
4、通过ModuleFactory->checkPriv()检查当前登录的用户所在的节点是否可以访问这个模块;
5、检查通过后,生成ActionFactory对象,并检查动作名($action_name)是否有效;
6、通过ActionFactory->checkPriv()检查当前登录的用户是否可以访问指定动作;
7、检查通过后,生成Action对象,并调用其run()方法;
8、Action->run()会返回一个Response对象。最后Application->run()执行Response->run()完成整个运行。
[/code:1:24fc2d3c49]
[b:24fc2d3c49]*** 各对象详细说明[/b:24fc2d3c49]
[b:24fc2d3c49]Application[/b:24fc2d3c49]:这个类封装了一个PHP应用程序。不过由于PHP的执行方式,所以每次浏览器发起请求时,Application对象都会重新创建一个。所以说封装了一个HTTP请求更合适。但是我准备在以后缓存这个Application对象(只建立一个),所以就不改名了。
[b:24fc2d3c49]Request[/b:24fc2d3c49]:这个类封装了$_GET和$_POST,并提供getModuleName()方法和getActionName()方法来来获得模块名称和Action名称。
[b:24fc2d3c49]ModuleFactory[/b:24fc2d3c49]:用于创建不同Module的工厂类。主要作用就是检查当前登录的用户是否允许访问指定的Module,并创建相应的Module对象。
[b:24fc2d3c49]Module[/b:24fc2d3c49]:封装一个功能模块。
[b:24fc2d3c49]ActionFactory[/b:24fc2d3c49]:用于创建不同Action的工厂类。主要作用是检查当前登录的用户是否允许访问指定的Action,并创建相应的Action对象。
[b:24fc2d3c49]Action[/b:24fc2d3c49]:封装一系列的action。注意不是单个action,而是一系列的action。
[b:24fc2d3c49]Response[/b:24fc2d3c49]:这个类及两个继承类封装了两种不同形式的动作执行结果。一种是[b:24fc2d3c49]RenderResponse[/b:24fc2d3c49],也就是显示特定的内容(例如显示一个模板),而另一种是[b:24fc2d3c49]RedirectResponse[/b:24fc2d3c49],就是重定向浏览器(提供了跨页面共享数据能力)。
Application->run()说明
Application对象($app)创建后,执行run方法。run()主要做下面几件事情:
[code:1:24fc2d3c49]
1、生成一个Request对象。这个对象封装了$_GET和$_POST,并提供了getActionName()方法和getModuleName()方法;
2、$app调用Request->getModuleName()获得$_GET[‘module’]。如果没有提供,则使用config.inc.php中定义的默认名称;
3、生成ModuleFactory对象(这个对象以后也会缓存起来,只要一个实例就行了);
4、调用ModuleFactory->checkModuleName($module_name)检查是否有效(即是否定义了这个Module)。要注意的是checkModuleName()会装入该Module的配置文件;
5、调用ModuleFactory->checkPriv($node, $user, $module_name)检查当前登录的用户是否允许使用这个模块(checkPriv()方法后面会详细解释);
6、调用ModuleFactory->buildModule($module_name)创建Module对象;
7、调用Module->run()执行,并获得从Module返回的Response对象;
8、执行Response对象。
[/code:1:24fc2d3c49]
Module->run()说明
进入Module对象后,Module->run()将创建action对象并执行:
[code:1:24fc2d3c49]
1、调用Request->getActionName()获得$_GET['action'];
2、生成ActionFactory对象
3、调用ActionFactory->checkPriv($user, $action_name)检查$action_name是否有效以及$user是否允许访问这个action;
4、调用ActionFactory->buildAction($action_name)生成action对象;
5、调用Action->run(),并返回。
[/code:1:24fc2d3c49]
Action->run()说明
在Action->run()中,将根据$action_name来确定要调用的方法名。然后调用这个方法。而具体的方法就在Action的继承类中实现。
ModuleFactory->checkPriv()说明
[code:1:24fc2d3c49]
1、载入指定模块的配置文件(模块配置文件的说明请看本文后面部分);
2、如果配置文件中auth一项设置不为yes,则直接返回true。也就意味着允许访问这个模块。所以如果要让某个模块在用户未登录的情况下就可以被访问,只要把模块配置文件的auth项设置为no即可。例如处理用户登录的模块就必须设置成no;
3、下一步检查当前是否已经有登录用户的节点信息是否可用,如果不可用则返回false;
4、下一步检查当前登录用户是否可以访问这个模块,并返回结果。此处会调用Node->getModulePriv(),并返回一个Privilege对象(其实就是一个array,所以判断节点用户是否可以访问这个模块只要检查这个array中是否有该模块的名称或者id即可)。至于Node->getModulePriv()要在Node的继承类中实现。
[/code:1:24fc2d3c49]
ActionFactory->checkPriv()说明
[code:1:24fc2d3c49]
1、载入这个Action的配置;
2、检查配置的auth项是否设置为yes。如果不为yes直接返回ture;
3、检查是否有登录了的用户,如果没有则返回false;
4、检查Action的配置,确定是否需要检查用户是否有权限访问这个action。如果配置设置不为yes,那么直接返回true;
5、调用User->getActionPriv(),并进行检查(User->getActionPriv()需要在User继承类中实现)。
[/code:1:24fc2d3c49]
RenderResponse说明
这个类其实没什么好说的,调用其run()方法式就是echo指定的内容。当然指定的内容就可以用模板引擎产生了。框架里面有一个Brian E. Lozier (brian@massassi.net)开发的模板引擎(我改了一些小地方以适应框架),非常不错。当然你要用Smarty这些也是完全没问题的。
RedirectResponse说明
这个类最大的特点是可以通过appendQueryString()追加URL参数,以及通过appendPostData()追加POST数据。在转向之前,RedirectResponse的代码会检查是否有需要追加的数据,如果有则自动转换为URL参数。如果是POST数据,则存到$_SESSION['RESPONSE_POSTDATA']里面。然后在Request对象的构造函数中检查$_SESSION['RESPONSE_POSTDATA']是否有数据,有则合并到$_POST中。
[b:24fc2d3c49]*** 如何用PFC构建自己的应用程序[/b:24fc2d3c49]
主要有下面几个步骤:
一、重载Application、User、Node三个类,实现下列几个方法:
[code:1:24fc2d3c49]
Application->login();
Application->logout();
User->_loadModulePriv();
Node->_loadModulePriv();
[/code:1:24fc2d3c49]
注意在User和Node构造函数中要调用parent::AttributeSet()初始化属性列表。
二、创建一个modules目录,并在其中创建一个modules_list.php文件,这个文件定义下面这样一个数组:
[code:1:24fc2d3c49]
$modules_list = array(
'welcome' => '/welcome',
'admin' => '/admin',
'pc_project' => '/pc_project'
);
[/code:1:24fc2d3c49]
这个array中的每一个key就是一个模块的名称(框架代码中的$module_name),而value就是该模块在modules目录下的路径(module_path)。
三、在modules目录下创建需要的模块目录,例如welcome。并在此目录下再创建下列目录:
configs用来保存模块配置文件和动作映射文件;
includes用来保存模块实现文件和动作实现文件(具体的执行代码);
templates网页模板。
四、在module_path/configs目录下创建module_config.php文件,并定义如下的数组:
[code:1:24fc2d3c49]
$module_config = array();
$module_config['id'] = 0x1000;
$module_config['name'] = 'welcome';
$module_config['description'] = '欢迎页面';
$module_config['auth'] = 'no';
[/code:1:24fc2d3c49]
id项是模块的id,每个模块的id必须不同,而且定下来以后最好不要随便修改;
name是模块的名称,必须和modules目录中$modules_list定义的模块名称相同;
description是模块的描述信息;
auth是设置该模块是否需要用户登录才能够使用。
五、在module_path/configs目录下创建module_config.php文件,并定义如下的数组:
[code:1:24fc2d3c49]
$default_action = 'DisplayLoginForm';
$action_map = array();
$action_map['DisplayLoginForm'] = array('ModWelcome');
$action_map['Login'] = array('ModWelcome');
$action_map['Logout'] = array('ModWelcome', 'yes');
[/code:1:24fc2d3c49]
$default_action定义了该模块的默认动作;
$action_map[]中的每一项就是动作对应的Action对象名。例如$action_map['Login'] = array('ModWelcome')就指定Login这个动作对应于ModWelcome这个Action的继承对象。
注意$action_map[]中每一项对应的是一个array,其中有三项。第一项是Action对象名,第二项是设置这个动作是否需要用户登录后才可以执行,第三项则是设置是否要检查用户能否访问这个动作。
六、在module_path/includes目录下创建需要的Action对象实现文件。其命名规则是action_ 加上对象名称。例如对象名称设置为ModWelcome,那么文件名就应该是action_modwelcome.php(注意必须全部是小写字母)。
实现文件的大致结构如下:
[code:1:24fc2d3c49]
<?php
require_once (APPROOT . '/pfc/template.php');
class ModWelcome extends Action
{
/**
* @return Response
* @desc 显示登录表单
*/
function _displayLoginForm() {
$tpl = & new Template('login.tpl.php');
$tpl->setVars($this->_request->form);
return new RenderResponse($tpl->fetch());
}
}
?>
[/code:1:24fc2d3c49]
对象必须是Action的继承类,每一个方法就是一个动作的实现。命名规则是下划线加上动作名。例如'DisplayLoginForm'这个动作的方法名就是“_displayLoginForm”。
七、在module_path/templates目录下放入需要显示的模板。
大体上来说,就是这几个步骤了。往应用程序添加新功能时只要修改modules_list.php文件,然后从步骤二做起就行了。
[b:24fc2d3c49]*** 后记[/b:24fc2d3c49]
由于时间有限,所以文档写得不详细(而且肯定存在错误的地方)。很多细节都没有提到,所以大家就多看看代码了。代码里面已经有一个我做好的应用程序(部分功能),是从正在开发的项目中提取出来的。虽然功能比较简单,但是我想用来帮助理解和学习PFC框架是绝对足够了。
[b:24fc2d3c49]*** 下载[/b:24fc2d3c49]
http://www.dualface.com/~dualface/pfc/pfc_demo.zip
[b:24fc2d3c49]*** 在线演示[/b:24fc2d3c49]
http://www.dualface.com/~dualface/pfc_demo/
用户名:root
密码:root
[color=red:24fc2d3c49]用户管理部分没有完成,出错是正常的。其次pc_project只定义了一个配置文件,所以根本不能够运行。
此外请不要更改root用户所在部门(也就是“系统管理”部门)的功能模块,谢谢合作。
[/color:24fc2d3c49]
[b:24fc2d3c49]*** 感谢[/b:24fc2d3c49]
感谢让我获得灵感及技巧的各位无私奉献自己经验的网友
感谢自轻量级OO框架1.0发布以来给我提意见的各位网友
感谢Brian E. Lozier (brian@massassi.net) 共享他出色的模板引擎 :)
感谢我女朋友在我写文档的时候没有骚扰我,而是乖乖的在看韩剧 :P
[b:24fc2d3c49]*** 作者信息[/b:24fc2d3c49]
作者:廖宇雷
MSN:dualface@msn.com (闲聊者恕不奉陪 :em20: )
QQ:102077994(闲聊者拖出去打 :twisted: )
email:daut@dualface.com(发垃圾邮件者TJJTDS :em12: )
[6月16日更新]
文档还有很多不足的地方,特别是ModuleFactory和ActionFactory没有详细说明,而代码里面的注释也不多,所看起来肯定比较累。今天空闲时间没有了,改天一定详细补充内容。
| dualface 回复于:2004-06-14 16:04:55 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PFC在线演示 http://www.dualface.com/~dualface/pfc_demo/ 用户名:root 密码:root | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tonera 回复于:2004-06-14 16:26:12 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 占位先,以后在这里发言。 [color=red:e15a925ba9][2004-06-16][/color:e15a925ba9]第二次发言: 今日发现:在class MyApp中发现你的logout()用的是session_unset(); 如果你的这个框架作为一个应用的一个模块的话,就会作用到其他模块所用到的注册session。 它应该不能干涉到别人(其他应用模块)的session吧。 :) 说的不对请指正。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 夜猫子 回复于:2004-06-14 16:49:24 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [code:1:fb6e4cca26] Error code : 4294967274 Error message : DB Error: value count on row Debug info : INSERT INTO tb_depts (id, title, module_name, module_id, type) VALUES (18, '夜猫子的部门', 'pc_project', 1) [nativecode=1136 ** Column count doesn't match value count at row 1] [/code:1:fb6e4cca26] 呵呵 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| dualface 回复于:2004-06-14 17:14:48 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Sorry,下载地址修复了! 在线演示也修复了。不过用户管理是还没有做完的。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 财狼 回复于:2004-06-14 20:29:57 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 楼主又有好东东了,才急忙粗粗看了一遍,感觉非常地妙——原谅我不知道说啥好了。。。 以前楼主的1.0版我也修改扩展过,好在没敢在这里献丑,唉,差的太远了。。。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| longnetpro 回复于:2004-06-14 21:19:43 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 非常不错,值得借鉴。 不过想知道,模板的实现,用的什么方法?我比较关心这个。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| jhsea3do 回复于:2004-06-14 21:53:10 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 看到最后一句话, 我响楼主一定是老MOPER了 :) brian的模板我去看了一下,慢方便的, <?=变量?>的写法和jsp,asp非常像~ 我自己最近也在写类似的东西, 这篇文章对我非常有帮助哦! | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| longnetpro 回复于:2004-06-14 22:06:10 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <?=变量?> 不推荐这种写法,凡不用<?php ?>这种写法的,均被我认为考虑不周的东西。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| dualface 回复于:2004-06-14 22:15:54 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [quote:79cd505958="财狼"]楼主又有好东东了,才急忙粗粗看了一遍,感觉非常地妙——原谅我不知道说啥好了。。。 以前楼主的1.0版我也修改扩展过,好在没敢在这里献丑,唉,差的太远了。。。[/quote:79cd505958] 不能这样说啊。要不是大家献计献策,我又怎么能够继续改进呢? | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| shukebeita 回复于:2004-06-14 22:21:37 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 楼主很用功呀。我目前用的框架和这个很象,有意思的是连模板类选的都一样。这个模板非常高效用的就是php本身。我的应用程序也需要非常麻烦的权限控制,所以我在数据库里增加里2个表来注册安装了的module和action通过和用户表的配合进行权限控制(这个方法是从XOOPs中学来的)。 我想如果楼主愿意是不是可以把这个去cosoft.org.cn注册一下,用bsd的授权来发布,当作一个开源项目的来做,让更多的人来参与和鼓励大家使用,这样能够得到更多的积极的反馈,省得新人们一次一次的重复劳动。 <?=变量?> 这种写法和这个模板没有任何关系,不是模板作者的主意,只是php提供的一种简便手段。 jhsea3do可能误会了。 这样的帖子值得发个火的。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||


