曹振华

posts - 45, comments - 0, trackbacks - 0, articles - 0
  PHP博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

Fleaphp 常用方法

Posted on 2009-02-20 14:11 曹振华 阅读(2310) 评论(0)  编辑 收藏 引用 网摘

FleaPHP 开源应用程序开发框架

FleaPHP API 手册 » 1.5 其他


FLEA::initWebControls()
函数原型:

/**
 * 初始化 WebControls,返回 FLEA_WebControls 对象实例
 *
 * @return FLEA_WebControls
 */
function & initWebControls()开发者可以调用 FLEA_WebControls 对象实例的 control() 方法来创建各种控件。

使用示例:

$ui =& FLEA::initWebControls();
// 创建一个宽度为 40 字符,name 和 id 属性为 username 的单行文本框
$ui->control('textbox', 'username', array('size' => 40));
--------------------------------------------------------------------------------

 

FLEA::initAjax()
函数原型:

/**
 * 初始化 Ajax,返回 FLEA_Ajax 对象实例
 *
 * @return FLEA_Ajax
 */
function & initAjax()FLEA_Ajax 对象实例提供了多个方法,让开发者可以为页面上的控件、连接添加 ajax 效果。

使用示例:

$ajax =& FLEA::initAjax();
/**
 * 注册页面控件 username 的 change 事件。
 * 当该事件出现时,引发一个 ajax 调用。调用地址由 url() 函数生成。
 */
$ajax->registerEvent('username', 'change', url('MyController', 'checkUsername'));
--------------------------------------------------------------------------------

 

FLEA::getDBO()
函数原型:

/**
 * 返回数据库访问对象实例
 *
 * @param array|string|int $dsn
 *
 * @return FLEA_Db_Driver_Prototype
 */
function & getDBO($dsn = 0)开发者可以直接调用 FLEA::getDBO() 获得一个数据库访问对象。该对象提供了类似 adodb 的方法,为不同的数据库系统提供了一致的访问接口。如果开发者使用表数据入口来访问数据库,那么不需要调用该方法来获取数据库访问对象。

$dsn 参数通常是一个数组,由下列内容组成:

driver 数据库驱动类型,例如 mysql、pgsql 等; host 数据库所在服务器,通常为 localhost 或 127.0.0.1 port 连接数据库的端口,通常无需指定 login 连接时使用的用户名 password 连接时使用的密码 database 连接后要使用的数据库名 charset 字符集设置,如果没有设置该选项,则以应用程序设置 databaseCharset 为准 options 附加的连接选项 $dsn 参数也可以是一个字符串,规则如下:

driver://login:password@host:port/options如果多次以相同的 $dsn 参数调用 FLEA::getDBO(),那么返回的数据库对象都将是同一个。

还可以用 FLEA::getDBO() 获得默认的数据库访问对象实例。默认数据库访问对象的连接参数来自应用程序设置 dbDSN。

使用示例:

$dsn = array(...);
$dbo =& FLEA::getDBO($dsn);

// 获取默认的数据库访问对象
$defaultDbo =& FLEA::getDBO();
--------------------------------------------------------------------------------

 

FLEA::parseDSN()
函数原型:

/**
 * 分析 DSN 字符串,返回包含 DSN 连接信息的数组,失败返回 false
 *
 * @param string $dsnString
 *
 * @return array
 */
function parseDSN($dsnString)该方法用于分析一个 DSN 字符串,并以数组形式返回分析结果。

DSN 字符串示例:

mysql://root:123456@localhost
查看(40) 评论(0) 收藏 推荐
FleaPHP API 手册 » 1.4 基本缓存服务
2007-03-15 11:07:27

基本缓存服务为 FleaPHP 的数据库访问提供支持,用于提高数据库访问组件的性能。

开发者也可以在应用程序中使用基本缓存服务来缓存一些应用程序经常用到的,并较少变动的数据。


--------------------------------------------------------------------------------

FLEA::getCache()
函数原型:

/**
 * 读取指定缓存的内容,如果缓存内容不存在或失效,则返回 false
 *
 * @param string $cacheId 缓存ID,不同的缓存内容应该使用不同的ID
 * @param int $time 缓存过期时间或缓存生存周期
 * @param boolean $timeIsLifetime 指示 $time 参数的作用
 * @param boolean $cacheIdIsFilename 指示是否用 $cacheId 作为缓存文件的文件名
 *
 * @return mixed 返回缓存的内容,缓存不存在或失效则返回 false
 */
function getCache($cacheId, $time = 900, $timeIsLifetime = true, $cacheIdIsFilename = false)缓存文件名是根据 $cacheId 用 md5 算法生成的。如果希望使用 $cacheId 来指定缓存文件名,则 $cacheIdIsFilename 参数应该为 true。

缓存文件全部保存在应用程序设置 internalCacheDir 指定的目录中。因此该目录必须就有可写权限。

当 $timeIsLifetime 参数为 true 时,该函数会检查缓存文件的最后更新日期加上 $time 是否大于当前时间。如果是,则返回 false,表示缓存的内容已经过期。

如果 $timeIsLifetime 参数为 true,且 $time 参数为 –1,则表示缓存数据永不过期。

如果 $timeIsLifetime 参数为 false,则该函数会检查缓存文件的最后更新日期是否大于 $time 参数指定的时间。如果是,则返回 false。

使用示例:

// 用法 1:缓存数据,缓存数据生存期为 900 秒
$cacheId = 'myDataCache';
$data = FLEA::getCache($cacheId, 900);
if (!$data) {
    // 从数据库读取数据
    $data = $dbo->getAll($sql);
    FLEA::writeCache($cacheId, $data);
}

// 用法 2:以原始文件的最后更新日期来判断缓存是否有效
$xmlFilename = 'myData.xml';
$xmlData = FLEA::getCache($xmlFilename, filemtime($xmlFilename), false);
if (!$xmlData) {
    $xmlData = parseXML($xmlFilename);
    FLEA::writeCache($xmlFilename, $xmlData);
}
--------------------------------------------------------------------------------

 

FLEA::writeCache()
函数原型:

/**
 * 将变量内容写入缓存
 *
 * @param string $cacheId
 * @param mixed $data
 * @param boolean $cacheIdIsFilename 指示是否用 $cacheId 作为文件名
 *
 * @return boolean
 */
function writeCache($cacheId, $data, $cacheIdIsFilename = false)该方法各个参数的意义与 FLEA::getCache() 完全一致。


--------------------------------------------------------------------------------

 

FLEA::purgeCache()
函数原型:

/**
 * 删除指定的缓存内容
 *
 * @param string $cacheId
 * @param boolean $cacheIdIsFilename 指示是否用 $cacheId 作为文件名
 *
 * @return boolean
 */
function purgeCache($cacheId, $cacheIdIsFilename = false)该方法各个参数的意义与 FLEA::getCache() 完全一致。

查看(16) 评论(0) 收藏 推荐
FleaPHP API 手册 » 1.3 对象注册和检索
2007-03-15 11:06:33

对象注册和检索服务为开发者提供了一个简单易用的对象管理机制,让开发者可以很方便的获取自己需要的对象。


--------------------------------------------------------------------------------

FLEA::getSingleton()
函数原型:

/**
 * 返回指定对象的唯一实例
 *
 * @param string $className
 *
 * @return object
 */
function & getSingleton($className)FLEA::getSingleton() 返回指定对象的唯一实例。不管在应用程序的不同位置调用多少次,对于同一个名字的对象,永远都只会返回一个实例。

通常,对于提供各种服务的对象来说,并不需要多个实例。因此使用这个方法,不但简单,而且可以避免不必要的对象构造操作。从而降低了应用程序使用的内存,同时提高了运行性能。

当然,由于 PHP 脚本在每一次请求时都会重新执行,所以当次请求中构造的对象在请求结束后就销毁了。下一次请求会重新构造一个新的对象。但 FLEA::getSingleton() 仍然可以避免在同一次请求中多次构造同名的对象。

使用示例:

$obj =& FLEA::getSingleton('MY_OBJ');
$obj2 =& FLEA::getSingleton('MY_OBJ');
// 此时 $obj 和 $obj2 实际上指向同一个对象实例在 PHP4 中,一定要使用 =& 来进行对象赋值。否则仍然会导致 PHP 生成对象的副本。


--------------------------------------------------------------------------------

 

FLEA::register()
函数原型:

/**
 * 将一个对象实例注册到对象实例容器
 *
 * @param object $obj
 * @param string $name
 *
 * @return object
 */
function & register(& $obj, $name = null)开发者可以调用 FLEA::register() 将一个对象以指定的名字注册到对象容器中。以便稍后将该对象取出来使用。

不过如果开发者使用 FLEA::getSingleton() 来获取对象实例,那么此时构造的对象会自动注册。

如果没有提供 FLEA::register() 的第二个参数,则使用对象的类名称来注册对象,否则使用指定的名称来注册对象。利用这个特性,可以将同一个对象注册为不同的名字。

如果指定名字的对象已经存在与容器中,则抛出 FLEA_Exception_ExistsKeyName 异常。

$obj =& new MyObject();
FLEA::register($obj);
// 用另一个名字注册同一个对象
FLEA::register($obj, 'MyObject2');** 请记住,PHP 不存在持久化的对象。每一次请求结束时,脚本创建的所有对象都会被销毁。所以注册到对象容器中的对象也仅在当此请求中有效 .{color: red} **


--------------------------------------------------------------------------------

 

FLEA::registry()
函数原型:

/**
 * 从对象实例容其中取出指定名字的对象实例,如果没有指定名字则返回包含所有对象的数组
 *
 * @param string $name
 *
 * @return object
 */
function & registry($name = null)FLEA::registry() 用于从对象容器总检索指定名字的对象。如果指定名字的对象不在容器中,则抛出 FLEA_Exception_NotExistsKeyName 异常。

使用示例:

$obj =& new MyObject();
FLEA::register($obj, 'MyObject');
......
// 取出先前注册的对象
$obj2 =& FLEA::registry('MyObject');
--------------------------------------------------------------------------------

 

FLEA::isRegistered()
函数原型:

/**
 * 检查指定名字的对象是否已经注册
 *
 * @param string $name
 *
 * @return boolean
 */
function isRegistered($name)FLEA::isRegistered() 检查指定名称的对象是否存在于对象容器中。

使用示例:

if (FLEA::isRegistered('MyObject')) {
    echo 'MyObject 对象已经注册';
}

查看(11) 评论(0) 收藏 推荐
FleaPHP API 手册 » 1.2 应用程序设置
2007-03-15 11:04:33

应用程序设置部分提供的方法让开发者可以在应用程序中修改和读取设置值。


--------------------------------------------------------------------------------

FLEA::loadAppInf()
函数原型:

/**
 * 载入应用程序设置
 *
 * @param mixed $__config 配置数组或配置文件名
 */
function loadAppInf($__flea_internal_config = null)FLEA::loadAppInf() 从文件或数组中读取设置,并添加到应用程序设置中。如果有同名的设置,则会覆盖原有的值。

使用示例:

// 从文件载入设置
FLEA::loadAppInf('Config/MyAppConfig.php');包含设置的文件必须用 return 语句返回一个数组,例如:

<?php
// Config/MyAppConfig.php 文件的内容

return array(
    'MyOption' => 'value',
    'MyOptions' => array('option_1' => 'value_1', 'option_2' => 'value_2'),
);或者从数组中读取设置:

$inf = array(
    'NewOption' => 'value',
);

FLEA::loadAppInf($inf);
--------------------------------------------------------------------------------

 

FLEA::getAppInf()
函数原型:

/**
 * 取出指定名字的设置值
 *
 * @param string $option
 *
 * @return mixed
 */
function getAppInf($option)开发者可以用 FLEA::getAppInf() 随时从应用程序设置设置中读取需要的值。

使用示例:

// 读取一个字符串
echo FLEA::getAppInf('MyOption');

