用户名 密码 记住我 还未注册?

MediaWiki - 模块开发

[首页]

模块开发

Wikipedia,自由的百科全书

首页 | 最近更改 | 编辑本页 | 修订历史 | 切换到MediaWiki模式

可打印版 | 免责声明 | Privacy policy

目录

xoops_version.php

xoops_version.php是XOOPS模块的基本要素,XOOPS系统依据/modules文件夹中的每个子文件夹是否包含xoops_version.php文件来判断该文件夹是否是XOOPS模块。

本例的文件夹结构如下:

/modules/moddevversion
	/images
	/logo.png
	/xoops_version.php

这个子文件夹中包含xoops_version.php,内容如下所示:

/modules/moddevversion/xoops_version.php
<?php
$modversion['name'] = "模块开发 - xoops_version.php";
$modversion['version'] = 0.01;
$modversion['description'] = "演示xoops_version.php的基本要素";
$modversion['author'] = <<<AUTHOR
胡争辉 QQ: 443089607 QQMail: [email protected] GTalk: huzhengh
GMail: [email protected] Skype: huzhenghui"
AUTHOR;
$modversion['credits'] = "";
$modversion['license'] = "版权所有";
$modversion['image'] = "images/logo.png";
$modversion['dirname'] = "moddevversion";
?>

在访问“系统管理”的“模块管理”页面时,将看到出现一个未安装模块,如图 1-1 未安装模块所示。

图1-1:未安装模块
Enlarge
图1-1:未安装模块

虽然这个模块仅有一个xoops_version.php文件,但也能被XOOPS系统识别,能够查看模块信息、安装、更新、卸载该模块。单击查看模块信息按钮image:image002-mokuai.png ,将弹出查看模块信息窗口,如图1-2模块信息所示。

图1-2模块信息
Enlarge
图1-2模块信息


单击安装按钮image:image004-mokuai.png ,出现如图1-3点击按钮安装此模块所示确认界面。

图1-3点击按钮安装此模块
Enlarge
图1-3点击按钮安装此模块

单击“安装”按钮后,XOOPS系统将安装该模块,并显示安装过程,如图1-3模块安装过程所示。

图1-4模块安装过程
Enlarge
图1-4模块安装过程

单击“回到模块管理页面”链接,将看到该模块已被安装在系统中,如图1-5模块被成功安装所示。

图1-5模块被成功安装
Enlarge
图1-5模块被成功安装

如果需要卸载该模块,则首先需要停止使用该模块,取消该模块的“激活”复选框,然后单击“提交”按钮,如图1-6确认停止使用所示。

图1-6确认停止使用
Enlarge
图1-6确认停止使用


单击“提交”按钮,将解除该模块的启动状态,并显示相应的提示信息,如图1-7解除启动状态所示。

图1-7解除启动状态
Enlarge
图1-7解除启动状态


单击“回到模块管理页面”链接,可以看到模块已停用,如图1-8模块已停用所示。

图1-8模块已停用
Enlarge
图1-8模块已停用


模块被停用后,可以看到在操作列中新出现了卸载按钮image:image011-mokuai.png ,单击卸载按钮,出现如图1-9确认卸载信息对话框。

图1-9确认卸载信息
Enlarge
图1-9确认卸载信息

单击“是”按钮即可卸载该模块,并出现卸载成功信息,如图1-10卸载成功所示。

图1-10卸载成功
Enlarge
图1-10卸载成功


图1-10卸载成功 单击“回到模块管理页面”链接,又将回到如图1-1未安装模块状态。

下面详细讲解本例中xoops_version.php文件各行代码的含义。

<?php
$modversion['name'] = "模块开发 - xoops_version.php";
//这行代码用于声明模块的名称。
$modversion['version'] = 0.01;
//这行代码用于声明模块的版本,XOOPS中模块的版本采用十进制浮点数表示。
说明:XOOPS模块的版本号格式与PHP标准的版本号格式不同,PHP标准的版本号请参考http://www.php.net/manual/zh/function.version-compare.php

$modversion['description'] = "演示xoops_version.php的基本要素";
//这行代码是模块的描述信息。
$modversion['author'] = <<<AUTHOR
胡争辉 QQ: 443089607 QQMail: [email protected] GTalk: huzhengh
GMail: [email protected] Skype: huzhenghui"
AUTHOR;
//这几行代码是模块的作者信息。
说明:模块的作者信息不支持HTML标记。

$modversion['credits'] = "";
//这行代码是模块的相关贡献人员信息。
$modversion['license'] = "版权所有";
//这行代码是模块的版权说明。
$modversion['image'] = "images/logo.png";
//这行代码是模块的图标路径,其中路径是相对于模块目录的路径,在本例中,模块目录的路径为/modules/moddevversion/,图标的相对路径为images/logo.png,图标相对于XOOPS系统的路径即是/modules/moddevversion/images/logo.png。
注意:XOOPS系统的部分后台功能会判断是否设置了图标,因此应保证设置该项,并且存在该图片。

$modversion['dirname'] = "moddevversion";
//这行代码是模块的目录名,在本例中,模块目录的路径为/modules/moddevversion/,所以目录名就是moddevversion。

?>

模块普通页面

网站通过页面与访问者交互,XOOPS系统支持两种页面--普通页面和管理页面,在XOOPS管理区,管理员可以为每个模块的普通页面和管理页面分别设置权限。如果设置显示系统导航区块,在系统导航区块中,还会显示在xoops_version.php文件中定义的子菜单。接下来,本例讲解普通页面的制作。

本例的文件夹结构如下:

/modules/moddevpage
	/images
	/logo.png
	/index.php
	/subpage1.php
	/subpage2.php
	/xoops_version.php

其中xoops_version.php的内容如下:

/modules/moddevpage/xoops_version.php
<?php
$modversion['name'] = "模块开发 - 模块普通页面";
$modversion['version'] = 0.01;
$modversion['description'] = "演示普通页面的制作";
$modversion['author'] = <<<AUTHOR
胡争辉 QQ: 443089607 QQMail: [email protected] GTalk: huzhengh
GMail: [email protected] Skype: huzhenghui"
AUTHOR;
$modversion['credits'] = "";
$modversion['license'] = "版权所有";
$modversion['image'] = "images/logo.png";
$modversion['dirname'] = "moddevpage";
$modversion["hasMain"] = 1;
$modversion["sub"][0]["name"] = "子页面 1";
$modversion["sub"][0]["url"] = "subpage1.php";
$modversion["sub"][1]["name"] = "子页面 2";
$modversion["sub"][1]["url"] = "subpage2.php";
?>

在这个文件中增加了hasMain参数。

$modversion["hasMain"] = 1;

这个参数代表该模块包括普通页面,因此在安装该模块后,系统导航区块中会显示相应的菜单项,如图1-11导航菜单中的菜单项所示。

图1-11导航菜单中的菜单项
Enlarge
图1-11导航菜单中的菜单项

同时在管理区的群组管理中,可以为每个群组分别设置是否能访问该模块。如1-12模块使用权限所示。

图1-12模块使用权限
Enlarge
图1-12模块使用权限

为了支持XOOPS系统管理模块使用权限,需要在页面中包含/mainfile.php这个文件,例如本例中的index.php文件的内容如下。

/modules/moddevpage/index.php
<?php
require_once dirname(__FILE__)."/../../mainfile.php";
include XOOPS_ROOT_PATH."/header.php";
?>
Index
<?php
include XOOPS_ROOT_PATH."/footer.php";
?>

mainfile.php文件是模块普通页面必要的包含文件,后面所包含的header.php和footer.php用于显示页面,包括显示区块等相关功能。如果普通页面不需要借助XOOPS系统来处理页面显示内容,那么只需要包含mainfile.php,不需要包含header.php和footer.php,在header.php和footer.php中间的内容将显示为页面的主体部分,如图1-13模块普通页面所示。

图1-13模块普通页面
Enlarge
图1-13模块普通页面

XOOPS系统将自动处理页面的页眉、页脚以及区块,并把header.php和footer.php中间输出的内容自动组合在页面的主体部分。

在图1-13模块普通页面中,"模块开发 -> 模块普通页面"的下面出现了两个缩进的菜单项“子页面1”和“子页面 2”,这两个菜单项是XOOPS系统支持的子菜单功能,定义在xoops_version.php文件中。