// 读取一个数组
print_r(FLEA::getAppInf('MyOptions');
--------------------------------------------------------------------------------

 

FLEA::setAppInf()
函数原型:

/**
 * 修改设置值
 *
 * @param string $option
 * @param mixed $data
 */
function setAppInf($option, $data = null)修改一个或多个应用程序设置的值。

使用示例:

// 修改单个设置
FLEA::setAppInf('MyOption', 'new_value');

// 修改多个设置
$newSettings = array(
    'myAppOpt1' => 'new_value',
    'myAppOpt2' => 'new_value',
);
FLEA::setAppInf($newSettings);
查看(8) 评论(0) 收藏 推荐
FleaPHP API 手册 » 1.1 基本服务
2007-03-15 11:03:16

基本服务中最重要的方法是 FLEA::init()。该方法用于初始化 FleaPHP 框架的运行环境。紧接着,开发者需要调用 FLEA::runMVC() 方法来运行应用程序的控制器代码。


--------------------------------------------------------------------------------

FLEA::init()
函数原型:

/**
 * 准备运行环境
 */
function init()开发者通过 require('FLEA.php') 载入 FleaPHP 框架的核心文件后,需要用 FLEA::loadAppInf() 或者 FLEA::setAppInf() 方法来载入应用程序设置。接下来,必须调用 FLEA::init() 方法来完成 FleaPHP 框架的初始化工作。

FLEA::init() 主要完成下列工作:

安装 FleaPHP 异常的处理例程 根据应用程序设置设置决定是否载入日志服务 检查 php.ini 中 magic_quotes 设置是否为 on,并将被 PHP 自动转义后的数据撤销转义 根据应用程序设置的 urlMode 决定是否对 URL 进行处理 根据应用程序设置 requestFilters 决定运行哪些输入过滤器 根据应用程序设置 autoLoad 决定自动载入哪些文件 根据应用程序设置 sessionProvider 和 autoSessionStart 决定使用哪一个 session 服务 根据应用程序设置 responseCharset 和 requestCharset 定义常量 RESPONSE_CHARSET 和 DATABASE_CHARSET 根据应用程序设置 multiLangaugeSupport 决定是否载入多语言支持 根据应用程序设置 autoResponseHeader 决定是否自动输出 HTTP HEADER 信息 这些初始化工作对于应用程序的绝大部分来说都是必须。因此务必记得在 require('FLEA.php') 后要调用 FLEA::init()。

使用示例:

<?php

require('FLEA.php');
FLEA::loadAppInf('APP_INF.php');
FLEA::init();
FLEA::runMVC();
--------------------------------------------------------------------------------

 

FLEA::runMVC()
函数原型:

/**
 * FleaPHP 应用程序 MVC 模式入口
 */
function runMVC()如果要使用 FleaPHP 的 MVC 模式。那么在载入 FLEA.php 后,调用 FLEA::runMVC() 即可启动 MVC 模式。

在 MVC 模式启动后,FleaPHP 会根据 URL 地址中包含的控制器名称和控制器动作名称,执行开发者编写的控制器代码。


--------------------------------------------------------------------------------

 

FLEA::import()
函数原型:

/**
 * 导入文件搜索路径
 *
 * @param string $dir
 */
function import($dir)如果开发者按照 FleaPHP 开发指南中建议的命名规范和目录结构来规划自己的应用程序。那么开发者可以很方便的使用 FLEA::loadClass()、FLEA::loadFile() 方法来载入需要的类定义文件和其他文件。同时 FleaPHP 框架本身也能更容易的找到应用程序文件。

为了实现根据类名称查找对应的文件,FleaPHP 内部有一个 CLASS_PATH 变量。FleaPHP 会根据 CLASS_PATH 变量的值来查找文件。

通过 FLEA::import() 方法,可以将一个目录添加到 CLASS_PATH 变量中。从而让 FleaPHP 能够在新的目录中查找需要的文件。

使用示例:

FLEA::import('/var/www/mysite/APP');
--------------------------------------------------------------------------------

 

FLEA::loadClass()
函数原型:

/**
 * 载入指定类的定义文件
 *
 * @param string $filename
 * @param boolean $noException 如果为 true,则类定义文件没找到时不抛出异常
 *
 * @return boolean
 */
function loadClass($className, $noException = false)FLEA::loadClass() 用于载入指定类的定义文件。如果类已经定义,则该方法会直接返回 true。如果找不到指定类的定义文件,则抛出 FLEA_Exception_ExpectedClass 异常。

使用示例:

// 实际载入 Helper/Query.php 文件,并检查该文件中是否定义了 Helper_Query 类
FLEA::loadClass('Helper_Query');如果开发者使用 PHP5,那么可以在 __autoload() 魔法函数中使用 FLEA::loadClass() 来自动载入类定义文件。但用法略有不同:

function __autoload($class)
{
    FLEA::loadClass($class, true);
    ......
}FLEA::loadClass() 的第二个参数为 true 时,即便需要的类定义文件没有找到,FLEA::loadClass() 也仅仅是返回 false,而不会抛出一个异常。


--------------------------------------------------------------------------------

 

FLEA::loadFile()
函数原型:

/**
 * 载入指定的文件
 *
 * @param string $className
 * @param boolean $loadOnce 指定为 true 时,FLEA::loadFile() 等同于 require_once
 *
 * @return boolean
 */
function loadFile($filename, $loadOnce = false)与 FLEA::loadClass() 类似,FLEA::loadFile() 用于载入指定的文件。而载入的文件仍然遵循FleaPHP 开发指南中建议的命名规范和目录结构。

使用示例:

// 实际载入 Data/Tables.php 文件
FLEA::loadFile('Data_Tables.php');
--------------------------------------------------------------------------------

 

FLEA::getFilePath()
函数原型:

/**
 * 按照 FleaPHP 中命名规则,搜索文件
 *
 * @param string $filename
 * @param boolean $return 指示是否直接返回处理后的文件名,而不判断文件是否存在
 *
 * @return string
 */
function getFilePath($filename, $return = false)FLEA::getFilePath() 根据 FleaPHP 命名规范将指定的名字转换为实际的文件名。该方法主要用于 FLEA::loadClass() 和 FLEA::loadFile()。

查看(33) 评论(0) 收藏 推荐
FleaPHP API 手册
2007-03-15 11:01:20

介绍
FleaPHP 的核心是一个名为 FLEA 的类以及一些全局函数。

FLEA 类和这些全局函数为 FleaPHP 框架提供了所需的基本服务,包括:应用程序设置服务、对象注册和检索、缓存服务等。

大部分 FleaPHP 的组件都依赖于 FLEA 类和这些全局函数提供的服务。


--------------------------------------------------------------------------------

基本服务
FLEA::init() FLEA::runMVC() FLEA::import() FLEA::loadFile() FLEA::loadClass() FLEA::getFilePath() 应用程序设置
FLEA::loadAppInf() FLEA::getAppInf() FLEA::setAppInf() 对象注册和检索
FLEA::getSingleton() FLEA::register() FLEA::registry() FLEA::isRegistered() 基本缓存服务
FLEA::getCache() FLEA::writeCache() FLEA::purgeCache() 其他
FLEA::initWebControls() FLEA::initAjax() FLEA::getDBO() FLEA::parseDSN() 1.1 基本服务 1.2 应用程序设置 1.3 对象注册和检索 1.4 基本缓存服务 1.5 其他
查看(24) 评论(0) 收藏 推荐
FleaPHP 自动化 CRUD 操作(1)
2007-03-10 00:02:56

演示了如何使用 FleaPHP 的自动化 CRUD 操作读取数据。这是 CRUD 视频系列的第一部。

PHPChina 地址:
http://downloads.phpchina.com/sources/fleaphp/crud/crud-1.html

备用电信地址:
http://www.fleaphp.org/videos/curd-1/index.html

备用网通地址:
http://www.fleaphp.net/videos/curd-1/index.html

 

查看(101) 评论(0) 收藏 推荐
jQuery + SWF Uploader 结合做的图片管理
2007-03-08 17:02:36

最近在项目中应用了 jQuery 和 SWF Uploader,感觉非常之爽!

下面这个视频是一个图片管理器的使用,看看效果如何吧!

电信地址:
http://www.fleaphp.org/videos/ajax_album/index.html

网通地址:
http://www.fleaphp.net/videos/ajax_album/index.html

客户端使用 jQuery 和一个自写的 js 插件实现上传界面、上传进度条、图片预览,上传使用 SWF Uploader。服务端使用 FleaPHP 处理文件上传操作和返回 JSON。

查看(196) 评论(2) 收藏 推荐
关于 FleaPHP
2007-03-02 14:43:34

FleaPHP 并不是心血来潮的结果,而是作者在 Web 开发中不断探索的成果。虽然 FleaPHP 缺乏 Zend Framework 那样巨大的号召力,也没有 CakePHP 和 Symfony 那样庞大的社区。但 FleaPHP 仍然是一个值得你花时间去了解、去学习的框架。


--------------------------------------------------------------------------------

 

FleaPHP 的设计目标
FleaPHP 致力于减少开发者创建 Web 应用程序的工作量,并降低开发难度和强度,提高开发效率。

快速、轻量级,避免臃肿的结构带来的性能损失
由于 PHP 是解释执行,如果花费太多资源在框架本身,显然不适合的。就像一台计算机如果把大量的资源都花在操作系统上了,而应用程序能够得到的资源却少得可怜,显然是无法让用户接受的。
可扩展、开放性的架构,允许开发者引入自己的组件或者任何成熟的工具库
框架虽然提供了许多组件,但不可能完全满足用户的需求。因此,框架本身应该是松散耦合、可扩展的。开发者可以很简单的为框架加入新的组件。同时,框架的逐步发展也不应该影响框架的核心基础。最后,开放性的架构让开发者在框架中引入其他组件或者工具库时不会遇到任何困难。例如开发者可能会使用 Smarty 来做模板引擎,以及 PEAR 中的一些库来简化开发工作。
尽可能少的契约,但同时提供足够的自动化能力,减轻开发强度
虽然契约式编程,可以让框架本身的设计变得更简单,开发者也能从框架获得更多的帮助。但太过严格的规则和约定会明显降低框架的适应性,为此需要对两者进行适当的平衡。FleaPHP设计时采用尽可能少的契约,通过更复杂的实现来实现一些自动化能力。或者以最少量的配置信息来帮助框架为开发者提供服务。
高度灵活的解决方案,提供开发应用程序的大多数基本组件
虽然现在已经有许许多多出色的工具库可供选择。但对于一些平常的需求来说,这些工具库可能具有过度杀伤能力(也就是说工具库本身提供了远远超过需求的功能)。由此带来了学习难度增大、性能降低等问题。为此,FleaPHP 框架提供了一组轻量级的基本组件。这些组件被设计为拥有基本的功能和可扩展。 例如 FleaPHP 附带的基于角色的权限验证组件虽然不如 phpGACL 这样的库功能强大,但却能够解决平常开发都会遇到的典型权限验证问题,并允许开发者自行扩展这个组件。

--------------------------------------------------------------------------------

 

FleaPHP 的主要特征
除了 MVC 模式实现、Dispatcher 调度器、模板引擎等常见功能外,FleaPHP 框架还拥有许多独一无二的特点:

简单、容易理解的 MVC 模型
不像其他流行的框架,FleaPHP 提供的 MVC 模型注重简单和容易理解。例如 FleaPHP 不要求开发者从特定的类派生自己的控制器类和业务模型类。
易于使用、高度自动化的数据库 CRUD 操作
FleaPHP 采用 TableDataGateway 设计模式来封装数据表操作。FLEA_Db_TableDataGateway 类不但提供了容易使用的 CRUD 操作,还实现了数据表之间的关联操作。同时,FleaPHP 没有像其他框架那样将每一行记录都封装为一个对象(毫无疑问这会产生明显的性能问题),而是利用 PHP 强大的数组来保存和传递数据。
尽可能少的配置
虽然像数据库联接信息等配置仍然是不可少的,但 FleaPHP 应用程序通常只需要设置几个选项,即可在各种环境中运行良好。而且 FleaPHP 的所有设置都采用 PHP 数组来保存,不但容易理解,而且省掉了解析、缓存等不必要的过程,提高了性能。
高度可配置能力
虽然 FleaPHP 自动化程度很高,但 FleaPHP 同时也拥有高度的可配置能力。通过覆盖 FleaPHP 默认的选项,开发者可以获得最大程度的灵活性。让开发者可以在适应现有代码、保持开发习惯等各方面获得好处。
自动化的数据验证和转义
即便不做任何处理,程序将数据通过 FLEA_Db_TableDataGateway 提交到数据库前。FleaPHP 也会自动对数据进行验证,并转义特殊字符,最大程度消除 SQL 注入攻击。
丰富的助手对象和组件
FleaPHP 附带了一些非常实用的助手对象,从生成图像验证码、处理文件上传到通用数据验证等。这些助手对象大多是一些独立的对象,完全不依赖于 FleaPHP 框架本身。因此开发者不但可以在 FleaPHP 之外使用这些助手对象,也可以方便的加入自己的助手对象。 组件是比助手对象更为复杂的可重用单元。这些组件包括基于角色的用户管理、脚手架等。利用这些组件,开发者可以很快的完成一些常见任务,并能在这些组件基础上扩展出功能更复杂的组件。
与 Smarty 集成
只需要修改几个选项,FleaPHP 应用程序就可以和流行的 Smarty 模版引擎集成。
100% FREE
当然,最后一点就是 FleaPHP 是一个完全开放源代码和文档(不是那种滑稽的删除了所有注释仅能运行的代码)、不限制使用的项目。你可以自由的学习、使用 FleaPHP,也可以在自己的应用程序中使用 FleaPHP。不管你的应用程序是否是商业应用,都不需要公开你的源代码,从最大程度上保护了你的知识产权。不过如果你愿意将代码反馈到社区,那么大家都会感谢你。
请记住,FleaPHP 是一个持续发展的框架,随时有新特性被加入到框架中。你现在需要,但 FleaPHP 尚未提供的功能,也许不久以后就出现在 FleaPHP 中了。当然,这需要你积极参与 FleaPHP 的发展,提出你的建议和意见。


--------------------------------------------------------------------------------

 

自由的 FleaPHP
FleaPHP 是一个遵循 BSD 协议发布的开放源代码应用程序开发框架。你可以免费获取 FleaPHP 框架,并应用到自己的开发工作中。与流行的 GPL 协议不同,FleaPHP 遵循的 BSD 协议不要求开发者将基于 FleaPHP 框架开发的应用程序公布于众。这很好的保护了开发者及其所属企业的利益。更进一步,即便你基于 FleaPHP 实现了自己的产品或者对 FleaPHP 进行了修改以满足自己的需求。你仍然不需要公布你的劳动成果。

下面是关于 BSD 协议的简单介绍:

BSD 开源协议是一个给于使用者很大自由的协议。可以自由的使用,修改源代码,也可以将修改后的代码作为开源或者专有软件再发布。当你发布使用了 BSD 协议的代码,或者以 BSD 协议代码为基础做二次开发自己的产品时,需要满足三个条件:

如果再发布的产品中包含源代码,则在源代码中必须带有原来代码中的 BSD 协议。 如果再发布的只是二进制类库/软件,则需要在类库/软件的文档和版权声明中包含原来代码中的 BSD 协议。 不可以用开源代码的作者/机构名字和原来产品的名字做市场推广。 BSD 协议鼓励代码共享,但需要尊重代码作者的著作权。BSD 由于允许使用者修改和重新发布代码,也允许使用或在 BSD 代码上开发商业软件发布和销售,因此是对商业集成很友好的协议。很多的公司企业在选用开源产品的时候都首选 BSD 协议,因为可以完全控制这些第三方的代码,在必要的时候可以修改或者二次开发。


--------------------------------------------------------------------------------

 

FleaPHP的起源
两年多以前,我开始涉及使用 PHP 开发 Web 应用的工作。在反复编写一些过程式代码后,我彻底厌倦了这种开发方式,开始怀念 C++ 中的面向对象设计。这时,正好在 ChinaUnix 上看到了shukebeita兄的精华贴。在这篇帖子里,shukebeita 提出了一种面向对象的 PHP 应用开发方式。虽然只有一个雏形,但这已经让我受益匪浅。

 随后,我根据 shukebeita 的思路实现了 PFC 的第一个版本(当时命名为轻量级 OO 框架)。其实说起来,根本不能称之为框架,仅仅只有两个类。但已经实现了一个简单但实用的核心结构。现在回过头来看,PFC1 实际上实现了一个 Dispatcher 模式,根据 HTTP 请求中的 action 参数调用不同的代码。

在接下来的两年时间,PFC 不断翻新,最终发展到了 PFC3。该版本的 PFC 已经完整的实现了 Dispatcher、MVC 模式,并且引入了 ViewDriver 抽象层、基于角色的权限验证、采用 Provider 模式实现的用户和角色信息管理、一个简单的但带有缓存功能模板引擎等内容。期间曾经试图将 PFC 发扬光大(笑),可惜由于工作变动和个人原因,项目进度非常缓慢,最后终于放弃了。但导致 PFC 放弃的主要原因并不是因为进度缓慢,而是因为我看到了 Web 应用开发的杀手 —— Ruby on Rails。

Ruby on Rails
 Ruby on Rails(后文简称 RoR)是一个采用 Ruby 语言实现的快速、轻便的 Web 应用开发框架,通过契约式编程大大简化了 Web 应用的开发工作。

所谓契约式编程,基本思想就是开发者必须严格遵守框架确定的一些规则和模式(例如对象命名、数据库主键字段命名等)。由于这些规则和模式的存在,框架可以自动完成许多以前需要开发者自己处理的工作。例如根据特定的名字,获取业务对象或者数据表操作对象。更主要的原因是 RoR 实现了 ActiveRecord 模式,并且在这个基础模式之上,扩展了许多便于开发者操作数据库的方法。

虽然 ActiveRecord 只能处理 Create(建立)、Read(读取)、Update(更新)、Delete(删除)等数据表操作,以及一对一、一对多和多对多等几种有限的数据表间关联关系。但我们平时开发的大量应用程序,CRUD 又何尝不是其中的主要内容呢。因此,RoR 为开发者解决了大部分日常任务,让开发者可以集中精力到更关键的地方,例如业务流程的实现。

在我看到 RoR 后,明白 PFC 虽然已经解决了 MVC 模式、权限验证等任务,但最主要的数据库访问却没有提供任何能够简化开发的解决方案。经过反复考虑,我终止了 PFC 系列,开始了一个“全新”的框架设计。

Flea1 与 FleaPHP
最初,这个新框架沿用了PFC系列的命名方式,命名为 flea1(也就是 FLEA 第一版)。在这个版本中,我试验了一些想法,并取得了不错的效果。

不过,我没有采用严格的 ActiveRecord 模式,而是采用了类似CakePHP,一个类似 RoR 的 PHP 框架的 Model 设计。这种设计既实现了 CRUD 操作,又实现了数据表间的关联操作。将这个最初版本的 flea1 框架应用到实际工作中后,马上取得了立竿见影的效果。数据库访问工作被大大简化,甚至连数据库访问代码都不用写了。而且对于数据表之间的关联,也能完成自动化的处理。

接下来,我拿到了《企业应用架构模式》这本经典的设计模式书籍。经过仔细研究,并实际测试。我发现在 PHP 里面使用 ActiveRecord 模式并不是一个很好的选择。因为 ActiveRecord 实际上是针对数据表里面的每一个数据行构造一个对象。这样一来,对于 PHP 这种面向对象能力不强(尤其是 PHP4)的脚本语言来说,带来了许多棘手的问题。


最终,flea1 的设计方案进行了一些调整,确定为现在的架构,并且框架命名为 FleaPHP。


--------------------------------------------------------------------------------

 

未来的发展
FleaPHP 在外来将继续保持简单易用、高度模块化的特点,但同时通过可插入的模块形式提供更多的功能。

FleaPHP 项目的短期目标:

完善文档
一个成功的项目,离不开完善的文档和技术支持。目前,FleaPHP 的核心和主要功能已经日趋稳定,但文档还很匮乏。所以,近期 FleaPHP 项目组的主要工作就是完善文档,确保开发者能够尽快掌握 FleaPHP 的使用。文档目前正在撰写的包括开发指南和一些系列文章。
支持更多的数据库系统
目前,FleaPHP 仅能支持 MySQL 数据库。但由于 FleaPHP 的数据库抽象层非常简单,所以短期内即可增加对多种数据库的支持。
FleaPHP 项目的长期目标:

以插件形式提供更多的功能
由于 FleaPHP 开放式的结构,开发者可以很方便的为 FleaPHP 提供更多的插件。这些将要增加的插件包括完整的 Ajax 支持。
吸收开发者参与,将 FleaPHP 建设为一个成功的社区开源项目 如果你有热情,并且有能力为 FleaPHP 做贡献,我们随时都欢迎你加入 FleaPHP 开发者团队!

查看(32) 评论(0) 收藏 推荐
FleaPHP 应用程序开发框架 - 经常问到的问题 (FAQ)
2007-03-02 14:42:00

在这里列出了一些经常会问到的问题,也许你的困惑在这里就可以找到答案。

FleaPHP 是免费的吗?
简单的回答“是”,你不用支付任何费用,即可在你或你所在企业开发的应用程序中使用 FleaPHP。同时,你不用将你的应用程序代码公布。关于 FleaPHP 授权协议的详细信息,请阅读“关于 FleaPHP”。

FleaPHP 官方网站有哪些?
fleaphp.org 是 FleaPHP 项目官方网站之一,提供所有最新的文档和 FleaPHP 源代码,以及开发者论坛服务。fleaphp.net 是 FleaPHP 项目官方网站的子站,即将推出应用程序模版发布服务。

QeeYuan.com(自贡市起源科技有限公司)是 FleaPHP 项目发起人创办的企业,也是目前唯一为 FleaPHP 提供商业支持的企业。

fleaphp.com 是由一名 FleaPHP 爱好者维护的网站,提供了一些示例程序片段和使用 FleaPHP 的经验和体会等文档。并不是 FleaPHP 项目官方网站。

FleaPHP 兼容 PHP4 吗?
是的,FleaPHP 100% 兼容 PHP4 和 PHP5。同时,FleaPHP 不限制开发者在自己编写的代码中采用 PHP5 专有的特征。

有实际采用 FleaPHP 开发的项目和网站吗?
“当然”,FleaPHP 是一个在实际开发工作中不断完善和改进的框架。因此 FleaPHP 是伴随着实际应用项目一起出现的。更多信息请浏览实际采用 FleaPHP 开发的项目和网站列表。如果你有用 FleaPHP 开发的项目,我们也希望你能够提供信息,完善这个列表。

查看(22) 评论(0) 收藏 推荐
FleaPHP 开发指南 - A2. 使用 PATHINFO 和 URL 重写
2007-02-27 21:00:36

FleaPHP 应用程序通过分析 URL 地址来确定要执行的控制器及动作,以及传递给动作方法的参数。

默认情况下,FleaPHP 应用程序通过

http://www.example.com/index.php?controller=test&action=benchmark&source=1这样的 URL 地址来访问应用程序的每一个功能。但有时候你希望 URL 地址能够更好看一点,例如上面的地址变为:

http://www.example.com/index.php/test/benchmark/source/1或者

http://www.example.com/test/benchmark/source/1要实现上述两种效果,必须借助 FleaPHP 对 PATHINFO 模式和 URL 重写的支持。


--------------------------------------------------------------------------------

 

PATHINFO
要使用 PATHINFO 模式来运行应用程序,只需要简单的设置应用程序选项 urlMode 为 URL_PATHINFO 就可以了。

 采用 PATHINFO 时,对于相对地址,必须改写为使用 / 开头的绝对地址。例如 css/style.css 应该写为 /css/style.css,而 images/banner.jpg 要写为 /images/banner.jpg。除了图片、CSS 样式表和 Javascrīpt 文件外,对网站其他文件的引用也要使用绝对地址。


--------------------------------------------------------------------------------

 

URL 重写
URL 重写比起 PATHINFO 来复杂得多,而且有一些限制。

目前 FleaPHP 对 URL 重写的支持还很简单,与 PATHINFO 相比仅仅是从 URL 地址中隐藏了 index.php 入口文件的名字; URL 重写需要 Apache 的 mod_rewrite 模块支持(IIS 用户可以使用一些商业软件); 必须配置 Apache 或者 .htaccess 文件,以便启用 mod_rewrite 模块; 对于复杂的目录结构,你不得不编写更多的重写规则。 好了,希望上面的话没有吓到你。那么看看最简单的情况:

RewriteEngine on

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php/$1 [L]
# 处理 css 子目录和 images 子目录
RewriteRule ^.*/(css/.+)$ $1 [L]
RewriteRule ^.*/(images/.+)$ $1 [L]上面的重写规则很简单,首先是启用 URL 重写。然后是判断请求的文件是否已经存在。只有当请求的文件不存在时才进行 URL 重写。

如果有更多子目录,例如 flash、scrīpts 等,只需要按照对 css 和 images 子目录的处理照搬即可。

把上述内容保存到应用程序根目录,文件名为 .htaccess。

 在 Windows 资源管理器里面不允许你建立 .htaccess 这样只有扩展名的文件。所以用记事本编写好内容后,保存时,文件名要输入为 ".htaccess"(感谢 RainChen 提供的小技巧)。

或者先将文件保存为其他名字,例如 app.htaccess。然后进入命令行窗口(通过开始菜单运行 cmd.exe 程序即可),输入 ren app.htaccess .htaccess 命令来对文件改名。

最后,修改应用程序设置的 urlMode 选项为 URL_REWRITE。


--------------------------------------------------------------------------------

 

如何生成 URL 地址
在 FleaPHP 应用程序中,我们总是应该使用 url() 函数和 FLEA_Controller_Action::_url() 方法来生成 URL 地址。这样不管 urlMode 选项怎么设置,我们都可以确保应用程序生成可以工作的 URL 地址。

例如 url('test', 'benchmark', array('source' => 1)) 这样的调用,在不同 urlMode 设置下,生成的 URL 地址也不同。

这种特性,可以避免因为应用程序修改了 urlMode 选项,而导致需要手工替换全部 URL 地址的问题。


--------------------------------------------------------------------------------

 

更复杂的自定义 URL 地址
正在开发的 URL 路由功能,可以让应用程序获得完全的自定义 URL。例如

http://www.example.com/index.php?controller=article&action=view&article_id=123可以用下面的地址来代替。不但好看,而且便于搜索引擎索引文件。

http://www.example.com/article/123
查看(31) 评论(0) 收藏 推荐
FleaPHP 开发指南 - A1. 升级 FleaPHP
2007-02-27 20:58:02

当 FleaPHP 发布新版时,您也许希望可以将应用程序所使用的 FleaPHP 框架也升级到最新版本。虽然我们已经尽量避免新版 FleaPHP 与早期的版本不兼容,但由于新功能的加入和现有功能的增强,出现不兼容的情况是在所难免的。

从 1.0.50 版本开始,FleaPHP 才算进入了比较稳定的阶段。因此升级说明也从此版本开始。


--------------------------------------------------------------------------------

 

从 1.0.50 升级到 1.0.60
新增的 actionMethodPrefix 应用程序选项默认值为 action,该设置可以进一步提高控制器方法的安全性。如果你不想修改现有应用程序的控制器方法名,那么只需要将该设置改为 '' 即可。或者在 require('FLEA/FLEA.php') 后用 set_app_inf('actionMethodPrefix', '') 修改这项设置。 新版本中去掉了 cache_get() 和 cache_set() 函数,改为用 get_cache() 和 write_cache() 代替。 新版本中将应用程序设置 coreCacheDir 更名为 internalCacheDir。 新版中将 FLEA_Helper_Html 类的全部方法转为了全局函数,并删除了 FLEA_Helper_Html 类。诸如 load_class('FLEA_Helper_Html') 这样的代码应该修改为 require_once(FLEA_DIR . '/Helper/Html.php')。同时 FLEA_Helper_Html::renderTextbox() 等方法调用也要改为 html_textbox() 等对应的全局函数。 新版中 autoLoad 选项必须是一个数组,数组中每个项目是一个要载入文件名(只需要文件名和扩展名,不需要目录)。 新版中对于 MANY_TO_MANY 关联,必须提供 joinTable 选项(也就是中间表名称)。 新版中 FLEA_Db_TableDataGateway 删除了 getMidtableName() 方法。 新版中不再推荐使用 throw_error() 显示错误信息,而是推荐使用 __THROW() 抛出异常。
查看(14) 评论(0) 收藏 推荐
FleaPHP 开发指南 - 8. 如何使用 RBAC 组件实现访问控制
2007-02-27 20:53:16

如何使用 RBAC 组件?

请务必更新到 1.0.60.553 版本以上,确保 RBAC 组件与文档中的描述相符合

RBAC 是英文(Role-Based Access Control)的缩写,也就是基于角色的访问控制。RBAC 的定义比较晦涩,我就以比较生动的形式来阐述什么是 RBAC。


--------------------------------------------------------------------------------

 

ATM 机的一天
假设有一台 ATM(自动提款机)放在街边,我们来看看这个 ATM 度过的一天。

早上,有一个家伙走到 ATM 面前,对着机器说:“芝麻开门,芝麻开门,给我 100 块!”。很显然 ATM 不会有任何动作。失望之余,这个家伙踢了 ATM 一脚走了。 中午,一位漂亮的 Office lady 走到 ATM 机面前,放入她的信用卡,输入密码后,取出了 1200 块钱。当然,这些钱很快就会变成一件衣服或是化妆品。 下班时分,银行的工作人员来到 ATM 机器面前,放入一张特制的磁卡,然后输入密码。从中查询到 ATM 机器内还有充足的现金,无需补充。所以他很高兴的开着车去下一台 ATM 机器所在地了。 现在我们要开发一台具有同样功能的 ATM 机,应该怎么做呢?

首先,我们的 ATM 机不能让人随便取钱,不然银行会破产的。接下来,ATM 机需要一个让人们放入磁卡并输入密码的设备。人们放入磁卡并输入密码后,ATM 机还要能够判断这张磁卡的卡号和密码是否有效,并且匹配。之后,ATM 机必须判断磁卡的卡号属于哪种类型,如果是信用卡,那么则显示查询账户余额和取款的界面。如果是特制的磁卡,则显示 ATM 机内的现金余额。


--------------------------------------------------------------------------------

 

ATM 与 RBAC
上面的例子显得有点荒诞,但是却是一个典型的基于角色的访问控制。

对于没有磁卡或者输入了错误密码的用户,一律拒绝服务,也就是不允许进行任何其他操作; 如果输入了正确的密码,必须判断用户输入哪一种类型,并提供相应的服务界面; 如果用户尝试访问自己不能使用的服务,那么要明确告诉用户这是不可能的。 这个流程中,一共出现了两种角色:信用卡用户和管理卡用户。而那些没有磁卡的用户,都属于没有角色一类。RBAC 要能够工作,至少需要两个数据:角色信息和访问控制表。

角色信息通常是指某个用户具有的角色,例如你持有一张信用卡,那么你就具有“信用卡用户”这个角色。如果你持有一张管理卡,那么你就具有“管理卡用户”这个角色。如果你既没有信用卡,又没有管理卡,那么你就没有上述两种角色。

有了角色信息,RBAC 系统还需要一个访问控制表。访问控制表(Access Control Table)是一组数据,用于指出哪些角色可以使用哪个功能,哪些角色不能使用哪个功能。例如在 ATM 机中,具有“信用卡用户”角色,就可以使用查询账户余额和取款两项功能;而具有“管理卡用户”角色,就可以使用查询 ATM 机内现金余额的动能。

我们来模拟一次 ATM 机的操作:

唐雷有一张信用卡,他放入 ATM 机并输入了正确的密码。这时,他被 ATM 机认为具有“信用卡用户”角色。 根据上面的判断结果,ATM 机显示了一个操作界面,上面有查询账户余额和取款两项操作按钮。 唐雷按下了“查询账户余额”按钮,ATM 机的查询账户余额功能被调用。 在查询账户余额功能中,再次检查用户的角色信息,确定他可以使用这个功能。 进行一系列操作,然后将唐雷信用卡账户上的余额数字显示到屏幕上。 唐雷很郁闷他的信用卡又透支了,悻悻然取出卡走人了。这时 ATM 自动清除当前的角色信息,为下一次操作做好准备。 从上面可以看出,RBAC 充当了系统的一道安全屏障。所有的操作都需要进过 RBAC 验证过后才能使用。这样充分保证了系统的安全性。


--------------------------------------------------------------------------------

 

RBAC 概念
在 FleaPHP 的 RBAC 组件中,只有下列几项概念需要理解:

用户:应用程序的使用者; 角色:一个名字,可以为用户指定多个角色(0-n); 访问控制表(ACT):一个数组,用来指明哪些功能可以被哪些角色访问或者限制访问。 除了上述三个概念,要想 RBAC 系统能够正常工作,还需要用户信息管理器、角色信息管理器和访问控制器三个部件。

用户信息管理器:提供用户信息的存储、查询服务,以及为用户指定角色信息; 角色信息管理器:提供角色信息的存储和查询服务 访问控制器:根据角色信息和访问控制表进行验证 FleaPHP 中已经实现了上述三个部件,所以开发者要做的功能就比较简单了。


--------------------------------------------------------------------------------

 

使用 RBAC
FleaPHP 中提供了 FLEA_Com_RBAC、FLEA_Com_RBAC_UsersManager 和 FLEA_Com_RBAC_RolesManager 三个部件,以及 FLEA_Dispatcher_Auth 调度器。

其中,FLEA_Com_RBAC_UsersManager 提供用户信息存储服务,而 FLEA_Com_RBAC_RolesManager 提供角色信息存储服务。FLEA_Com_RBAC 则和 FLEA_Dispatcher_Auth 结合,一起提供了访问控制能力。

下面我们来看看 RBAC 到底怎么工作的。

修改应用程序设置
要使用访问控制功能,首先需要修改应用程序设置。让应用程序使用 FLEA_Dispatcher_Auth 调度器,而不是默认的 FLEA_Dispatcher_Simple 调度器。

<?php

require('FLEA/FLEA.php');
set_app_inf('dispatcher', 'FLEA_Dispatcher_Auth');
/**
 * ...
 * 其他初始化代码
 * ...
 */

run();

?>FLEA_Dispatcher_Auth 调度器和 FLEA_Dispatcher_Simple 调度器的基本功能一样。但在调用控制器动作方法前,FLEA_Dispatcher_Auth 调度器会通过 FLEA_Com_RBAC 组件获取保存在 session 中的用户角色信息,然后再读取控制器的访问控制表(ACT)。最后调用 FLEA_Com_RBAC::check() 方法检查用户拥有的角色是否可以访问这个控制器及要调用的控制器动作。

验证通过,则控制器动作方法会被调用,否则将显示错误信息,或者调用应用程序设置 dispatcherAuthFailedCallback 指定的错误处理程序。

准备控制器的 ACT 文件
设置好应用程序后,接下来要做的就是为控制器准备 ACT 文件。

ACT 文件和控制器文件同名,并且保存在同一个目录下,只是扩展名为 .act.php。例如控制器 Controller_Default 的文件名是 Controller/Default.php,那么该控制器的 ACT 文件名就是 Controller/Default.act.php。

ACT 文件的内容通常使用下面的格式:

<?php

return array(
    'allow' => 'POWER_USER, SYSTEM_ADMIN',

    'actions' => array(
        'remove' => array(
            'allow' => 'SYSTEM_ADMIN',
        ),

        'create' => array(
            'deny' => 'SYSTEM_ADMIN',
        ),
    ),
);

?>可以看到,ACT 文件只是单纯的返回一个数组。这个数组遵循下面的格式:

array(
    'allow' => '允许访问该控制器的角色名',
    'deny' => '禁止访问该控制器的角色名',

    'actions' => array(
        '动作名' => array(
            'allow' => '允许访问该动作的角色名',
            'deny' => '禁止访问该动作的角色名',
        ),
        // .... 更多动作
    ),
);在上面的格式中,角色名可以是多个,例如“POWER_USER, MANAGER”。只需要用“,”分隔多个角色名就可以了。

通常,我们只需要为控制器指定 allow 或者 deny 就可以了。但有时候我们要允许多个角色都可以访问该控制器,但该控制器中的特定方法只允许上述角色中部分角色可以访问。这时,我们可以通过'动作名' => array('allow' => '角色名', 'deny' => '角色名') 的方式来指定该控制器动作特有的 ACT。

为了便于开发,FleaPHP 预定义了几个角色,分别是:

RBAC_EVERYONE:表示任何用户(不管该用户是否具有角色信息) RBAC_HAS_ROLE:表示具有任何角色的用户(该用户必须有角色信息) RBAC_NO_ROLE:表示不具有任何角色的用户 RBAC_NULL:表示该设置没有值  特别注意,上述四个预定义角色并不是字符串,而是常量。因此必须以 'allow' => RBAC_EVERYONE 这样方式使用。并且不能和其他角色混用,例如 'allow' => RBAC_EVERYONE . ', POWER_USER' 就是错误的。

验证规则
在验证时,首先从 session 中取出用户的角色信息。取出来的角色信息是一个数组,数组中每一个项为用户具有的一个角色。例如:

$userRoles = array(
    'POWER_USER',
    'MANAGER',
);然后取出控制器的 ACT,再按照下列规则进行验证:

如果 ACT 的 allow 为 RBAC_EVERYONE,则进行下列检查:
如果 ACT 的 deny 为 RBAC_NULL,则表示表示允许任何角色访问,验证结果为 true; 如果 ACT 的 deny 为 RBAC_NO_ROLE,则表示用户只要具有角色信息,就可以访问。因此如果用户的角色信息为空白,则验证结果为 false,否则验证结果为 true; 如果 ACT 的 deny 为 RBAC_HAS_ROLE,则表示用户只要具有角色信息,就不允许访问。因此如果用户的角色信息为空白,则验证结果为 true,否则验证结果为 false; 如果 ACT 的 deny 为 RBAC_EVERYONE,则表示这个 ACT 存在冲突(因为 allow 和 deny 都为 RBAC_EVERYONE); 检查用户的角色名是否出现在 deny 指定的角色名中,如果有,则验证结果为 false,否则验证结果为 true。 如果 ACT 的 allow 为 RBAC_HAS_ROLE,则表示用户只要具有角色信息,就可以访问。因此如果用户的角色信息为空白,则验证结果为 false,否则验证结果为 true; 如果 ACT 的 allow 为 RBAC_NO_ROLE,则表示用户只要具有角色信息,就不允许访问。因此如果用户的角色信息为空白,则验证结果为 true,否则验证结果为 false; 如果 ACT 的 allow 为 RBAC_NULL,则进行下列检查:
如果 ACT 的 deny 为 RBAC_NULL,则表示 ACT 既没有设置允许访问的角色,也没有设置拒绝访问的角色,这时候假定为允许访问,所以验证结果为 true; 如果 ACT 的 deny 为 RBAC_NO_ROLE,则表示用户只要具有角色信息,就可以访问。因此如果用户的角色信息为空白,则验证结果为 false,否则验证结果为 true; 如果 ACT 的 deny 为 RBAC_HAS_ROLE,则表示用户只要具有角色信息,就不允许访问。因此如果用户的角色信息为空白,则验证结果为 true,否则验证结果为 false; 如果 ACT 的 deny 为 RBAC_EVERYONE,则表示拒绝任何角色访问,验证结果为 false; 5) 检查用户用户的角色名是否出现在 deny 指定的角色名中,如果有,则验证结果为 false,否则验证结果为 true。 验证进行到这里时,ACT 的 allow 必然是角色名,因此只要用户具有的角色名在 allow 指定的角色名中,验证结果就为true,否则验证结果为false。 ACT 示例
之所有进行这么复杂的验证,是考虑到多种多样的验证需求。看看下面几个例子:

只要具有角色,就允许访问: array(
    'allow' => RBAC_HAS_ROLE
);只要具有角色,就不允许访问: array(
    'deny' => RBAC_HAS_ROLE
);用户具有角色,并且没有 POWER_USER 角色时,允许访问: array(
    'allow' => RBAC_HAS_ROLE,
    'deny' => 'POWER_USER'
)用户只要没有 MANAGER 角色,就允许访问: array(
    'deny' => 'MANAGER',
)用户具有 POWER_USER 和 MANAGER 角色时允许访问,但具有 SYSTEM_ADMIN 角色时拒绝访问。对于这个 ACT 定义,如果用户的角色为 ‚POWER_USER, GUEST‘,则允许访问。如果用户的角色为 ‚POWER_USER, SYSTEM_ADMIN‘,则不允许访问。因为 deny 的优先级总是大于 allow。 array(
    'allow' => 'POWER_USER, MANAGER',
    'deny' => 'SYSTEM_ADMIN',
)上面虽然只说了对控制器的验证,但对控制器动作的验证规则是完全相同的。只是只有当用户被允许访问控制器时,才会对要访问的控制器动作进行验证。这种机制提供非常高的灵活性,例如:

<?php

return array(
    'allow' => 'POWER_USER, SYSTEM_ADMIN',

    'actions' => array(
        'remove' => array(
            'allow' => 'SYSTEM_ADMIN',
        ),

        'create' => array(
            'deny' => 'SYSTEM_ADMIN',
        ),
    ),
);