<?php
$modversion["sub"][0]["name"] = "子页面 1";
$modversion["sub"][0]["url"] = "subpage1.php";
$modversion["sub"][1]["name"] = "子页面 2";
$modversion["sub"][1]["url"] = "subpage2.php";
?>

键值“sub”代表子菜单,下面的每一项都代表一个菜单项,菜单项的索引从0开始,每个菜单项包括两个键值“name”和“url”,其中“name”的值为菜单项显示的文字,“url”的值为菜单项的地址,其中地址是相对于模块目录的地址。

菜单项页面的代码格式与index.php相同,例如“子页面 1”的代码为。

/modules/moddevpage/subpage1.php
<?php
require_once dirname(__FILE__)."/../../mainfile.php";
include XOOPS_ROOT_PATH."/header.php";
?>
Sub Page 1
<?php
include XOOPS_ROOT_PATH."/footer.php";
?>

输出效果与图1-13模块普通页面类似,也会显示本模块的子菜单项。如图1-14子页面1所示。

图1-14子页面1
Enlarge
图1-14子页面1

模块管理页面

除了普通页面,XOOPS系统还支持模块管理页面,模块管理页面与模块普通页面类似,也支持子菜单。下面本例讲解管理页面的制作。

本例的文件夹结构如下:

/modules/moddevadmin
	/admin
	/admin1.php
	/admin2.php
	/index.php
	/menu.php
	/images
	/xoops_version.php

其中xoops_version.php的内容如下:

/modules/moddevadmin/xoops_version.php
<?php
$modversion['name'] = "模块开发 - 模块管理页面";
$modversion['version'] = 0.01;
$modversion['description'] = "演示管理页面的制作";
$modversion['author'] = <<<AUTHOR
胡争辉 QQ: 443089607 QQMail: [email protected] GTalk: huzhengh
GMail: [email protected] Skype: huzhenghui"
AUTHOR;
$modversion['credits'] = "";
$modversion['license'] = "版权所有";
$modversion['image'] = "images/logo.png";
$modversion['dirname'] = "moddevadmin";
$modversion["hasAdmin"] = 1;
$modversion["adminindex"] = "admin/index.php";
$modversion["adminmenu"] = "admin/menu.php";
?>

其中hasAdmin参数表示该模块包括管理页面。

$modversion["hasAdmin"] = 1;

adminindex参数表示该模块管理页面的首页地址,该地址为相对于模块根目录的地址。

$modversion["adminindex"] = "admin/index.php";

安装该模块后,在管理区的左侧会显示该模块的图标,表示该模块具有管理页面,如图1-15模块管理图标所示。

图1-15模块管理图标
Enlarge
图1-15模块管理图标

在管理区的群组管理中,可以为每个群组分别设置是否能管理该模块。如图1-16模块管理权限所示。

图1-16模块管理权限
Enlarge
图1-16模块管理权限

为了支持XOOPS系统管理模块管理权限,需要在页面中包含/include/cp_header.php这个文件,例如本例中的admin/index.php文件的内容如下。

/modules/moddevadmin/admin/index.php
<?php
require_once dirname(__FILE__)."/../../../include/cp_header.php";
xoops_cp_header();
?>
Admin Index
<?php
xoops_cp_footer();
?>

/include/cp_header.php是模块管理页面必要的包含文件,提供后面所调用的xoops_cp_header()和xoops_cp_footer()等函数。xoops_cp_header()和xoops_cp_footer()用于显示管理区页面,包括页眉、页脚、模块菜单等相关功能。如果管理页面不需要显示内容,那么只需要包含/include/cp_header.php,不需要调用xoops_cp_header()和xoops_cp_footer()。在xoops_cp_header()和xoops_cp_footer()中间的内容将显示为管理页面的主体部分,如图1-17模块管理首页所示。

图1-17模块管理首页
Enlarge
图1-17模块管理首页

XOOPS系统将自动处理管理区页面的页眉、页脚以及模块菜单,并把xoops_cp_header()和xoops_cp_footer()中间输出的内容自动组合在管理区页面的主体部分。

当鼠标移动到模块图标上的时候,页面将自动出现一个该模块管理区的子菜单,如图1-18模块管理子菜单所示。

图1-18模块管理子菜单
Enlarge
图1-18模块管理子菜单

其中包括了三个菜单项“模块管理页面 -> 首页”、“模块管理页面 -> 管理页面 1”和“模块管理页面 -> 管理页面 2”,这三个菜单项是XOOPS系统支持的管理区子菜单功能。为了显示管理区子菜单,首先需要在xoops_version.php文件中定义管理区子菜单的描述文件。

$modversion["adminmenu"] = "admin/menu.php";

该文件的内容如下。

/modules/moddevadmin/admin/menu.php
<?php
$adminmenu[0]['title'] = "模块管理页面 - 首页";
$adminmenu[0]['link'] = "admin/index.php";
$adminmenu[1]['title'] = "模块管理页面 - 管理页面 1";
$adminmenu[1]['link'] = "admin/admin1.php";
$adminmenu[2]['title'] = "模块管理页面 - 管理页面 2";
$adminmenu[2]['link'] = "admin/admin2.php";
?>

变量$adminmenu代表管理区子菜单,下面的每一项都代表一个菜单项,菜单项的索引从0开始,每个菜单项包括两个键值“title”和“link”,其中“title”的值为菜单项显示的文字,“link”的值为菜单项的地址,其中地址是相对于模块目录的地址。

管理区菜单项页面的代码格式与admin/index.php相同,例如“模块管理页面-管理页面1”的代码为。

/modules/moddevadmin/admin/admin1.php
<?php
require_once dirname(__FILE__)."/../../../include/cp_header.php";
xoops_cp_header();
?>
Admin 1
<?php
xoops_cp_footer();
?>

输出效果与图1-17模块管理首页类似,当鼠标停留在模块图标上方时,也会显示模块的管理菜单,如图1-19模块管理页面1所示。

图1-19模块管理页面1
Enlarge
图1-19模块管理页面1

数据表

模块除了包含页面,通常还会包含保存在数据库中的数据表,在XOOPS系统中,为模块的数据库访问提供方便的封装,安装模块时将自动创建指定的数据表以及记录,在卸载模块时将自动删除指定的数据表。在安装的过程中,XOOPS为数据表自动添加表前缀。为了便于访问数据表,XOOPS还提供了相应的类。接下来本例将讲解数据表的安装、卸载以及访问。

本例的文件夹结构如下:

/modules/moddevsql
	/images
	/logo.png
	/sql
	/mysql.sql
	/index.php
	/xoops_version.php

其中xoops_version.php的内容如下:

/modules/moddevsql/xoops_version.php
<?php
$modversion['name'] = "模块开发 - 数据库";
$modversion['version'] = 0.01;
$modversion['description'] = "演示数据库的使用";
$modversion['author'] = <<<AUTHOR
胡争辉 QQ: 443089607 QQMail: [email protected] GTalk: huzhengh
GMail: [email protected] Skype: huzhenghui"
AUTHOR;
$modversion['credits'] = "";
$modversion['license'] = "版权所有";
$modversion['image'] = "images/logo.png";
$modversion['dirname'] = "moddevsql";
$modversion["hasMain"] = 1;
$modversion["sqlfile"]["mysql"] = "sql/mysql.sql";
$modversion["tables"][] = "moddevsql_contact";
?>

其中sqlfile参数表示该模块包括创建数据表的脚本,键值mysql表示当前的XOOPS系统采用mysql数据库时所使用的创建数据表脚本的路径,该路径为相对于模块根目录的路径。

$modversion["sqlfile"]["mysql"] = "sql/mysql.sql";

本例中的创建数据表脚本的内容如下。

/modules/moddevsql/sql/mysql.sql
CREATE TABLE `moddevsql_contact` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `firstname` text NOT NULL,
  `lastname` text NOT NULL,
  `QQ` text NOT NULL,
  `QQMail` text NOT NULL,
  `GTalk` text NOT NULL,
  `GMail` text NOT NULL,
  `Skype` text NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;
INSERT INTO `moddevsql_contact` (`id`, `firstname`, `lastname`, `QQ`, `QQMail`, `GTalk`, `GMail`, `Skype`) VALUES (1, '争辉', '胡', '443089607', '[email protected]', 'huzhengh', '[email protected]', 'huzhenghui');

安装该模块时,XOOPS系统会自动解析该脚本,并为表名增加相应的前缀,从安装过程中可以看到创建的表以及插入的数据,如图1-20安装数据库模块所示。