?>用户只要具有 POWER_USER 和 SYSTEM_ADMIN 两个角色之一,就可以访问这个控制器。但只有当用户具有 SYSTEM_ADMIN 角色时,才允许使用控制器的 remove 动作。反之,如果用户具有 SYSTEM_ADMIN 角色,就不允许使用控制器的 create 动作。

 特别注意,不管是 allow 还是 deny,只要用户具有的角色有其中之一符合条件就会判定该规则有效。例如 'allow' => 'POWER_USER, SYSTEM_ADMIN' 只要用户具有 POWER_USER 和 SYSTEM_ADMIN 两个角色之一,就算作允许访问。而不需要用户同时具有 POWER_USER 和 SYSTEM_ADMIN 角色。

角色信息存储服务
准备好控制器的 ACT 后,我们还需要使用角色信息存储服务,来管理应用程序中会用到的角色信息。

首先,我们要建立如下的数据表(假定使用 MySQL)。这个数据表很简单,每行记录存储一个角色。

CREATE TABLE `roles` (
  `role_id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
  `rolename` VARCHAR( 32 ) NOT NULL ,
  `created` INT NULL ,
  `updated` INT NULL
);然后我们在应用程序中就可以从 FLEA_Com_RBAC_RolesManager 派生一个对象来管理角色信息了:

load_class('FLEA_Com_RBAC_RolesManager');
class MyRolesManager extends FLEA_Com_RBAC_RolesManager
{
    var $tableName = 'roles';
    var $primaryKey = 'role_id';
}

$rolesManager =& get_singleton('MyRolesManager');
/* @var $rolesManager MyRolesManager */
$rolesManager->create(array('rolename' => 'SYSTEM_ADMIN'));
$rolesManager->create(array('rolename' => 'POWER_USER'));
$rolesManager->create(array('rolename' => 'MANAGER'));事实上,FLEA_Com_RBAC_RolesManager 是一个表数据入口对象,所以可以直接使用 create()、find() 等方法来添加、查询角色信息。

用户信息存储服务
只有角色信息,RBAC 还无法工作。我们还需要用户信息存储服务。这些服务由 FLEA_Com_RBAC_UsersManager 来提供。首先建立存储用户信息的数据表(仍然假定使用 MySQL):

CREATE TABLE `users` (
  `user_id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
  `username` VARCHAR( 32 ) NOT NULL ,
  `password` VARCHAR( 64 ) NOT NULL ,
  `email` VARCHAR( 128 ) NOT NULL ,
  `created` INT NULL ,
  `updated` INT NULL
); 特别注意,存储用户信息的数据表中,至少需要用户名、密码和电子邮件地址三个字段。

然后我们就可以很方便的存储和查询用户信息了:

load_class('FLEA_Com_RBAC_UsersManager');
class MyUsersManager extends FLEA_Com_RBAC_UsersManager
{
    var $tableName = 'users';
    var $primaryKey = 'user_id';
}

$usersManager =& get_singleton('MyUsersManager');
/* @var $usersManager MyUsersManager */

$usersManager->create(array(
    'username' => 'dualface',
    'password' => '12345678',
    'email' => 'dualface@gmail.com',
));上面的代码会建立一个用户名为 dualface 的用户,而密码明文是 12345678。你也许会奇怪,难道密码不需要加密后存储吗?

实际上,FLEA_Com_RBAC_UsersManager 为你自动完成了该项工作。FLEA_Com_RBAC_UsersManager 在建立一个用户或者更新一个用户时,对于密码字段都是特别处理的。所以程序只需要提供密码明文就行了,而不需要自己加密。不过同时也要注意在更新用户时,不要更新密码字段。而是应该使用 FLEA_Com_RBAC_UsersManager::changePassword() 方法来修改用户账户的密码。

FLEA_Com_RBAC_UsersManager 采用什么加密方法来存储密码,是由 FLEA_Com_RBAC_UsersManager::$encodeMethod 变量决定的。默认为 PWD_CRYPT,即使用 crypt() 函数来加密。可用的加密方式还有 PWD_MD5(存储用 md5() 函数编码后的密码)和 PWD_CLEARTEXT(存储密码明文)。由于不同的加密方式,生成的密码长度都不同,所以建立用户信息数据表时,密码字段的长度为 64,而不是常用的 32。

 特别注意,crypt() 函数加密的密码超过了 32 个字符,因此一定要确保用户信息表的密码字段有足够的长度。

如果用户信息表的用户名、密码和电子邮件地址三个字段不是默认的 username、password 和 email,那么要分别通过 FLEA_Com_RBAC_UsersManager::$usernameField、FLEA_Com_RBAC_UsersManager::$passwordField 和 FLEA_Com_RBAC_UsersManager::$emailField 变量来指定。

FLEA_Com_RBAC_UsersManager 虽然也是一个表数据入口,但是提供了 findByUserId()、findByUsername、findByEmail 等便利的方法。请参考 API 文档中的 FLEA_Com_RBAC_UsersManager 类,了解所有便利方法。

为用户指定角色
有了用户和角色信息,我们还需要将用户信息和角色信息关联起来。这仍然是通过 FLEA_Com_RBAC_UsersManager 来完成。

首先也是建立一个数据表,用来存储用户和角色之间的关联关系:

CREATE TABLE `roles_users` (
  `user_id` INT NOT NULL ,
  `role_id` INT NOT NULL ,
  PRIMARY KEY ( `user_id` , `role_id` )
);接下来修改我们的 FLEA_Com_RBAC_UsersManager 继承类:

load_class('FLEA_Com_RBAC_UsersManager');

class MyUsersManager extends FLEA_Com_RBAC_UsersManager
{
    var $tableName = 'users';
    var $primaryKey = 'user_id';
    var $rolesFields = 'roles';

    var $manyToMany = array(
        'tableClass' => 'MyRolesManager',
        'mappingName' => 'roles',
        'joinTable' => 'roles_users',
    );
}新增加的一个 MANY_TO_MANY 用于将用户和角色关联起来。**注意 MANY_TO_MANY 关联的 mappingName 选项一定要和 $rolesFields 变量的值一样。否则用 FLEA_Com_RBAC_UsersManager::fetchRoles() 无法取得用户的角色信息。

不过只是这样的定义,还不能实际使用。我们看一段实际使用的代码:

<?php
require('FLEA/FLEA.php');
// 假定数据库连接信息保存在 APP/Config/DSN.php 文件中
register_app_inf('APP/Config/DSN.php');
// 由于没有调用 run() 来启动 MVC 模式,所以需要自行初始化 FleaPHP
__FLEA_PREPARE();

load_class('FLEA_Com_RBAC_RolesManager');
class MyRolesManager extends FLEA_Com_RBAC_RolesManager
{
    var $tableName = 'roles';
    var $primaryKey = 'role_id';
}

load_class('FLEA_Com_RBAC_UsersManager');
class MyUsersManager extends FLEA_Com_RBAC_UsersManager
{
    var $tableName = 'users';
    var $primaryKey = 'user_id';

    var $manyToMany = array(
        'tableClass' => 'MyRolesManager',
        'mappingName' => 'roles',
        'joinTable' => 'roles_users',
    );
}

$usersManager =& get_singleton('MyUsersManager');
/* @var $usersManager MyUsersManager */

// 取出用户
$user = $usersManager->findByUsername('dualface');
// 清空现有的角色信息
$user[$usersManager->rolesField] = array();

// 取出 POWER_USER 角色
$rolesManager =& get_singleton('MyRolesManager');
/* @var rolesManager MyRolesManager */
$role = $rolesManager->find(array('rolename' => 'POWER_USER'));
// 指定给用户
$user[$usersManager->rolesField][] = $role[$rolesManager->primaryKey];

// 取出 MANAGER 角色
$role = $rolesManager->find(array('rolename' => 'MANAGER'));
// 指定给用户
$user[$usersManager->rolesField][] = $role[$rolesManager->primaryKey];

// 保存修改后的用户信息
$usersManager->update($user);

// 重新从数据库读取用户信息,确定为用户指定的角色信息已经保存到数据库
$user = $usersManager->findByUsername('dualface');
dump($user);运行这段代码,可以看到为用户指定的角色信息,确实保存到数据库了:


通常,我们会在应用程序中提供一个管理界面,用于管理用户信息,并且可以为用户指定角色。这样的管理界面类似下图:


上图中的权限实际上就是可以给用户指定的角色,只不过换了一个称谓而已。

用户登录
由于要使用 RBAC 组件进行访问控制,所以我们的用户登录部分要多写几行代码。常见的登录代码如下:

<?php
require('FLEA/FLEA.php');
// 假定数据库连接信息保存在 APP/Config/DSN.php 文件中
register_app_inf('APP/Config/DSN.php');
// 由于没有调用 run() 来启动 MVC 模式,所以需要自行初始化 FleaPHP
__FLEA_PREPARE();

load_class('FLEA_Com_RBAC_RolesManager');
class MyRolesManager extends FLEA_Com_RBAC_RolesManager
{
    var $tableName = 'roles';
    var $primaryKey = 'role_id';
}

load_class('FLEA_Com_RBAC_UsersManager');
class MyUsersManager extends FLEA_Com_RBAC_UsersManager
{
    var $tableName = 'users';
    var $primaryKey = 'user_id';

    var $manyToMany = array(
        'tableClass' => 'MyRolesManager',
        'mappingName' => 'roles',
        'joinTable' => 'roles_users',
    );
}

/**
 * 模拟登录
 */
login('dualface', '12345678');

/**
 * 处理用户登录
 */
function login($username, $password) {
    $usersManager =& get_singleton('MyUsersManager');
    /* @var $usersManager MyUsersManager */

    // 验证用户名和密码是否正确
    $user = $usersManager->findByUsername($username);
    if (!$user || !$usersManager->checkPassword($password, $user[$usersManager->passwordField])) {
        echo "Username invalid or password mismatch.";
        exit;
    }

    // 获取用户角色信息
    $roles = $usersManager->fetchRoles($user);

    // 获得 FLEA_Com_RBAC 组件实例
    $rbac =& get_singleton('FLEA_Com_RBAC');
    /* @var $rbac FLEA_Com_RBAC */

    // 为了降低服务器负担,我们只在 session 中存储用户ID和用户名
    $sessionUser = array(
        'USERID' => $user[$usersManager->primaryKey],
        'USERNAME' => $user[$usersManager->usernameField],
    );

    // 将用户ID、用户名和角色信息保存到 session
    $rbac->setUser($sessionUser, $roles);

    // 登录成功
    echo "Login successed, contents of session:";
    dump($_SESSION);
}

?>上面的代码中第一次出现了对 FLEA_Com_RBAC 的使用。通常我们只需要用到 FLEA_Com_RBAC::setUser() 方法。这个方法将用户信息和对应的角色信息保存到 session。为了节约服务器资源,我们要尽量减少保存在 session 中的内容。

运行这个脚本,可以看到如下的输出:


大家在开发自己的应用程序时,基本上可以把 login() 函数的内容照搬过去。

用户注销
处理用户注销非常简单,通常用 session_destroy() 销毁 session 数据就可以了。如果只想清除用户登录信息,而不影响 session 中的其他信息,可以用下面两行代码:

$rbac =& get_singleton('FLEA_Com_RBAC');
$rbac->clearUser();
--------------------------------------------------------------------------------

 

实现访问控制
实际上,做完上面几个步骤,我们的 RBAC 已经可以工作了。你可以尝试登录系统,然后访问那些受到保护的控制器。然后再从系统注销后,重新访问受保护的控制器。

目前,FleaPHP 的 RBAC 在处理 ACT 上,还不够灵活。每个控制器的 ACT 都是从文件载入的,而不是从数据库。但有聪明的开发者已经想出了变通的做法。

那就是把从数据库获取控制器 ACT 的代码写在控制器的 .act.php 文件中,例如:

APP\Controller\MyController.act.php

<?php

$modelACT =& get_singleton('Model_ControllerACTProvider');
/* @var $modelACT Model_ControllerACTProvider */
return $modelACT->getACT('MyController');

?>当然,我们还要实现一个 Model_ControllerACTProvider 表数据入口:

<?php

load_class('FLEA_Db_TableDataGateway');

class Model_ControllerACTProvider extends FLEA_Db_TableDataGateway
{
    var $tableName = 'controller_acts';
    var $primaryKey = 'controller_name';

    function getACT($controllerName) {
        $row = parent::find(array($this->primaryKey => strtoupper($controllerName)));
        return unserialize($row['act']);
    }

    function setACT($controllerName, $ACT) {
        $row = array(
            $this->primaryKey => strtoupper($controllerName),
            'act' => serialize($ACT)
        );
        return parent::create($row);
    }
}

?>以及一个数据表:

CREATE TABLE `controller_acts` (
  `controller_name` VARCHAR( 32 ) NOT NULL ,
  `act` TEXT NOT NULL ,
  `created` INT NULL ,
  `updated` INT NULL ,
  PRIMARY KEY ( `controller_name` )
)这样一来,我们就可以在数据库中保存控制器的 ACT 了。

查看(21) 评论(0) 收藏 推荐
FleaPHP 开发指南 - 7. 数据表关联
2007-02-27 20:41:40

数据表关联是指两个或者多个数据表的记录之间的逻辑关系。

例如:

每一个公民都有一个身份证号码 每一位作者都写了多本(0-n)书籍,而每一本书籍都有多个(1-n)作者 每一篇文章都有多个(0-n)评论 每一个评论都属于一篇文章 目前,FleaPHP 支持四种类型的数据表关联,分别是:

HAS_ONE: 当前表的每一条记录都拥有最多一条(0–1)关联记录 HAS_MANY: 当前表的每一条记录都拥有多条(0-n)关联记录 MANY_TO_MANY: 当前表的每一条记录都和其他表的多条(0-n)记录关联 BELONGS_TO: 当前表的每一条记录都属于另一个表的某条记录 在 FleaPHP 中,可以为每一个表数据入口定义多个不同的关联,例如:

<?php

load_class('FLEA_Db_TableDataGateway');