图1-20安装数据库模块
Enlarge
图1-20安装数据库模块

在安装带数据库的模块时,首先会查找数据库安装脚本。

SQL file found at D:/wamp/www/xoopstutorial/modules/moddevsql/sql/mysql.sql.

然后解析脚本并执行,如果脚本中包含创建表的脚本,XOOPS系统将自动为建表脚本的表名加上前缀,然后创建数据库,如果数据表创建成功,则输出相应的信息。

Table xoops_moddevsql_contact created.

如果脚本中包含向数据表插入数据的脚本,XOOPS系统将自动为插入脚本世纪末表名加上前缀,然后插入数据,如果插入数据成功,则输出相应的信息。

Data inserted to table xoops_moddevsql_contact.

模块成功安装后,模块中的程序就可以访问该数据表了,本例中的index.php文件的功能就是访问moddevsql_contact数据表,代码如下。

/modules/moddevsql/index.php
<?php
require_once dirname(__FILE__)."/../../mainfile.php";
/* @var $xoopsDB XoopsMySQLDatabaseProxy */
$sql = "SELECT * FROM ".$xoopsDB->prefix("moddevsql_contact");
$result = $xoopsDB->query($sql);
include XOOPS_ROOT_PATH."/header.php";
?>
<table>
    <tr>
        <th>
            id
        </th>
        <th>
            first name
        </th>
        <th>
            last name
        </th>
        <th>
            QQ
        </th>
        <th>
            QQ Mail
        </th>
        <th>
            Google Talk
        </th>
        <th>
            Google Mail
        </th>
        <th>
            Skype
        </th>
    </tr>
<?php
while (false !== ($data = $xoopsDB->fetchArray($result))) {
?>
    <tr>
        <td>
            <?php echo htmlspecialchars($data["id"]); ?>
        </td>
        <td>
            <?php echo htmlspecialchars($data["firstname"]); ?>
        </td>
        <td>
            <?php echo htmlspecialchars($data["lastname"]); ?>
        </td>
        <td>
            <?php echo htmlspecialchars($data["QQ"]); ?>
        </td>
        <td>
            <a href="mailto:<?php echo htmlspecialchars($data["QQMail"]); ?>">
                <?php echo htmlspecialchars($data["QQMail"]); ?>
            </a>
        </td>
        <td>
            <?php echo htmlspecialchars($data["GTalk"]); ?>
        </td>
        <td>
            <a href="mailto:<?php echo htmlspecialchars($data["GMail"]); ?>">
                <?php echo htmlspecialchars($data["GMail"]); ?>
            </a>
        </td>
        <td>
            <?php echo htmlspecialchars($data["Skype"]); ?>
        </td>
    </tr>
<?php
}
?>
</table>
<?php
include XOOPS_ROOT_PATH."/footer.php";
?>

为了获取数据,首先要构造SQL,代码如下。

$sql = "SELECT * FROM ".$xoopsDB->prefix("moddevsql_contact");

这里用到了$xoopsDB类的prefix函数。$xoopsDB是XOOPS系统提供的数据库访问类,其中封装了与数据库交互的基本函数。由于XOOPS系统自动为表增加前缀,因此在模块中使用表名时,需要调用$xoopsDB类的prefix函数为表增加前缀,prefix函数的定义如下。

/class/database/database.php
function prefix($tablename='') {}

构造了SQL之后,就可以查询数据库并获得结果集。

$result = $xoopsDB->query($sql);

这里用到了$xoopsDB类的query函数,该函数用于在数据库执行查询,query函数的定义如下。

/class/database/mysqldatabase.php
function query($sql, $limit=0, $start=0) {}

query函数是对mysql_query函数的简单封装。获取了结果集后,就可以循环访问该结果集获取数据行了。