class Model_ProductClass extends FLEA_Db_TableDataGateway
{
    var $tableName = 'product_class';
    var $primaryKey = 'pclass_id';

    var $hasMany = array(
        array(
            'tableClass' => 'Model_Permissions',
            'foreignKey' => 'pclass_id',
            'mappingName' => 'permissions',
        ),
        array(
            'tableClass' => 'Model_Products',
            'foreignKey' => 'pclass_id',
            'mappingName' => 'products',
            'enabled' => false,
        ),
    );
    var $hasOne = array(
        array(
            'tableClass' => 'Model_ProductClassAdverts',
            'foreignKey' => 'pclass_id',
            'mappingName' => 'advert',
        )
    );
}

?>
--------------------------------------------------------------------------------

 

术语
在详细介绍这四种关联之前,先了解一些后文将会用到的术语。

关联: 一个关联是一个关系,这个关系属于某一个数据表。例如 users 表可能就拥有一个或者多个关联。 主表: 对于一个关联,拥有该关联的数据表就是主表。例如 posts 表定义了一个 MANY_TO_MANY 关联。那么在这里(指这个关联),posts 就是主表。 关联表: 在一个关联中,关联表就是除主表外的另一个表。 外键: 在数据库原理中,外键的含义很复杂。但在 FleaPHP 框架中的数据库关联功能中,外键泛指一个记录中用于关联另一个记录的字段。例如 profile 表中的 user_id 字段就是用于关联 users 表的字段。这个 user_id 字段就是一个外键。 中间表: 在 MANY_TO_MANY 关联中,除了主表和关联表,还需要另一个表来保存这两个表的记录之间的互相关联关系。这个表称为中间表。 理解这几个术语后,我们再来看每一种关联的详细解释。


--------------------------------------------------------------------------------

 

HAS_ONE 一对一关联
HAS_ONE 是一种非常简单的关联关系。表示一个记录拥有另一个记录。这两个记录分别位于两个数据表中。

示例
在一个信息管理系统中,users 表用于存储用户帐户的基本信息,例如用户名、密码等。而 profiles 表则用于存储用户的个人信息,例如家庭住址、邮政编码等。

由于每一个用户(一条 users 表中的记录)都有一份对应的个人信息(一条 profiles 表中的记录)。因此,我们就可以为 users 表定义一个 HAS_ONE 关联。

很明显,users 表的记录拥有一条 profiles 表的记录。因此,当 users 表中的一条记录被删除时,被删除记录所拥有的 profiles 表中的关联记录也会被自动删除。

表定义
在 HAS_ONE 关联中,要求外键放置在关联表中。

上述例子的表定义简化版如下:

users 表:

user_id 主键字段 username profiles 表:

profile_id 主键字段 address postcode user_id 外键字段 对应的 MySQL 代码如下:

CREATE TABLE `users` (
    `user_id` INT NOT NULL AUTO_INCREMENT ,
    `username` VARCHAR( 32 ) NOT NULL ,
    PRIMARY KEY ( `user_id` )
);

CREATE TABLE `profiles` (
    `profile_id` INT NOT NULL AUTO_INCREMENT ,
    `address` VARCHAR( 128 ) NOT NULL ,
    `postcode` VARCHAR( 8 ) NOT NULL ,
    `user_id` INT NOT NULL ,
    PRIMARY KEY ( `profile_id` )
);对应的 FLEA_Db_TableDataGateway 继承类的定义如下:

<?php

load_class('FLEA_Db_TableDataGateway');

class Users extends FLEA_Db_TableDataGateway
{
    var $tableName = 'users';
    var $primaryKey = 'user_id';

    var $hasOne = array(
        'tableClass' => 'Profiles',
        'foreignKey' => 'user_id',
        'mappingName' => 'profile',
    );
}

class Profiles extends FLEA_Db_TableDataGateway
{
    var $tableName = 'profiles';
    var $primaryKey = 'profile_id';
}

?>演示代码
<?php

// 首先插入一条 users 记录
$modelUsers =& new Users();
$newUserId = $modelUsers->create(
    array('username' => 'dualface')
);

// 接下来,再插入一条 profiles 记录
$modelProfiles =& new Profiles();
$modelProfiles->create(
    array(
        'address' => 'SiChuan ZiGong',
        'postcode' => '643000',
        'user_id' => $newUserId
    )
);

// OK,我们现在尝试读取一条 users 记录,看看会得到什么结果
$user = $modelUsers->find($newUserId);
dump($user);

?>结果很有趣,多出来的 ‘profile’ 字段正好是我们刚刚插入 profiles 表的记录内容:

Array
(
    [user_id] => 1
    [username] => dualface
    [ref___id] => 1
    [profile] => Array
        (
            [profile_id] => 1
            [address] => SiChuan ZiGong
            [postcode] => 643000
            [user_id] => 1
            [ref___id] => 1
        )
)说明
在上面的例子中,Users 类中有一个 $hasOne 成员变量。该变量为一个数组:

var $hasOne = array(
    'tableClass' => 'Profiles',
    'foreignKey' => 'user_id',
    'mappingName' => 'profile',
);$hasOne 成员变量用于为一个表数据库入口指定 HAS_ONE 关联。

 在关联的定义中,tableClass 指定关联表的表数据入口类名称,foreignKey 指定外键字段名,而 mappingName 则指定在主表的查询结果中用什么字段映射关联表的数据。

 

 

未完待续。。。。

查看(15) 评论(0) 收藏 推荐
FleaPHP 开发指南 - 6. 访问数据库
2007-02-27 20:32:39

这一章我们就来看看 FleaPHP 的数据库访问功能。体验一下 FleaPHP 出色的自动化 CRUD 能力。


--------------------------------------------------------------------------------

 

连接数据库
在 htdocs 目录中创建子目录 testDB,并在子目录下创建文件 test1.php 文件,内容如下:

<?php

require('../FLEA/FLEA.php');
__FLEA_PREPARE();

// 准备数据库连接信息
$dsn = array(
    'driver'        => 'mysql',
    'host'          => 'localhost',
    'login'         => 'root',
    'password'      => '',
    'database'      => 'test',
);

// 获取数据库访问对象
$dbo =& get_dbo($dsn);

// 连接到数据库
if ($dbo->connect()) {
    echo 'Connect to database successed.';
}

?> 请注意这里我们没有调用 run() 函数。因此我们需要调用 __FLEA_PREPARE() 函数来初始化 FleaPHP 运行环境。并且 __FLEA_PREPARE() 函数应该在用 register_app_inf() 或 set_app_inf() 修改应用程序设置后调用。

现在启动 APM Express,通过浏览器执行 http://localhost/testDB/test1.php,如果一切正常,应该看到 Connect to database successed 信息。

如果出现如下的错误信息,说明 MySQL 数据库的 root 用户密码不正确。请修改上面代码中的 password 信息。

Warning: mysql_connect() [function.mysql-connect]: Access denied for user 'root'@'localhost'
--------------------------------------------------------------------------------

 

创建记录
接下来,我们用 phpMyAdmin 在 test 数据库中执行下面的 SQL 语句。这会创建在 test 数据库中创建一个名为 posts 的表。

CREATE TABLE `posts` (
  `post_id` int(11) NOT NULL auto_increment,
  `title` varchar(255) NOT NULL,
  `body` text NOT NULL,
  `created` int(11) default NULL,
  `updated` int(11) default NULL,
  PRIMARY KEY  (`post_id`)
) DEFAULT CHARSET=gb2312;现在我们修改 test1.php 的内容为以下内容:

<?php

require('../FLEA/FLEA.php');

// 准备数据库连接信息
$dsn = array(
    'driver'        => 'mysql',
    'host'          => 'localhost',
    'login'         => 'root',
    'password'      => '',
    'database'      => 'test',
);
// 指定数据库连接设置,TableDataGateway 会自动取出 dbDSN 设置来连接数据库
set_app_inf('dbDSN', $dsn);

// 初始化 FleaPHP 运行环境
__FLEA_PREPARE();

// 由于 FLEA_Db_TableDataGateway 并不是自动载入的,因此需要明确载入
load_class('FLEA_Db_TableDataGateway');

// 从 FLEA_Db_TableDataGateway 派生 Posts 类
class Posts extends FLEA_Db_TableDataGateway
{
    // 指定数据表名称
    var $tableName = 'posts';
    // 指定主键字段名
    var $primaryKey = 'post_id';
}

// 构造 Posts 实例
$modelPosts =& new Posts();
// 创建一条新记录,并返回新记录的主键值
$newPostId = $modelPosts->create(array(
    'title' => 'First post',
    'body'  => 'First post body',
));
echo $newPostId;

?>在浏览器重新运行 test1.php,会看到输出结果 1。如果多刷新几次,可以看到这个数字不断增长。现在转到 phpMyAdmin,浏览 posts 表,会发现这个表已经插入了数据。


注意上图中划红圈的 created 字段。虽然我们上面的代码在用 $modelPosts->create() 插入记录时并没有提供该字段的值,但该字段的值被自动填充了。

 当数据表中具有名为 created、created_at 或 created_on 的字段,并且字段类型为整数或日期,则在向这个数据表插入记录时。FleaPHP 会自动用当前时间填充该字段。同样的,updated、updated_at 或 updated_on 字段会在更新记录时用当前时间填充。

关于 FLEA_Db_TableDataGateway
FLEA_Db_TableDataGateway 是一个提供自动化 CRUD 操作的类。开发者必须从该类派生自己的类。每一个 FLEA_Db_TableDataGateway 派生类对应一个数据表。例如上面代码中的 Posts 类就对应数据表 posts。FLEA_Db_TableDataGateway 派生类在 FleaPHP 应用程序中称为表数据入口。

每一个表数据入口都需要定义一个必须的成员变量:

$tableName 指定该表数据入口对应的数据表 如果数据表有多个主键字段,那么还要用 $primaryKey 指定要使用的主键字段。当没有用 $primaryKey 指定时,FLEA_Db_TableDataGateway 会自动根据数据表定义来确定主键字段名。

完成上面的定义后,一个表数据入口类就准备好了。只要实例化这个类,就能对该类对应的数据表进行各种操作了。


--------------------------------------------------------------------------------

 

读取和更新记录
现在我们继续修改前面的代码,增加如下内容:

/**
 * .... 接续上面的代码片段
 */

echo "<hr />\n";
// 读取刚刚创建的新记录
$post = $modelPosts->find($newPostId);
// 输出记录内容
dump($post);

// 修改记录内容
$post['title'] = 'New title';
// 保存修改后的记录到数据库
$modelPosts->update($post);

// 重新查询被修改后的记录
$updatedPost = $modelPosts->find($newPostId);
// 输出修改后的记录内容
dump($updatedPost);现在通过浏览器执行 test1.php,就可以看到两个稍有不同的输出。

第一段输出是用 $modelPosts->find() 取出的记录内容。而第二段数据是用 $modelPosts->update() 更新后再取出的记录内容。


对比两段输出,可以看到第二段输出的 title 字段和 updated 字段都被修改了。


--------------------------------------------------------------------------------

 

删除记录
删除记录有两种主要的方式,一是用表数据入口的 remove() 方法,以一条记录做参数。另一种方法是用 removeByPkv() 方法,以记录的主键值做参数。

// 取出所有 title 字段值为 'First post' 的记录
$posts = $modelPosts->findAll(array('title' => 'First post'));
// 删除这些记录
foreach ($posts as $post) {
    $modelPosts->remove($post);
    // 或者使用
    // $modelPosts->removeByPkv($post[$modelPosts->primaryKey]);
}这个章节里面,我们粗略的看了一下 FleaPHP 提供的表数据入口提供的基本操作。在后续章节里面,我们会看到表数据入口的其他强大功能。

查看(30) 评论(0) 收藏 推荐
FleaPHP 开发指南 - 5. 应用程序设置
2007-02-27 20:25:03

FleaPHP 是一个具有高度灵活性的框架。开发者可以用不同的设置来调整 FleaPHP 的工作方式。这些设置统一保存在名为“应用程序设置”的数据源中。

实际上,除了 FleaPHP 框架本身,应用程序也可以使用“应用程序设置”来保存应用程序运行时需要的各种设置。

FleaPHP 的应用程序设置有一个默认配置文件,保存在 FLEA/Config/Default_APP_INF.php 中。应用程序可以在入口文件(例如 index.php)中修改这些设置,以便调整 FleaPHP 的工作方式。


--------------------------------------------------------------------------------

 

如何使用应用程序设置?
当 FleaPHP 框架初始化时,默认的应用程序设置文件(Default_APP_INF.php)会被载入。如果应用程序要指定设置,推荐的做法有下列几种:

创建应用程序的私有设置文件
当需要指定多个应用程序设置时,推荐使用该方法。具体的做法非常简单,只需要定义类似如下的文件即可(假设下面的内容保存到文件 APP/Config/MY_APP_INF.php)。

<?php
return array(
    'defaultController' => 'UserCenter',
    'urlLowerChar'      => false,
    'dispatcher'        => 'FLEA_Dispatcher_Auth',
    'dbDSN'     => array(
        'driver'        => 'mysql',
        'host'          => 'localhost',
        'login'         => 'root',
        'password'      =>空字符串,
        'database'      => 'test',
    ),
);
?>然后在应用程序的入口文件 index.php 中调用 run() 函数的代码前,增加一行 register_app_inf('APP/Config/MY_APP_INF.php') 即可。例如:

<?php
require('FLEA/FLEA.php');
register_app_inf('APP/Config/MY_APP_INF.php');
run();
?>直接在入口文件中指定设置
对于少量的设置,可以在入口文件中直接用 set_app_inf() 函数指定。例如:

<?php
require('FLEA/FLEA.php');
set_app_inf('defaultController', 'UserCenter');
run();
?> 不管采用哪一种方式,重要的都是必须在 run() 之前就指定好应用程序设置。


--------------------------------------------------------------------------------

 

默认的应用程序设置
默认的应用程序设置提供了符合常见应用程序运行需要的设置。下面分类列出这些设置的名字和详细说明。

核心配置
namespace 应用程序的默认名字空间,默认值为空字符串
这个设置会影响到应用程序所有类的名称定义。例如 namespace 设置为 FOO 时,应用程序所有控制器、模型的类名字都要加上前缀 FOO_。变成诸如 FOO_Controller_Default、FOO_Model_News 等。

该设置仅用于兼容使用早期FleaPHP开发的应用程序,不建议在新应用程序中使用。

为了让你的代码能够更容易的在其他应用程序中复用,最好将 namespace 设置为空字符串。
controllerAccessor 指示控制器的 URL 参数名,默认值为 controller
这个设置指定在 URL 查询参数中,用什么名字的参数指定控制器名字。例如 controllerAccessor 设置为 “ctl” 时,就必须用 index.php?ctl=MyController 来指定要调用的控制器。
defaultController 指示默认控制器的名字,默认值为 Default
当 url 参数中没有指定要调用的控制器时,将依据 defaultController 的设置调用默认的控制器。
actionAccessor 和 defaultAction,默认值分别为 action 和 index
这两个设置的作用和 controllerAccessor、defaultController 类似。只不过用于指定控制器动作的参数名和默认动作名。
urlMode 指定 URL 分析和构造模式,默认值为 URL_STANDARD
URL 的分析和构造模式,目前支持三种,分别是:URL_STANDARD、URL_PATHINFO 和 URL_REWRITE。

URL_STANDARD 模式中,URL 参数采用采用标准的方式,例如 index.php?controller=MyController&action=MyAction&class_id=2&sort=1

关于 URL_PATHINFO 和 URL_REWRITE 的详细说明,请参考使用 PATHINFO 和 URL 重写。
urlLowerChar 指示是否将 url 参数中包含的控制器名字和动作名字强制转为小写字符,默认值为 false
对于 Windows 系统来说,这个设置无关紧要。而对于 Linux/Unix 系统来说,这个设置会关系到控制器类定义文件的命名。

当 urlLowerChar 为 true 时,控制器名字会被转为小写字符,而该控制器的类名字除第一个字母为大写外,其他全为小写。例如控制器名为 MyController,实际的控制器类名称为 Mycontroller,对应的类定义文件为 Mycontroller.php。

当 urlLowerChar 为 false 时,控制器名字和控制器的类名字完全对应,例如控制器名为 QuickBenchmark,实际的控制器类名称为 QuickBenchmark,对应的类定义文件为 QuickBenchmark.php。
controllerClassPrefix 指示控制器类名称前缀,默认值为 Controller_ actionMethodPrefix 和 actionMethodSuffix 指示控制器动作的方法名要加上的前缀和后缀,默认值分别为 action 和空字符串
使用前缀和后缀可以,让控制器动作方法的名称和控制器中的其他方法区别开来。同时也可以避免无意中造成控制器内的私有方法被浏览器访问到。
dispatcher 指示应用程序要使用的 URL 调度器,默认值为 FLEA_Dispatcher_Simple
URL 调度器分析 URL 参数,决定要调用的控制器和控制器动作方法,最后调用控制器动作方法。默认的 FLEA_Dispatcher_Simple 是一个简单的调度器,仅仅是分析 URL 参数,然后完成调用工作。而更复杂的 FLEA_Dispatcher_Auth 则可以结合 FleaPHP 自带的 RBAC(基于角色的访问控制)组件完成访问控制功能。

如果开发者自己编写了调度器,那么修改这个设置即可让应用程序使用开发者自己编写的调度器。
dispatcherFailedCallback 指示调度器调度失败后,要调用的处理程序,默认值为 null
如果希望应用程序处理调度失败的情况(例如控制器或控制器方法不存在),则需要覆盖这个设置。
<?php
set_app_inf('dispatcherFailedCallback', 'appDispatcherFailedHandler');
?>internalCacheDir 指示 FleaPHP 内部及 cache 系列函数使用的缓存目录,默认值为 FLEA/_Cache/ 目录 autoLoad 指示要自动载入的文件,默认载入 FLEA_Helper_Array.php、FLEA_Helper_Html.php 和 FLEA_Controller_Action.php 三个文件
这个设置必须是一个数组,数组中每一个项目为要自动载入的文件。
sessionProvider 指示要使用的 session 服务提供程序,默认值为 null
如果设置为 null,则表示使用 PHP 自带的 session 服务。
autoSessionStart 指示是否自动起用 session 支持,默认值为 true
如果该设置为 true,则每次 FleaPHP 框架初始化后都会自动执行 session_start() 函数。
requestFilters 指示使用哪些过滤器对 HTTP 请求进行过滤,默认值为空数组
和 autoLoad 设置类似,该设置必须为数组。但数组中每一个项目为要运行的过滤器类名字。过滤器按照出现在数组中的顺序初始化和运行。

每一个过滤器实际上都是一个脚本,无需要实现为一个类。可以参考 FLEA/Filter/ 目录中的过滤器代码实现自己的过滤器。

 FleaPHP 初始化时,会根据 PHP 运行环境设置和应用程序设置来决定是否自动运行 FLEA_Filter_MagicQuotes 和 FLEA_Filter_Uri 过滤器。因此开发者不应该在 requestFilters 设置中调用这两个过滤器。
数据库相关
dbDSN 数据库连接设置,必须是数组,默认值为 null
dbDSN 是 FleaPHP 应用程序默认的数据库连接设置。正确指定该设置后,FleaPHP 会在应用程序需要访问数据库时尝试自动连接数据库。

dbDSN 数组中每个选项的含义如下:

driver 数据库驱动类型,例如 mysql、pgsql 等; host 数据库所在服务器,通常为 localhost 或 127.0.0.1 port 连接数据库的端口,通常无需指定 login 连接时使用的用户名 password 连接时使用的密码 database 连接后要使用的数据库名 charset 字符集设置,如果没有设置该选项,则以应用程序设置 databaseCharset 为准 options 附加的连接选项 典型的 dbDSN 设置如下:
<?php
set_app_inf('dbDSN',
    array(
        'driver'    => 'mysql',
        'host'      => 'localhost',
        'login'     => 'username',
        'password'  => 'password',
        'database'  => 'test_db',
    )
);
?>dbTDGAutoInit 指示构造表数据入口对象时,是否自动连接到数据库,默认值为 true
如果你希望自己控制数据库连接,那么可以将该设置指定为 false。
dbTablePrefix 指示数据表的全局前缀,默认为空字符串,该设置会影响到所有数据表 dbValidationProvider 指示表数据入口要使用的数据验证服务对象,默认值为 FLEA_Helper_Validation 视图和模版相关
view 指示要使用的模板引擎,PHP 表示使用 PHP 语言本身作模板引擎,默认值为 PHP
目前 FleaPHP 提供了 FLEA_View_Simple 模版引擎和 FLEA_View_Smarty 模版引擎。其中 FLEA_View_Smarty 实际上是一个连接器,用于连接 Smarty 模版引擎。
viewConfig 指定模板引擎要使用的配置信息,默认为 null
不同模版引擎可能需要不同的配置,可以用 viewConfig 设置来指定。
I18N
有关 FleaPHP 对 I18N 支持的详细信息,请参考开发指南的相关章节。

responseCharset 指示 FleaPHP 输出内容的使用的编码,默认值为 gb2312
FleaPHP 核心本身并不假定要处理的内容采用什么编码,也不会自动将输入内容转换为输出内容指定的编码。responseCharset 设置仅仅是用来作为一个参考,特别是 autoResponseHeader 设置为 true 时,FleaPHP 会自动送出 Content-Type: text/html; charset=xxxxx 的 HTTP 头信息。
databaseCharset 指示当 FleaPHP 连接数据库时,要指定的编码,默认值为 gb2312
许多较为高级的数据库,例如 PostgreSQL、MySQL 4.1/5.x、Oracle 等,都允许在数据库中保存不同编码的数据。因此开发者要正确设置 databaseCharset 设置,以便 FleaPHP 在连接数据库时能够正确设置编码,避免乱码问题。

对于较老的数据库,例如 MySQL 3.x/4.0,这个设置没有意义。
autoResponseHeader 指示是否自动输出 Content-Type: text/html; charset=xxxxx 的 HTTP 头信息,默认值为 true
当该设置为 true 时,FleaPHP 会在初始化时自动输出一个 HTTP 头信息,以指定应用程序输出内容的编码。具体指定什么编码,由 responseCharset 设置决定。

对于大部分服务器,启用该设置可以避免出现浏览器无法正确识别输出内容编码的问题。但在某些服务器环境中,启用该设置会导致出现无法输出动态图像等问题。
charsetConstant 指示是否自动定义 RESPONSE_CHARSET、DATABASE_CHARSET 等常量,默认值为 true
当该设置为 true 时,FleaPHP 会在初始化时根据 responseCharset 和 databaseCharset 设置分别定义 RESPONSE_CHARSET 和 DATABASE_CHARSET 常量。应用程序可以用这两个常量简化一些开发。
multiLangaugeSupport 指示是否启用多语言支持,默认值为 false
当该设置为 true 时,会自动载入由 languageSupportProvider 指定的多语言支持服务提供程序。
languageSupportProvider 指定提供多语言支持的提供程序,默认值为 FLEA_Com_Language
FLEA_Com_Language 是 FleaPHP 自带的多语言支持服务提供程序。
languageFilesDir 指示语言文件的保存位置,默认值为 null
当使用多语言支持时,必须修改该设置,指向一个保存所有语言文件的目录。

语言文件按照“语言/字典名.php”的目录结构存储,例如 languageFilesDir 设置为 /var/www/test/languages,则语言文件的实际文件名就可能是:/var/www/test/languages/chinese-gb2312/user_interface.php。
defaultLanguage 指示默认语言,默认值为 chinese-gb2312
当载入语言文件时如果没有指定语言参数,则会从 defaultLanguage 指定的语言目录下载入字典文件。
autoLoadLanguage 指示要自动载入的语言字典,默认值为 null
autoLoadLanguage 可以是数组,其中每一项是一个要载入的字典名。或者是一个用“,”分隔多个字典名的字符串。
FLEA_Dispatcher_Auth 和 RBAC 组件
dispatcherAuthProvider 指示调度器要使用的验证服务提供程序,默认值为 FLEA_Com_RBAC
FLEA_Com_RBAC 提供了 check() 方法,让调度器通过调用该方法来检查当前发起请求的用户是否有权限访问指定的控制器和控制器动作方法。如果开发者要编写自己的验证服务提供程序,就必须实现 check() 方法。如果使用开发者自己编写的调度器,也可以通过该设置来指定验证服务提供程序。

check() 方法的原型是:function check($roles, $ACT)
defaultControllerACTFile 指示 RBAC 组件要使用的默认 ACT 文件,默认值为空字符串
通过该设置,可以为多个控制器指定 ACT(访问控制表),而不需要为每一个控制器都提供一个 .act.php 文件。注意,该设置指定的文件必须是完整路径,或者相对于应用程序入口(index.php)的相对路径。
autoQueryDefaultACTFile 指示 RBAC 组件是否在没有找到控制器的 ACT 文件时,是否从默认 ACT 文件中查询控制器的 ACT,默认值为 false controllerACTLoadWarning 指示没有找到控制器的 ACT 时,是否显示警告信息,默认值为 true defaultControllerACT 指示当没有为控制器提供 ACT 时,要使用的默认 ACT,默认值为 null dispatcherAuthFailedCallback 指示用户没有权限访问控制器或控制器方法时,要调用的处理程序,默认值为 null RBACSessionKey 指示 RBAC 组件用什么键名在 session 中保存用户数据,默认值为 RBAC_USERDATA
如果在一个域名下同时运行多个应用程序,请务必为每一个应用程序使用自己独一无二的键名。
日志服务和错误处理
logEnabled 指示是否启用日志服务,默认值为 false
如果该设置为 true,则会自动载入由 logProvider 设置指定的日志服务提供程序。
logProvider 指示日志服务的程序,默认值为 FLEA_Com_Log logFileDir 指示用什么目录保存日志文件,默认值为 null
最好将日志保存在浏览器无法访问的目录中。
logFilename 指示用什么文件名保存日志,默认值为 access.log logFileMaxSize 指示当日志文件超过多少 KB 时,自动创建新的日志文件,单位是 KB,不能小于 512KB,默认值为 4096 logErrorLevel 指示哪些级别的错误要保存到日志中,默认值为 ‚warning, error, exception‘ displayErrors 指示是否显示错误信息,默认值为 true friendlyErrorsMessage 指示是否显示友好的错误信息,默认值为 true
查看(33) 评论(0) 收藏 推荐
FleaPHP 开发指南 - 4. 命名规范和目录结构
2007-02-27 20:22:56

FleaPHP 的命名规则和目录结构初看上去比较复杂,但习惯以后,你会发现这种命名规则带来许多好处。因此像 Zend Framework 也是采用同样的做法。

当然,FleaPHP 对于应用程序的命名规则和目录结构没有强制性要求。只不过采用一致的命名规则和目录结构,可以方便对应用程序维护。同时 FleaPHP 应用程序开发者之间也可以更容易的进行协作。


--------------------------------------------------------------------------------

 