while (false !== ($data = $xoopsDB->fetchArray($result))) {

这里用到了$xoopsDB类的fetchArray函数,该函数用于获取结果集中的数据行。fetchArray函数的定义如下。

/class/database/mysqldatabase.php
function fetchArray($result) {}

fetchArray函数是对mysql_fetch_assoc函数的简单封装,获取的数据也是一个关联数组。该页面的运行效果如图1-21显示查询数据库的结果所示。

图1-21显示查询数据库的结果
Enlarge
图1-21显示查询数据库的结果

由于XOOPS系统中既可以安装模块,还可以卸载模块,所以为安装模块的过程设置了脚本之外,还需要为卸载模块的过程设置所需要删除的数据表。相关信息也是定义在xoops_version.php文件中。

$modversion["tables"][] = "moddevsql_contact";

其中键值tables代表在卸载时需要删除的数据表,该键值下面的每一项都是一个在卸载时需要删除的数据表的名称,在卸载过程中,XOOPS系统会自动为表名增加相应的前缀。并且会输出相应的信息,如图1-22卸载数据库模块所示。

图1-22卸载数据库模块
Enlarge
图1-22卸载数据库模块

如果在xoops_version.php设置了tables键值,则XOOPS系统在卸载模块时会执行删除数据表的过程,并输出相应的信息。

Deleting module tables...

删除每个表也会输出相应的信息。

Table xoops_moddevsql_contact dropped.

数据对象

XOOPS系统不仅提供了数据库访问的封装类变量,还提供面向对象的访问方式,可以将数据表中的一条记录封装成一个对象,下面本例将讲解面向对象的访问方式。 本例的文件夹结构如下:

/modules/moddevclass
	/class
	/contact.php
	/images
	/logo.png
	/sql
	/mysql.sql
	/index.php
	/xoops_version.php

其中xoops_version.php的内容如下:

/modules/moddevclass/xoops_version.php
<?php
$modversion['name'] = "模块开发 - 数据类";
$modversion['version'] = 0.01;
$modversion['description'] = "演示数据类的使用";
$modversion['author'] = <<<AUTHOR
胡争辉 QQ: 443089607 QQMail: [email protected] GTalk: huzhengh
GMail: [email protected] Skype: huzhenghui"
AUTHOR;
$modversion['credits'] = "";
$modversion['license'] = "版权所有";
$modversion['image'] = "images/logo.png";
$modversion['dirname'] = "moddevclass";
$modversion["hasMain"] = 1;
$modversion["sqlfile"]["mysql"] = "sql/mysql.sql";
$modversion["tables"][] = "moddevclass_contact";
?>

为便于对照学习,数据结构与上例类似。mysql.sql的内容如下:

/modules/moddevclass/sql/mysql.sql
CREATE TABLE `moddevclass_contact` (
/* 详见源文件 */
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;
INSERT INTO `moddevclass_contact` (`id`, `firstname`, `lastname`, `QQ`, `QQMail`, `GTalk`, `GMail`, `Skype`) VALUES (1, '争辉', '胡', '443089607', '[email protected]', 'huzhengh', '[email protected]', 'huzhenghui');

本例中使用数据对象封装访问数据的过程。数据访问对象的源代码如下:

/modules/moddevclass/class/contact.php
<?php
class ModdevclassContact extends XoopsObject {
    function ModdevclassContact() {
        $this->initVar("id", XOBJ_DTYPE_INT);
        $this->initVar("firstname", XOBJ_DTYPE_TXTBOX);
        $this->initVar("lastname", XOBJ_DTYPE_TXTBOX);
        $this->initVar("QQ", XOBJ_DTYPE_TXTBOX);
        $this->initVar("QQMail", XOBJ_DTYPE_EMAIL);
        $this->initVar("GTalk", XOBJ_DTYPE_TXTBOX);
        $this->initVar("GMail", XOBJ_DTYPE_EMAIL);
        $this->initVar("Skype", XOBJ_DTYPE_TXTBOX);
        return;
    }
}
class ModdevclassContactHandler extends XoopsObjectHandler {
    function getAll () {
        $ret = array();
        $sql = "SELECT * FROM ".$this->db->prefix("moddevclass_contact");
        $result = $this->db->query($sql);
        if (false === $result) {
            return $ret;
        }
        while (false !== ($row = $this->db->fetchArray($result))) {
            $contact = new ModdevclassContact();
            $contact->assignVars($row);
            $ret[$row["id"]] = $contact;
            unset($contact);
        }
        return $ret;
    }
}
?>

其中ModdevclassContact是数据对象,继承自XoopsObject。

class ModdevclassContact extends XoopsObject {}

XoopsObject是XOOPS提供的数据对象基础类,所有的数据对象都应当继承自XoopsObject。这个类是XOOPS系统的核心类。

/kernel/object.php
class XoopsObject {}

继承自XoopsObject的数据对象都需要初始化数据变量,这项工作应当在子类的构造函数中完成。对于访问数据库的数据对象来说,一般需要初始化所有的字段。本例中就初始化了所有的字段。

function ModdevclassContact() {
    $this->initVar("id", XOBJ_DTYPE_INT);
    $this->initVar("firstname", XOBJ_DTYPE_TXTBOX);
    $this->initVar("lastname", XOBJ_DTYPE_TXTBOX);
    $this->initVar("QQ", XOBJ_DTYPE_TXTBOX);
    $this->initVar("QQMail", XOBJ_DTYPE_ EMAIL);
    $this->initVar("GTalk", XOBJ_DTYPE_TXTBOX);
    $this->initVar("GMail", XOBJ_DTYPE_ EMAIL);
    $this->initVar("Skype", XOBJ_DTYPE_TXTBOX);
    return;
}

初始化数据变量需要调用initVar函数,该函数是XoopsObject类的成员,定义如下。

/kernel/object.php
function initVar($key, $data_type, $value = null, $required = false, $maxlength = null, $options = '') {}

其中$key是数据变量的名称,对于访问数据库的数据对象来说,使用字段名称;$data_type是数据变量的类型。XOOPS系统中使用常量来指示数据变量的类型,如表1-1数据变量类型所示。

表1-1数据变量类型
常量 用途
XOBJ_DTYPE_TXTBOX 1 文本,只有这个类型支持$maxlength参数
XOBJ_DTYPE_TXTAREA 2 文本,在显示时支持标记的替换
XOBJ_DTYPE_INT 3 整数
XOBJ_DTYPE_URL 4 文本, http://http://形式的链接
XOBJ_DTYPE_EMAIL 5 文本,电子邮件地址
XOBJ_DTYPE_ARRAY 6 数组
XOBJ_DTYPE_OTHER 7 其他,不进行类型检查,不进行内容修饰
XOBJ_DTYPE_SOURCE 8 文本,源代码
XOBJ_DTYPE_STIME 9 UNIX时间戳
XOBJ_DTYPE_MTIME 10 UNIX时间戳
XOBJ_DTYPE_LTIME 11 UNIX时间戳

本例中的ModdevclassContactHandler是数据访问句柄,继承自XoopsObjectHandler。

class ModdevclassContactHandler extends XoopsObjectHandler {}

XoopsObjectHandler是XOOPS系统提供的数据访问句柄基础类,所有的数据访问句柄都应当继承自XoopsObjectHandler,这个类是XOOPS系统的核心类。

/kernel/object.php
class XoopsObjectHandler {}

继承自XoopsObjectHandler的数据访问句柄类都应当按需要实现相应的数据访问函数。本例中为获取所有的数据实现了函数getAll。

function getAll () {
    $ret = array();
    $sql = "SELECT * FROM ".$this->db->prefix("moddevclass_contact");
    $result = $this->db->query($sql);
    if (false === $result) {
        return $ret;
    }
    while (false !== ($row = $this->db->fetchArray($result))) {
        $contact = new ModdevclassContact();
        $contact->assignVars($row);
        $ret[$row["id"]] = $contact;
        unset($contact);
    }
    return $ret;
}

这段程序的工作流程与上例相同,区别在于,上例直接输出数据库的结果,而本例中将数据库的结果保存在数据访问类中。

$contact->assignVars($row);

assignVars函数提供将fetchArray获取的记录值直接保存在数据访问对象的功能。这个函数在XoopsObject中定义。

/kernel/object.php
function assignVars($var_arr) {}

将所有的记录数据都转换成数据访问类并保存为数组后,getAll函数返回这个数组。相应的,页面也只需要获取对象数组并显示,不再需要直接访问数据库,index.php页面代码如下。

/modules/moddevclass/index.php
<?php
require_once dirname(__FILE__)."/../../mainfile.php";
$contacthandler = xoops_getmodulehandler("contact", "moddevclass");
/* @var $contacthandler ModdevclassContactHandler */
include XOOPS_ROOT_PATH."/header.php";
?>
<table>
    <tr>
        <!-- 详见源文件 -->
    </tr>
<?php
foreach ($contacthandler->getAll() as $contact) {
/* @var $contact ModdevclassContact */
?>
    <tr>
        <td>
            <?php echo $contact->getVar("id"); ?>
        </td>
        <td>
            <?php echo $contact->getVar("firstname"); ?>
        </td>
        <td>
            <?php echo $contact->getVar("lastname"); ?>
        </td>
        <td>
            <?php echo $contact->getVar("QQ"); ?>
        </td>
        <td>
            <a href="mailto:<?php echo $contact->getVar("QQMail"); ?>">
                <?php echo $contact->getVar("QQMail"); ?>
            </a>
        </td>
        <td>
            <?php echo $contact->getVar("GTalk"); ?>
        </td>
        <td>
            <a href="mailto:<?php echo $contact->getVar("GMail"); ?>">
                <?php echo $contact->getVar("GMail"); ?>
            </a>
        </td>
        <td>
            <?php echo $contact->getVar("Skype"); ?>
        </td>
    </tr>
<?php
}
?>
</table>
<?php
include XOOPS_ROOT_PATH."/footer.php";
?>

为了获取数据访问对象,首先需要获取数据访问句柄。

$contacthandler = xoops_getmodulehandler("contact", "moddevclass");

获取数据访问句柄时,不需要包含相应的文件,也不需要创建类实例。XOOPS系统提供了xoops_getmodulehandler用于直接获取数据访问句柄。

/include/functions.php
function &xoops_getmodulehandler($name = null, $module_dir = null, $optional = false) {}

第一个参数$name是模块中数据访问句柄的名称,该名称是模块中class文件夹的文件名,本例中数据访问句柄的文件名是contact.php,所以参数$name的值是contact。第二个参数$module_dir是模块的文件夹名称,本例中模块的文件夹是moddevclass。

注意:由于Windows文件系统不分区大小写,UNIX文件系统区分大小写,因此$name应该和文件名的大小写相同,文件名的后缀应当是小写的php;$module_dir应该和文件夹的大小写相同。

虽然PHP的类名不区分大小写,但是xoops_getmodulehandler函数对数据访问句柄的类名有额外的约定。数据访问句柄的类名包括三部分,模块名,类名和Handler,其中模块名应该仅有首字母大写,其余字母小写。类名的首字母大写。相关的代码如下。

ucfirst(strtolower($module_dir)).ucfirst($name).'Handler';

获取了数据访问句柄后,就可以访问其中定义的成员函数。

foreach ($contacthandler->getAll() as $contact) {

这个foreach循环将枚举所有的数据访问对象,每个数据访问对象的类型都是ModdevclassContact,数据访问对象可以调用getVar函数获取保存在其中的值。

<?php echo $contact->getVar("id"); ?>

getVar函数定义在XoopsObject中,用于获取由initVar初始化后的数据值。

/kernel/object.php
function getVar($key, $format = 's')  {}

其中$key参数应当是调用initVar初始化的数据变量名称。通过以上的修改,就把直接操作数据库变成了面向对象的数据访问。通过把数据访问封装成对象,不仅能独立的修改数据访问和页面展现,还能在不同的页面展现中使用相同的数据访问。页面效果如图 1 21 显示查询数据库的结果所示。

说明:使用基于XOOPS系统的Frameworks库,能够更方便的实现面向对象数据访问,因此本节仅介绍XoopsObject和XoopsObjectHandler的基本原理,在实际模块中应优先选择基于Frameworks库,而不是直接继承自XoopsObject和XoopsObjectHandler。


条件对象

XOOPS不仅能将数据库访问封装成对象,还提供将数据库的查询封装成对象。接下来本例讲解如何将查询封装成对象。

本例的文件夹结构如下:

/modules/moddevcriteria
	/class
	/contact.php
	/images
	/logo.png
	/sql
	/mysql.sql
	/index.php
	/xoops_version.php

其中xoops_version.php的内容如下:

/modules/moddevcriteria/xoops_version.php
<?php
$modversion['name'] = "模块开发 - 查询";
$modversion['version'] = 0.01;
$modversion['description'] = "演示查询对象的使用";
$modversion['author'] = <<<AUTHOR
胡争辉 QQ: 443089607 QQMail: [email protected] GTalk: huzhengh
GMail: [email protected] Skype: huzhenghui"
AUTHOR;
$modversion['credits'] = "";
$modversion['license'] = "版权所有";
$modversion['image'] = "images/logo.png";
$modversion['dirname'] = "moddevcriteria";
$modversion["hasMain"] = 1;
$modversion["sqlfile"]["mysql"] = "sql/mysql.sql";
$modversion["tables"][] = "moddevcriteria_contact";
?>

为便于对照学习,数据结构与上例类似。mysql.sql的内容如下:

/modules/moddevcriteria/sql/mysql.sql
CREATE TABLE `moddevcriteria_contact` (
  /* 详见源文件 */
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;
INSERT INTO `moddevcriteria_contact` (`id`, `firstname`, `lastname`, `QQ`, `QQMail`, `GTalk`, `GMail`, `Skype`) VALUES (1, '争辉', '胡', '443089607', '[email protected]', 'huzhengh', '[email protected]', 'huzhenghui');

本例中的数据访问句柄增加了对查询对象的支持,源代码如下:

/modules/moddevcriteria/class/contact.php
<?php
class ModdevcriteriaContact extends XoopsObject {
    function ModdevcriteriaContact() {
        /* 详见源文件 */
    }
}
class ModdevcriteriaContactHandler extends XoopsObjectHandler {
    function getAll ($criteria = null) {
        /* @var $criteria Criteria */
        $ret = array();
        if (true === isset($criteria)) {
            $sql = "SELECT * FROM ".$this->db->prefix("moddevcriteria_contact").
                " ".$criteria->renderWhere();
        } else {
            $sql = "SELECT * FROM ".$this->db->prefix("moddevcriteria_contact");
        }
        $result = $this->db->query($sql);
        if (false === $result) {
            return $ret;
        }
        while (false !== ($row = $this->db->fetchArray($result))) {
            $contact = new ModdevcriteriaContact();
            $contact->assignVars($row);
            $ret[$row["id"]] = $contact;
            unset($contact);
        }
        return $ret;
    }
}
?>

本例中的getAll函数增加了一个可选的$criteria参数,该参数用于传入一个条件对象,如果未设置该参数,则和上例相同,返回全部的数据。

function getAll ($criteria = null) {

因为设置查询条件和查询全部数据会影响SQL语句,所以引用了中间变量$sql,在查询时仅查询$sql。

$result = $this->db->query($sql);

当未传入条件对象$criteria时,$sql的取值与上例相同。

$sql = "SELECT * FROM ".$this->db->prefix("moddevcriteria_contact");

当传入了条件对象$criteria时,$sql只需要连接条件对象生成的WHERE语句即可。

           $sql = "SELECT * FROM ".$this->db->prefix("moddevcriteria_contact").
                " ".$criteria->renderWhere();

可以看出,条件对象在使用时非常简单。本例的index.php页面相应的增加了查询表单,代码如下。

/modules/moddevcriteria/index.php
<?php
require_once dirname(__FILE__)."/../../mainfile.php";
$contacthandler = xoops_getmodulehandler("contact", "moddevcriteria");
/* @var $contacthandler ModdevcriteriaContactHandler */
include XOOPS_ROOT_PATH."/header.php";
?>
<form>
    first name: <input name="firstname" />
    <input type="submit" />
</form>
<table>
    <tr>
        <!-- 详见源文件 -->
    </tr>
<?php
if (true === isset($_GET["firstname"])) {
    $myts =& MyTextSanitizer::getInstance();
    $criteria =
        new Criteria("firstname", $myts->addSlashes($_GET["firstname"]));
    $contacts = $contacthandler->getAll($criteria);
} else {
    $contacts = $contacthandler->getAll();
}
foreach ($contacts as $contact) {
/* @var $contact ModdevcriteriaContact */
?>
    <tr>
        <!-- 详见源文件 -->
    </tr>
<?php
}
?>
</table>
<?php
include XOOPS_ROOT_PATH."/footer.php";
?>

效果如图1-23查询表单所示。

图1-23查询表单
Enlarge
图1-23查询表单

与上例不同的时,为了区别全面查询和按first name查询两种不同的情况,引入了中间变量$contacts保存查询结果。

foreach ($contacts as $contact) {

页面中依据是否设置了查询条件参数选择相应的处理过程。

if (true === isset($_GET["firstname"])) {

如果没有设置查询条件,则采用和上例相同的调用方式获取全部的数据访问对象。

$contacts = $contacthandler->getAll();

如果设置了查询条件,则需要创建相应的条件对象,因为PHP依赖设置的不同,会对参数中的字符进行转义,因此先获取文本修饰对象。

$myts =& MyTextSanitizer::getInstance();

然后用文本修饰对象自动对参数转义后创建条件对象。

    $criteria =
        new Criteria("firstname", $myts->addSlashes($_GET["firstname"]));

接下来将条件对象传入getAll函数获取查询结果。

$contacts = $contacthandler->getAll($criteria);

通过上述这些修改,就实现了用条件对象查询数据,不需要在SQL语句中写WHERE子句,全部由Criteria类自动处理。

表单对象

上例中通过XOOPS系统提供的条件对象,将提交的表单信息封装成对象进行查询,在XOOPS系统中还可以进一步的将表单也封装成对象,接下来本例将讲解如何将表单封装成对象。

本例的文件夹结构如下:

/modules/moddevform
	/class
	/contact.php
	/images
	/logo.png
	/sql
	/mysql.sql
	/index.php
	/xoops_version.php

其中xoops_version.php的内容如下:

/modules/moddevform/xoops_version.php
<?php
$modversion['name'] = "模块开发 - 表单";
$modversion['version'] = 0.01;
$modversion['description'] = "演示表单对象的使用";
$modversion['author'] = <<<AUTHOR
胡争辉 QQ: 443089607 QQMail: [email protected] GTalk: huzhengh
GMail: [email protected] Skype: huzhenghui"
AUTHOR;
$modversion['credits'] = "";
$modversion['license'] = "版权所有";
$modversion['image'] = "images/logo.png";
$modversion['dirname'] = "moddevform";
$modversion["hasMain"] = 1;
$modversion["sqlfile"]["mysql"] = "sql/mysql.sql";
$modversion["tables"][] = "moddevform_contact";
?>

为便于对照学习,数据结构与上例类似。mysql.sql的内容如下:

/modules/moddevform/sql/mysql.sql
CREATE TABLE `moddevform_contact` (
  /* 详见源文件 */
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;
INSERT INTO `moddevform_contact` (`id`, `firstname`, `lastname`, `QQ`, `QQMail`, `GTalk`, `GMail`, `Skype`) VALUES (1, '争辉', '胡', '443089607', '[email protected]', 'huzhengh', '[email protected]', 'huzhenghui');

XOOPS系统中的表单对象与数据访问对象、查询对象相互独立,因此增加表单对象不会影响到数据访问句柄,数据访问句柄的功能与结构和上例类似,源代码如下:

/modules/moddevform/class/contact.php
<?php
class ModdevformContact extends XoopsObject {
    function ModdevformContact() {
        /* 详见源文件 */
    }
}
class ModdevformContactHandler extends XoopsObjectHandler {
    function getAll ($criteria = null) {
        /* @var $criteria Criteria */
        $ret = array();
        if (true === isset($criteria)) {
            $sql = "SELECT * FROM ".$this->db->prefix("moddevform_contact").
                " ".$criteria->renderWhere();
        } else {
            $sql = "SELECT * FROM ".$this->db->prefix("moddevform_contact");
        }
        $result = $this->db->query($sql);
        if (false === $result) {
            return $ret;
        }
        while (false !== ($row = $this->db->fetchArray($result))) {
            $contact = new ModdevformContact();
            $contact->assignVars($row);
            $ret[$row["id"]] = $contact;
            unset($contact);
        }
        return $ret;
    }
}
?>

在XOOPS系统中增加表单对象也只需要修改HTML的表单部分,本例的index.php页面的源代码如下:

/modules/moddevform/index.php
<?php
require_once dirname(__FILE__)."/../../mainfile.php";
$contacthandler = xoops_getmodulehandler("contact", "moddevform");
/* @var $contacthandler ModdevformContactHandler */
include XOOPS_ROOT_PATH."/header.php";
include_once XOOPS_ROOT_PATH."/class/xoopsformloader.php";
$search_form = new XoopsThemeForm("Search Contact", "search_form", "", "get");
$search_form->addElement(new XoopsFormText("first Name:", "firstname", 20, 20));
$search_form->addElement(new XoopsFormButton("", "submit", _SUBMIT, "submit"));
$search_form->display();
?>
<table>
    <!-- 详见源文件 -->
</table>
<?php
include XOOPS_ROOT_PATH."/footer.php";
?>

本例中没有在HTML中直接输出表单,而且通过表单对象输出,为了使用表单对象,需要包含相应的文件。通过按需加载,可以减轻页面的负担。

include_once XOOPS_ROOT_PATH."/class/xoopsformloader.php";

然后创建表单对象。

$search_form = new XoopsThemeForm("Search Contact", "search_form", "", "get");

XoopsThemeForm是带主题样式的表单对象,定义在themeform.php中。

/class/xoopsform/themeform.php
class XoopsThemeForm extends XoopsForm

XoopsForm是表单对象的基类,在使用时应当使用继承自XoopsForm的子类。XoopsThemeForm的构造函数继承自XoopsForm。

/class/xoopsform/form.php
function XoopsForm($title, $name, $action, $method="post", $addtoken=false) {}

参数$title表示表单的标题,$name表示表单的名称,$action表示表单的提交目标,$method表示提交的方法,一般是get或post,$addtoken表示增加安全标志避免被攻击。在创建表单对象之后,可以调用addElement方法增加表单元素。

$search_form->addElement(new XoopsFormText("first Name:", "firstname", 20, 20));

addElement方法用于向XoopsForm对象增加表单元素,是XoopsForm类的成员函数。

/class/xoopsform/form.php
function addElement(&$formElement, $required = false) {}

参数$formElement表示表单元素,$required表示该元素是否是必选项,在客户端会生成相应的JavaScript脚本验证表单。XoopsFormText是文本框对象,定义在formtext.php文件中。

/class/xoopsform/formtext.php
class XoopsFormText extends XoopsFormElement {}

XoopsFormText继承自XoopsFormElement,调用addElement函数向XoopsForm对象增加的表单元素都应该继承自XoopsFormElement。XoopsFormText的构造函数如下。

/class/xoopsform/formtext.php
function XoopsFormText($caption, $name, $size, $maxlength, $value="") {}

其中$caption参数是文本框元素对应的文本标签,$name是文本框的名称,$size是文本框的显示宽度,$maxlength是文本框中文本的最大宽度,$value是文本框的初始值。在增加了文本框后,接下来增加提交按钮。

$search_form->addElement(new XoopsFormButton("", "submit", _SUBMIT, "submit"));

XoopsFormButton是按钮对象,定义在formbutton.php文件中。

/class/xoopsform/formbutton.php
class XoopsFormButton extends XoopsFormElement {}

XoopsFormButton也是继承自XoopsFormElement,构造函数如下。

/class/xoopsform/formbutton.php
function XoopsFormButton($caption, $name, $value="", $type="button") {}

其中$caption和$name参数的含义与XoopsFormText相同,$value代表按钮的显示文字,$type是按钮的类型,XoopsFormButton支持三种按钮类型,button表示普通按钮,submit表示提交按钮,reset表示重置按钮,本例中创建了一个提交按钮。增加所有的表单元素后,调用display函数显示表单。

$search_form->display();

其中display函数定义在XoopsForm中。

/class/xoopsform/form.php
function display(){}

表单的显示效果如图1-24表单对象的效果所示。

图1-24表单对象的效果
Enlarge
图1-24表单对象的效果

该表单对象生成的HTML代码如下。

<form name='search_form' id='search_form' action='' method='get'
	onsubmit='return xoopsFormValidate_search_form();'>
<table width='100%' class='outer' cellspacing='1'>
	<tr>
		<th colspan='2'>Search Contact</th>
	</tr>
	<tr valign='top' align='left'>
		<td class='head'>
		<div class='xoops-form-element-caption'><span
			class='caption-text'>first Name:</span><span class='caption-marker'>*</span></div>
		</td>
		<td class='even'><input type='text' name='firstname'
			id='firstname' size='20' maxlength='20' value='' /></td>
	</tr>
	<tr valign='top' align='left'>
		<td class='head'></td>
		<td class='even'><input type='submit' class='formButton'
			name='submit' id='submit' value='提交' /></td>
	</tr>
</table>
</form>
<!-- Start Form Validation JavaScript //-->
<script type='text/javascript'>
<!--//
function xoopsFormValidate_search_form() { myform = window.document.search_form; return true;
}
//--></script>
<!-- End Form Vaidation JavaScript //-->

通过对比可以理解XoopsThemeForm类的显示方式,继承自XoopsForm的类有各自的显示方式。

模板

上例中通过XOOPS系统提供的表单对象,将表单封装成对象后输出,可以把表单的数据和相应的HTML标记展现分离,在XOOPS系统中还提供了模板机制,可以将页面的数据和页面的展现分离,接下来本例将讲解如何使用模板。本例的文件夹结构如下:

/modules/moddevtemplate
	/class
	/contact.php
	/images
	/logo.png
	/sql
	/mysql.sql
	/templates
	/moddevtemplate_index.html
	/index.php
	/xoops_version.php

其中xoops_version.php的内容如下:

/modules/moddevtemplate/xoops_version.php
<?php
$modversion['name'] = "模块开发 - 模板";
$modversion['version'] = 0.01;
$modversion['description'] = "演示模板的使用";
$modversion['author'] = <<<AUTHOR
胡争辉 QQ: 443089607 QQMail: [email protected] GTalk: huzhengh
GMail: [email protected] Skype: huzhenghui"
AUTHOR;
$modversion['credits'] = "";
$modversion['license'] = "版权所有";
$modversion['image'] = "images/logo.png";
$modversion['dirname'] = "moddevtemplate";
$modversion["hasMain"] = 1;
$modversion["sqlfile"]["mysql"] = "sql/mysql.sql";
$modversion["tables"][] = "moddevtemplate_contact";
$modversion["templates"][0]["file"] = "moddevtemplate_index.html";
$modversion["templates"][0]["description"] = "Template for index.php";
?>

其中templates参数代表模块的模板,$modversion[“templates”]是一个数组,数组中的每一项都是一个模板,每一项包含两个键值,file键值代表模板文件名,description键值代表模板的说明。本例中模块包含一个模板$modversion[“templates”][0],模板文件名用$modversion[“templates”][0][“file”]定义,值是moddevtemplate_index.html,模板说明用$modversion[“templates”][0][“description”]定义。

说明:XOOPS系统中所有的模板都可以被任何一个模块使用,因此模板的文件名应当是唯一的,习惯上采用模块的目录名加上下划线作为文件名的前缀,例如本例中的模块名是moddevtemplate,所以模板文件名使用moddevtemplate_作为前缀。

当模块中带有模板时,安装模块的过程中会显示添加模板的相应说明,如图1-25安装模板模块所示。

图1-25安装模板模块
Enlarge
图1-25安装模板模块

在安装过程中,当XOOPS系统发现定义了templates键时,会开始添加模块中的模板,并输出相应的说明。

Adding templates...

在添加模板的过程中会逐一添加定义的模板,首先会把模板添加到数据库中,并输出相应的说明。

Template moddevtemplate_index.html added to the database. (ID: 29)

然后编译该模板,输出相应的说明。

Template moddevtemplate_index.html compiled.

为便于对照学习,数据结构与上例类似,mysql.sql的内容如下:

/modules/moddevtemplate/sql/mysql.sql
CREATE TABLE `moddevtemplate_contact` (
  /* 详见源文件 */
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;
INSERT INTO `moddevtemplate_contact` (`id`, `firstname`, `lastname`, `QQ`, `QQMail`, `GTalk`, `GMail`, `Skype`) VALUES (1, '争辉', '胡', '443089607', '[email protected]', 'huzhengh', '[email protected]', 'huzhenghui');

XOOPS系统中的模板与数据访问对象、查询对象也相互独立,因此页面使用模板不会影响到数据访问句柄,数据访问句柄的功能与结构和上例类似,源代码如下:

/modules/moddevtemplate/class/contact.php
<?php
class ModdevtemplateContact extends XoopsObject {
    function ModdevtemplateContact() {
        /* 详见源文件 */
    }
}
class ModdevtemplateContactHandler extends XoopsObjectHandler {
    function getAll ($criteria = null) {
        /* @var $criteria Criteria */
        $ret = array();
        if (true === isset($criteria)) {
            $sql = "SELECT * FROM ".$this->db->prefix("moddevtemplate_contact").
                " ".$criteria->renderWhere();
        } else {
            $sql = "SELECT * FROM ".$this->db->prefix("moddevtemplate_contact");
        }
        $result = $this->db->query($sql);
        if (false === $result) {
            return $ret;
        }
        while (false !== ($row = $this->db->fetchArray($result))) {
            $contact = new ModdevtemplateContact();
            $contact->assignVars($row);
            $ret[$row["id"]] = $contact;
            unset($contact);
        }
        return $ret;
    }
}
?>

在XOOPS系统中增加模板只需要修改页面,本例的index.php页面的源代码如下:

/modules/moddevtemplate/index.php
<?php
require_once dirname(__FILE__)."/../../mainfile.php";
$contacthandler = xoops_getmodulehandler("contact", "moddevtemplate");
/* @var $contacthandler ModdevtemplateContactHandler */
$xoopsOption["template_main"] = "moddevtemplate_index.html";
include XOOPS_ROOT_PATH."/header.php";
/* @var $xoopsTpl XoopsTpl */
include_once XOOPS_ROOT_PATH."/class/xoopsformloader.php";
$search_form = new XoopsThemeForm("Search Contact", "search_form", "", "get");
$search_form->addElement(new XoopsFormText("first Name:", "firstname", 20, 20));
$search_form->addElement(new XoopsFormButton("", "submit", _SUBMIT, "submit"));
$xoopsTpl->assign_by_ref("search_form", $search_form->render());
if (true === isset($_GET["firstname"])) {
    $myts =& MyTextSanitizer::getInstance();
    $criteria =
        new Criteria("firstname", $myts->addSlashes($_GET["firstname"]));
    $contacts = $contacthandler->getAll($criteria);
} else {
    $contacts = $contacthandler->getAll();
}
$xoopsTpl->assign_by_ref("contacts", $contacts);
include XOOPS_ROOT_PATH."/footer.php";
?>

与上例相比,最明显的区别是页面中没有包含任何HTML标记,而是先声明页面将使用的模板。

$xoopsOption["template_main"] = "moddevtemplate_index.html";

声明模板的语句应当放在include XOOPS_ROOT_PATH."/header.php";语句之前,$xoopsOption变量主要用于设置XOOPS系统相关的选项,键名为template_main的选项代表当前页面使用的模板。模板选项的值就是模板的文件名。接下来创建表单对象的过程和上例相同,区别在于没有直接输出,而是将表单的内容设置为模板的变量。

$xoopsTpl->assign_by_ref("search_form", $search_form->render());

$xoopsTpl变量是XOOPS系统提供的模板对象,在XOOPS_ROOT_PATH."/header.php";文件中创建,因此应当在include XOOPS_ROOT_PATH."/header.php";之后使用$xoopsTpl变量。$xoopsTpl的类型是XoopsTpl,定义在template.php文件中。

/class/template.php
class XoopsTpl extends Smarty {}

XoopsTpl类继承自Smarty类,对于模块开发者而言,可以直接当成Smarty类使用。

说明:Smarty模板的详细信息及文档请参考[这里]。

assign_by_ref函数是Smarty类的成员函数,用于按引用设置模板变量值。

assign_by_ref函数的文档参见http://smarty.php.net/manual/en/api.assign.by.ref.php。

render是XoopsThemeForm的成员函数,功能是将主题风格的表单对象输出成HTML。定义如下。

/class/xoopsform/themeform.php
function render() {}

将表单对象的输出HTML设置为模板变量后,就可以在模板中自由的放置显示位置。和上例的另一个区别是没有枚举$contacts数组并输出,而是设置为模板变量。

$xoopsTpl->assign_by_ref("contacts", $contacts);

通过传递两个模板变量,就将程序逻辑从页面展示中分离出来。而页面展示则通过moddevtemplate_index.html模板实现,代码如下:

/modules/moddevtemplate/templates/moddevtemplate_index.html
<{strip}>
    <{$search_form}>
	<table>
	    <tr>
	        <th>
	            id
	        </th>
	        <th>
	            first name
	        </th>
	        <th>
	            last name
	        </th>
	        <th>
	            QQ
	        </th>
	        <th>
	            QQ Mail
	        </th>
	        <th>
	            Google Talk
	        </th>
	        <th>
	            Google Mail
	        </th>
	        <th>
	            Skype
	        </th>
	    </tr>
	    <{foreach item="contact" from=$contacts}>
		    <tr>
		        <td>
		            <{$contact->getVar("id")}>
		        </td>
		        <td>
		            <{$contact->getVar("firstname")}>
		        </td>
		        <td>
		            <{$contact->getVar("lastname")}>
		        </td>
		        <td>
		            <{$contact->getVar("QQ")}>
		        </td>
		        <td>
		            <a href="mailto:<{$contact->getVar("QQMail")}>">
		                <{$contact->getVar("QQMail")}>
		            </a>
		        </td>
		        <td>
		            <{$contact->getVar("GTalk")}>
		        </td>
		        <td>
		            <a href="mailto:<{$contact->getVar("GMail")}>">
		                <{$contact->getVar("GMail")}>
		            </a>
		        </td>
		        <td>
		            <{$contact->getVar("Skype")}>
		        </td>
		    </tr>
	    <{/foreach}>
	</table>
<{/strip}>

XOOPS系统中页面模板都是保存在模块的templates文件夹中,而在xoops_version.php文件中声明或者在页面中使用则不需要写文件夹。下面分析模板的结构,<{strip}>是Smarty提供的标记,用于清除额外的空白字符和回车换行字符,这样模板中既可以保持便于阅读的缩进格式,又不会影响输出的效果。

说明:strip标记的语法参见[这里]。

<{$search_form}>用于输出变量$search_form,也就是表单。<{foreach item="contact" from=$contacts}>是Smarty提供的标记,用于枚举数组中的元素。

说明: foreach标记的语法参见[这里]。 这样就完成了页面逻辑和模板的分离。

模板与数据库的共同点是XOOPS系统在安装模块和卸载模块时都会启动相应的安装过程和卸载过程。区别在于XOOPS系统在更新模块的过程中不支持数据库的更新,但是支持模板的更新。在安装模板后,进入管理区的模块管理页面,可以看到每个模块都有对应的更新模块的图标image:image029-mokuai.png ,单击moddevtemplate模块的更新图标,则会出现更新模块的确认框。如图1-26更新模块确认框所示。

图1-26更新模块确认框
Enlarge
图1-26更新模块确认框

单击“更新”按钮就会更新模块并输出更新模块的详细信息。如图1-27更新模块信息所示。

图1-27更新模块信息
Enlarge
图1-27更新模块信息

当xoops_version.php中包含templates时,就会启动更新模板的过程。

Updating templates...

每个模板先被重新插入到数据库中。

Template moddevtemplate_index.html inserted to the database.

然后被重新编译。

Template moddevtemplate_index.html recompiled.

在卸载过程中,也会卸载模板并输出卸载模板的详细信息。如图1-28卸载模板过程所示。

图1-28卸载模板过程
Enlarge
图1-28卸载模板过程

当xoops_version.php中包含templates时,就会启动卸载模板的过程。

Deleting templates...

每个模板都会被XOOPS系统从数据库中删除。

Template moddevtemplate_index.html deleted from the database. Template ID: 31

区块

上例通过模板实现了页面逻辑与页面展现的分离。XOOPS系统中广泛的运用模板技术将逻辑与展现分离,除了页面之外,区块也是通过模板技术实现逻辑与展现分离。接下来本例将讲解如何开发区块。本例的文件夹结构如下:

/modules/moddevblock
	/blocks
	/search_form.php
	/class
	/contact.php
	/images
	/logo.png
	/sql
	/mysql.sql
	/templates
	/blocks
	/moddevblock_block_search.html
	/moddevtemplate_index.html
	/index.php
	/xoops_version.php

其中xoops_version.php的内容如下:

/modules/moddevblock/xoops_version.php
<?php
$modversion['name'] = "模块开发 - 区块";
$modversion['version'] = 0.01;
$modversion['description'] = "演示区块的使用";	
$modversion['author'] = <<<AUTHOR
胡争辉 QQ: 443089607 QQMail: [email protected] GTalk: huzhengh
GMail: [email protected] Skype: huzhenghui"
AUTHOR;
$modversion['credits'] = "";
$modversion['license'] = "版权所有";
$modversion['image'] = "images/logo.png";
$modversion['dirname'] = "moddevblock";
$modversion["hasMain"] = 1;
$modversion["sqlfile"]["mysql"] = "sql/mysql.sql";
$modversion["tables"][] = "moddevblock_contact";
$modversion["templates"][0]["file"] = "moddevblock_index.html";
$modversion["templates"][0]["description"] = "Template for index.php";
$modversion['blocks'][0]['file'] = "search_form.php";
$modversion['blocks'][0]['name'] = "Search Contact";
$modversion['blocks'][0]['description'] = "搜索区块";
$modversion['blocks'][0]['show_func'] = "b_moddevblock_search_show";
$modversion['blocks'][0]['template'] = 'moddevblock_block_search.html';
?>

其中blocks参数代表模块的区块,$modversion[“blocks”]是一个数组,数组中的每一项都是一个区块,每一项包含五个键值,file键值代表处理区块逻辑的文件名。name键值代表区块的初始标题,description键值代表区块的说明,show_func键值代表处理区块逻辑的函数,template键值代表展现区块所使用的模板。本例中模块包含一个区块$modversion[“blocks”][0],处理区块逻辑的文件是search_form.php,区块的初始标题是Search Contact,处理区块逻辑的函数是b_moddevblock_search_show,展现区块的模板是moddevblock_block_search.html。当模块中带有区块时,安装模块的过程中会显示添加区块的相应说明,如图1-29安装区块所示。

Image:Image033-mokuai.jpg
图1-29安装区块

在安装过程中,当XOOPS系统发现定义了blocks时,会开始添加模块中的区块,并输出相应的说明。

Adding blocks...

在添加区块的过程中会逐一添加定义的区块,首先会把区块添加到数据库中,并输出相应的说明。

Block Search Contact added. Block ID: 17

然后把区块使用的模板添加到数据库中,并输出相应的说明。

Template moddevblock_block_search.html added to the database. (ID: 44)

接下来编辑该模板,输出相应的说明。

Template moddevblock_block_search.html compiled.

为便于对照学习,数据结构与上例类似,mysql.sql的内容如下:

/modules/moddevblock/sql/mysql.sql
CREATE TABLE `moddevblock_contact` (
  /* 详见源文件 */
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;
INSERT INTO `moddevblock_contact` (`id`, `firstname`, `lastname`, `QQ`, `QQMail`, `GTalk`, `GMail`, `Skype`) VALUES (1, '争辉', '胡', '443089607', '[email protected]', 'huzhengh', '[email protected]', 'huzhenghui');

XOOPS系统中的区块与数据访问对象、查询对象也相互独立,因此区块以及区块对应的模板不会影响到数据访问句柄,数据访问句柄的功能与结构和上例类似,源代码如下:

/modules/moddevblock/class/contact.php
<?php
class ModdevblockContact extends XoopsObject {
    function ModdevblockContact() {
        /* 详见源文件 */
    }
}
class ModdevblockContactHandler extends XoopsObjectHandler {
    function getAll ($criteria = null) {
        /* @var $criteria Criteria */
        $ret = array();
        if (true === isset($criteria)) {
            $sql = "SELECT * FROM ".$this->db->prefix("moddevblock_contact").
                " ".$criteria->renderWhere();
        } else {
            $sql = "SELECT * FROM ".$this->db->prefix("moddevblock_contact");
        }
        $result = $this->db->query($sql);
        if (false === $result) {
            return $ret;
        }
        while (false !== ($row = $this->db->fetchArray($result))) {
            $contact = new ModdevblockContact();
            $contact->assignVars($row);
            $ret[$row["id"]] = $contact;
            unset($contact);
        }
        return $ret;
    }
}
?>

本例中将查询表单移动到区块中实现,因此index.php的页面中不再需要创建表单对象,修改后的index.php源代码如下:

/modules/moddevblock/index.php
<?php
require_once dirname(__FILE__)."/../../mainfile.php";
$contacthandler = xoops_getmodulehandler("contact", "moddevblock");
/* @var $contacthandler ModdevblockContactHandler */
$xoopsOption["template_main"] = "moddevblock_index.html";
include XOOPS_ROOT_PATH."/header.php";
/* @var $xoopsTpl XoopsTpl */
/* 详见源文件 */
?>

相应的模板中也不需要输出表单,修改后的代码如下:

/modules/moddevblock/templates/moddevblock_index.html
<{strip}>
	<table>
        <!-- 详见源文件 -->
	</table>
<{/strip}>

本例中将在区块中实现上例中的查询表单,处理区块逻辑的文件源代码如下:

/modules/moddevblock/blocks/search_form.php
<?php
include_once XOOPS_ROOT_PATH."/class/xoopsformloader.php";
function b_moddevblock_search_show() {
    $search_form = new XoopsThemeForm("Search Contact", "search_form",
        XOOPS_URL."/modules/moddevblock/index.php", "get");
    $search_form->addElement(
        new XoopsFormText("first Name:", "firstname", 10, 10));
    $search_form->addElement(
        new XoopsFormButton("", "submit", _SUBMIT, "submit"));
    $block["search_form"] = $search_form->render();
    return $block;
}
?>

文件名search_form.php就是xoops_version.php中的$modversion['blocks'][0]['file']的值,所在的文件夹是模块文件夹下面的block子文件夹,XOOPS系统中处理区块逻辑的文件都放在模块文件夹下面的block子文件夹中。函数名b_moddevblock_search_show是xoops_version.php中的$modversion['blocks'][0]['show_func']的值。由于区块可能处于任何一个页面上,因此区块中的表单需要指定提交的页面URL。

    $search_form = new XoopsThemeForm("Search Contact", "search_form",
        XOOPS_URL."/modules/moddevblock/index.php", "get");

区块中逻辑与展现之间传递信息与页面不同,从上例中可知,XOOPS系统中页面逻辑与展现模板之间通过$xoopsTpl对象传递变量。而区块是通过函数返回值向展现模板传递变量。在多数情况下,区块会向模板传递多个变量,所以函数的返回值采用数组,表单的内容就是数组中的一项。

$block["search_form"] = $search_form->render();

准备所需的变量后,就通过返回值的形式向区块传递变量。

return $block;

返回变量后,就可以通过模板展现区块了,模板源代码如下:

/modules/moddevblock/templates/blocks/moddevblock_block_search.html
<{strip}>
    <{$block.search_form}>
<{/strip}>

区块模板的文件名moddevblock_block_search.html就是在xoops_version.php中声明的$modversion['blocks'][0]['template']的值。区块模板的文件夹是模块文件夹下面的templates/blocks子文件夹。区块函数的返回值成为模板中的$block变量,本例中直接输出表单内容。

安装模块后,还需要到系统管理的区块管理页面设置显示该区块,如图1-30区块的显示效果所示。

Image:Image034-mokuai.jpg
图1-30区块的显示效果

区块与模板类似,在安装、更新、卸载模块时,都会启动相应的处理过程,在更新带有区块的模块时,会输出相应的详细信息,如图1-31更新区块所示。

Image:Image035-mokuai.jpg
图1-31更新区块

当xoops_version.php中包含blocks时,就会启动更新区块的过程。

Rebuilding blocks...

先更新每个区块。

Block Search Contact updated. Block ID: 17

然后更新区块对应的模板。

Template moddevblock_block_search.html updated.

最后重新编译区块对应的模板。

Template moddevblock_block_search.html recompiled.

在卸载过程中,也会卸载区块并输出卸载区块的详细信息,如图1-32卸载区块所示。

Image:Image036-mokuai.jpg
图1-32卸载区块

当xoops_version.php中包含blocks时,就会启动卸载区块的过程。

Deleting block...

每个区块都会被卸载。

Block Search Contact deleted. Block ID: 17

每个区块对应的模板都会被XOOPS系统从数据库中删除。

Block template moddevblock_block_search.html deleted from the database. Template ID: 44

来自"http://xoops.org.cn/modules/mediawiki/index.php/%E6%A8%A1%E5%9D%97%E5%BC%80%E5%8F%91"

浏览统计:13,205 次。 最后修订:09:28 2009年4月16日 © XOOPS China.