全局函数的命名规则
全局函数的命名规则是用“_”分隔全小写的单词。例如 get_cache()、echo_h()。同时,函数的名字采用“动词+宾语”的形式。例如 write(动词)_cache(宾语)。

不过有些全局函数为了和 PHP 中已有的类似函数保持一致,采用了不同的命名方式(顺便抱怨一下,PHP 自身的全局函数命名比较混乱,各种形式的都有)。


--------------------------------------------------------------------------------

 

类的命名规则
所有 FleaPHP 自带的类,都以 FLEA_ 开头。然后根据用途命名。例如 FLEA_Controller_Action、FLEA_Helper_ImgCode。然后将类名字中的“_”替换为目录分隔符,就是这个类的定义文件所在位置。

举例:

FLEA_Controller_Action 类,保存文件为 FLEA/Controller/Action.php
FLEA_Db_TableDataGateway 类,保存文件为 FLEA/Db/TableDataGateway.php

这种命名规则和目录结构的优缺点如下:

优点:

避免命名冲突 根据类名字就能找到文件存放位置 应用程序中可以使用 FleaPHP 的 import()、load_class() 函数方便的载入类定义文件 如果使用 PHP5,可以很方便的用 __autoload() 来自动载入需要的类定义: <?php
function __autoload($className) {
    load_class($className);
}
?>缺点:

类名字较长,不便于输入,例如 FLEA_Com_RBAC_UsersManager 也许和现有习惯不同,需要时间来适应 对于第一个缺点,使用 Zend Development Environment 或者 Eclipse 这样的 IDE 可以缓解。这些 IDE 提供强大的输入自动完成功能,通常输入类名字的开头几个字母,就会显示候选列表让开发者选择。


--------------------------------------------------------------------------------

 

变量和常量命名
在 FleaPHP 中,变量分为全局变量、临时变量和模版变量三类。

全局变量和常量
全局变量和常量都使用全大写,以“_”分隔。例如 $GLOBALS['CLASS_PATH'] 和 FLEA_DIR。不过 FleaPHP 中尽量避免了使用全局变量和常量,因此一般来说不会和应用程序产生冲突。
临时变量
函数、类方法中使用的变量都是临时变量,命名规则是第一个单词小写,后续的单词第一个字母大写。例如 $requestFilters、$dispatcherClass 等。
模版变量
之所以要把模版变量单独列出来,是因为不同的模版引擎对变量名有不同的规范。从我个人来说,我倾向于模版变量使用全小写单词,并以“_”分隔,例如 $latest_products_list。这样在程序里面一眼就能看出哪些变量是用于模版的。

--------------------------------------------------------------------------------

 

FleaPHP 的目录结构
一个典型的 FleaPHP 应用程序具有如下的目录结构:


这个应用程序的目录主要分为 WebLibs 和 WebRoot。其中 WebLibs 保存程序的所有代码,而 WebRoot 目录下只保存用户可以访问的部分,例如 index.php 入口文件、图片、CSS 样式表和 JS 脚本。

WebLibs 下又分为 FLEA 和 YORK 两个目录。FLEA 目录保存 FleaPHP 的核心文件,而 YORK 目录保存应用程序的代码。之所以取名 YORK,是因为这个项目的公司名为 YORK。所以开发者在规划目录结构时,可以参照这种方式,为保存应用程序代码的目录取一个容易理解的名字。

WebRoot 是保存用户使用浏览器可以直接访问的内容,因此需要修改服务器或虚拟主机设置,将网站的根目录指向 WebRoot 目录。例如 www.example.com 指向 /example/WebRoot/。

这里介绍的目录结构有如下优点:

优点:

代码文件放置在浏览器访问不到的地方,提高了安全性 程序员和设计人员可以在不同的目录工作,降低了发生冲突的几率 目录结构更清晰,容易理解 而主要的缺点就是需要修改服务器设置,将网站根目录指向 WebRoot 目录。而有些虚拟主机不允许这样做,或者需要联系服务器管理员,比较麻烦。

对于这种目录结构,放置在 WebRoot 中的 index.php 入口文件应该明确调用 import() 将 WebLibs 目录添加到类定义搜索路径中。否则 load_class() 会找不到需要的文件。

<?php
require('../WebLibs/FLEA/FLEA.php');
import('../WebLibs/YORK/');
....
run();
?>对于虚拟主机用户,可以将 WebLibs 目录移动到 WebRoot 目录中。形成如下的目录结构:


上图中,所有文件都保存在应用程序的根目录 cdhlss 中,而代码文件保存在 libs 子目录中。其中 libs/APP 保存应用程序的代码。

相应的 index.php 需要修改为:

<?php
require('libs/FLEA/FLEA.php');
import('libs/APP/');
....
run();
?>在实际开发中,由于 FleaPHP 并没有强制要求命名规范和目录结构。所以开发者可以继续沿用自己熟悉的方式来开发应用程序。

查看(24) 评论(0) 收藏 推荐
FleaPHP 开发指南 - 3. 应用程序入口
2007-02-27 20:16:41

与许多开发框架一样,FleaPHP 通常也使用一个入口文件来启动框架,并运行应用程序代码。虽然 FleaPHP 并不要求应用程序必须使用单一的入口文件,不过在本系列文章中,我大部分时间都使用单一入口文件。


--------------------------------------------------------------------------------

 

单一入口应用程序
在 FleaPHP 应用程序使用 MVC 模式时,应用程序的所有功能都通过一个单一的文件来调用。这种通过单一文件来执行所有功能的应用程序,称为单一入口应用程序。有关单一入口应用程序的一些信息,可以参考 ChinaUnix 上的一篇帖子。

许多著名的 PHP 应用程序都是单一入口,例如 Drupal、WordPress、XOOPS、Mambo 等。当然也有 phpMyAdmin 这样的非单一入口应用程序。


--------------------------------------------------------------------------------

 

创建入口文件
现在,我们来创建一个最简单的入口文件。打开文本编辑器,创建 htdocs\index.php 文件,内容如下:

<?php
require('FLEA/FLEA.php');
run();
?>现在启动浏览器,输入地址:http://localhost/index.php,应该就可以看到如下的画面:


这个画面显示了一个错误信息,但是也表明 index.php 中的两行代码已经成功启动了 FleaPHP 框架。


--------------------------------------------------------------------------------

 

实现我们的第一个控制器
在 FleaPHP 应用程序中,应用程序包含多个控制器。每一个控制器又提供一组控制器动作(后文及本系列文章中都简称为“动作”)。每一个浏览器发送给 FleaPHP 应用程序的请求,都是由一个动作来处理的。将一组相关的动作集中到一起,就形成了一个控制器。

现在我们来实现第一个控制器:

创建 htdocs\APP\Controller 目录,并创建文件 htdocs\APP\Controller\Default.php (注意严格匹配目录名和文件名的大小写),内容如下:

<?php
class Controller_Default
{
    function actionIndex() {
        echo "My first controller.";
    }
}
?>同时修改 index.php 入口文件,内容改为:

<?php
require('FLEA/FLEA.php');
import(dirname(__FILE__) . '/APP');
run();
?>现在切换到浏览器,点击“刷新”按钮,可以看到 Default.php 文件中的 actionIndex 方法正确执行了。


 从刚刚这个例子可以看到,每一个控制器实际上就是一个类,而一个动作则是该类的一个方法。


--------------------------------------------------------------------------------

 

添加更多的动作
现在我们为这个控制器添加更多的 Action 方法:

<?php
class Controller_Default
{
    function actionIndex() {
        echo "My first controller.";
    }

    function actionSay() {
        echo "Oh, FleaPHP great!";
    }
}
?>切换到浏览器,将浏览地址从 http://localhost/index.php 改为 http://localhost/index.php?action=say 并按回车键。可以看到输出内容改变了。


 由此可见,action 参数的值决定了要调用控制器中的哪一个动作方法。在上面的例子中,action=say 时,调用的动作方法为 actionSay。因为 FleaPHP 默认要求每一个动作方法必须加上前缀 action。如果不提供 action 参数,则名为 index 的动作方法 actionIndex() 会被调用。


--------------------------------------------------------------------------------

 

实现更多的控制器
创建新文件 htdocs\APP\Controller\Book.php,并输入内容:

<?php
class Controller_Book
{
    function actionIndex() {
        echo "Book controller default action.";
    }

    function actionSayTitle() {
        echo h("<< Boost up with FleaPHP >>");
    }
}
?>现在切换到浏览器,输入地址 http://localhost/index.php?controller=Book&action=sayTitle,并按回车键。可以看到我们成功的调用了另一个控制器的动作方法。


 与使用 action 参数指定要调用的动作类似,用 controller 参数可以指定要调用的控制器。而此时 action 参数指定的就是该控制器的动作。

查看(28) 评论(1) 收藏 推荐
FleaPHP 开发指南 - 2. FleaPHP 中的 MVC 模式
2007-02-27 13:02:27

理解 FleaPHP 中,MVC 模式是如何实现的,以及其特点,可以帮助你更好的运用 FleaPHP。


--------------------------------------------------------------------------------

 

什么叫做设计模式?
简单来说,设计模式(Pattern)就是解决某一类问题的特定方法。由于这种特定方法在解决同类问题时具有通用性,所以我们就可以一次又一次的利用已有的经验。具体到程序编写上,就是我们可以用类似的程序结构和代码解决同类型的问题。有关设计模式的详细内容,可以阅读经典著作《设计模式》,这里我就不班门弄斧了。

MVC 实际上是一系列略有不同的模式。FleaPHP 采用的是Passive(被动)MVC 模式。

在 Passive MVC 模式中,Model(模型)完全不知道自己身处于 MVC 结构之中。换句话说,Model 就是一个普通的对象,与 MVC 模式里面的其他组成部分完全没有关联。具体而言,MVC 模式涉及到下列三类对象:

M 代表 Model,即模型,用于封装与业务逻辑有关的代码和数据。例如对订单的各种计算。 V 代表 View,即视图,用于呈现内容给用户(也就是将程序运行的结果返回给浏览器显示)。例如商品列表页面、后台登录页面。 C 代表 Controller,即控制器,用于接收用户输入(通过浏览器发起的请求),然后调用模型(Model)对输入数据进行处理并获得处理结果。最后将结果传递到视图(View),从而让用户能够看到自己操作的结果。例如用户点击删除文章按钮后,控制器调用操作文章的模型,删除掉指定文章,最后通过视图显示成功删除文章的提示信息。经过这样简单的分离,我们就把应用程序操作数据的代码(绝大部分 Web 应用程序都是对数据进行操作)和处理用户输入输出的代码分离开来了。

这种分离有许多好处:

清晰的将应用程序分隔为独立的部分; 业务逻辑代码能够很方便的在多处重复使用; 方便开发人员分工协作; 如果需要,可以方便开发人员对应用程序各个部分的代码进行测试。如果你上面的文字让你觉得很无聊或者不够严谨,那么说明你已经很熟悉 MVC 模式了。如果你看到上面的文字感到无所适从,那说明你还需要多阅读一些面向对象相关的书籍和文档。


--------------------------------------------------------------------------------

 

应用程序执行流程
下面的插图描述了基于 FleaPHP 应用程序的执行流程。


index.php 是应用程序的入口文件,负责定义一些应用程序必须的常量,并载入 FleaPHP 框架,然后执行 run() 函数; 过滤器链完成 HTTP 请求数据解析、MagicQuotes 处理等工作; 应用程序控制根据 HTTP 请求,调用领域逻辑、表数据入口、组件等,并将处理结果传送到视图/模板; 视图/模板根据应用程序控制器提供的数据生成输出内容并传送到浏览器。在 FleaPHP 中,index.php 里面的 run() 在调用过滤器链后,会运行一个调度器。该调度器根据 HTTP 请求参数决定要调用的应用程序控制器。例如 index.php?controller=blog&action=list 这个请求表示要调用名为 blog 的应用程序控制器的 list 动作。然后调度器会调用这个控制器的动作。


在 FleaPHP 应用程序中,控制器实现为一个类,控制器动作就是该类的一个方法。

在控制器(MVC 模式中的 Controller)方法中,通过调用领域逻辑代码(MVC 模式中的 Model)来处理 HTTP 请求提交的数据并获得结果。然后再将结果传递给视图(MVC 模式中的 View)。视图根据控制器方法提供的参数从模板文件构造最终的页面内容,并返回给浏览器。

查看(139) 评论(2) 收藏 推荐
FleaPHP 开发指南 - 1. 开始前的准备工作
2007-02-27 13:01:29

为了避免各种不同开发环境配置对学习 FleaPHP 造成的干扰,因此建议你按照本文配置一个专门用于学习 FleaPHP 的开发环境。

步骤:

首先 下载 APM Express 5,并解压缩到硬盘(默认会解压缩到 D:\APMXE5 目录)。 然后下载FleaPHP runtime 库(UTF8版本),解压缩到 D:\APMXE5\htdocs 目录中。解压缩完成后,htdocs 目录中应该有一个名为 FLEA 的子目录。 最后,启动 APMXE5,并从任务栏系统托盘区的 APM Express 图标上选择“Start”菜单,运行 Apache 和 MySQL。有关 APM Express 的详细信息,请参考Web 开发工具箱之 Apache PHP MySQL 绿色套装版。

 注意:在开发指南中,如果没有特别说明,htdocs 均指存放 PHP 脚本文件的目录。当你使用 APMXE5,并且将其解压缩到 D:\APMXE5 目录时,则 htdocs 目录等同于 D:\APMXE5\htdocs 目录。


只有注册用户登录后才能发表评论。
网站导航: