Oracle+PHP 简明手册

 

Flash 远程控制与 Oracle 和 PHPObject 结合使用


作者:Nick Bollweg

使用 PHPObject 将 Macromedia Flash 与 Oracle 数据无缝集成。

本文相关下载:
 示例代码和清单
 Oracle 数据库 10g 特别版
 Zend Core for Oracle
 Ghostwire Studios 的 PHPObject
 Macromedia Flash 30 日试用

2006 年 1 月发表

您的用户需要它,您的经理需要它。归根结底,在浏览器中开发低延迟的交互式应用程序真的很酷。随着 Ajax 框架和下一代浏览器的激增,您可以在短时间内迅速完成下一代 Google 地图的设计。

Ajax 和 XMLHttpRequest 很出色,利用它们的应用程序同样很出色。但如果要在 PHP 中使用 Oracle 数据库中的数据设计一个优化的富媒体应用程序,Flash 和 PHPObject 不用在浏览器功能方面花费太多心思就可帮助您快速完成。在 Oracle-PHP 简明手册的这篇文章中,我将对此进行介绍。

 

FlashJAX

由于支持 Ajax 的应用程序逐渐流行,Adobe 收购 Macromedia 造成的不确定性因素以及新兴的 SVG 存在巨大潜力,因此使用 Flash 部署新 Web 应用程序已不再是当前的时髦技术。但 Flash 仍是可用的高交互性 Web 应用程序的最佳平台,其预期的普及率为 97.3%(数据来源 Macromedia)。任何浏览器(当然也包括 Ajax 框架)都无法实现如此高的普及率。

Flash 远程控制 是一个构建到 Flash 播放器内核的技术,它支持在服务器与客户端之间无缝传输数据。(Macromedia 在这方面提供了一个引人瞩目但在一定程度上受服务器限制的产品。)此外,还存在几个开放源代码选择,其中包括 AMFPHP 和 PHPObject。这两种方法的作用机制是在用户的 Flash 播放器之间传递串行化对象,同时 Web 服务器 AMFPHP 在服务器端对 Macromedia 的 AMF 格式进行解码,而 PHPObject(本文的主题)相对比较成熟,它在客户端对 PHP 对象进行解码。此外,两者还可以使用 SOAP Web 服务,但该方法超出了本文的讨论范围。

 

快速入门

在本文中,您将需要一个适当的支持 Oracle 的 Web 服务器和 Oracle 数据库 10g。获取两者的最简单、最可靠的方法是下载 Zend Core for Oracle(提供现成的 Oracle 和 PHP 连接性)和 Oracle 数据库 10g 特别版 (Oracle 免费的入门数据库)。此外,您将需要下载最新版本的 GhostWire Studios PHPObject(本文使用 1.52 版。)安装 PHP 和 Oracle 后,在文档根目录下创建一个目录来存放此应用程序,并从示例代码下载中解压缩文件。我使用的目录名为“oclflash”。此时还需要解压缩 PHPObject 的“server”目录中的两个文件:Gateway.php 和 config.php。

对于桌面应用程序,必须具备 Microsoft Windows 或 Apple Macintosh 桌面环境和最新版本的 Flash 开发环境。此外,尽管许多常用编辑器还提供了 ActionScript 插件,但我还是建议使用 SE|PY(一个开放源代码的 ActionScript 编辑器)。

在 Flash 环境中,您将需要提供用 ActionScript 编写的 PHPObject 程序包,以便可以将它包含在您的 Flash 电影中。安装 Flash 后,您还将在文件夹中找到“Macromedia Extension Manager”的快捷方式以及 Flash 快捷方式。启动此应用程序,选择 File->Install Extension...。导航到将 PHPObject 安装文件解压缩到的位置并选择 PHPObject_AS2.mxp。现在,您的 Web 服务器和开发环境已经就绪。

 

执行所需的操作

本文中的示例是一个报表应用程序,它允许用户直观地导航一组复杂的数据(Flash 远程控制的一个重要用途)。(请参见图 1。)标题广告和简单的导航可能不需要此方法,但它对于非常强健的导航客户端将比较合适。

 

图 1
图 1 示例应用程序 - 简单的销售图

要完成本示例,您将使用下表扩展这个简单的 HR 模式(简明手册编写者的挚爱)以跟踪这个普及的简要销售图的每个销售。该表以及支持序列的定义以 createSaleTableAndSequence.sql(将在 HTML DB 或 SQL*Plus 中运行)的形式包含在示例代码中。

CREATE TABLE SALE ( 
        SALEDATE DATE NOT NULL , 
        SALESPERSON NUMBER NOT NULL , 
        INVOICE NUMBER, PRIMARY KEY (INVOICE) VALIDATE );
另一个脚本 generateTestData.php(包含在示例代码下载中)将生成一些随机销售数据。在您的浏览器中运行它(或者,如果您愿意,可以从命令行运行它)。

从该数据中,您将创建一个具有灵活下钻和摘要功能的条形图以及时间和员工维度。该图表的参数将被存储在单个 SQL 查询中,因此添加或删除维度只需要对该查询进行几处更改。由于该表已经填充了数据,因此如果您已经在 http://localhost/oclflash 中提供了应用程序,则现在可以通过打开 http://localhost/oclflash/chart.html 测试该应用程序。

 

打破界限

 

要创建一个可重用的 Flash 图表应用程序,所有特定于图表的信息均通过详细的列名位于一个 SQL 查询中。该方法需要在 PHP 和 Oracle 之间传递额外的数据,但它还允许通过修改某个查询来快速添加新图表维度。

在以下查询中:

select 
        "Widget Sales",
        "_Time_Year","_Time_Quarter",
        to_char(to_date("_Time_Month",'MM'),'Month') "_Time_Month",
        "_People_Manager",
        "_People_Salesperson",
        "__Time_Year",        "__Time_Quarter","__Time_Month","__People_Manager","__People_Salesperson"
from
(select 
        count(*)                                "Widget Sales",       
        to_char(SALEDATE,'YYYY')                "_Time_Year",
        to_char(SALEDATE,'Q')           "_Time_Quarter",
        to_char(SALEDATE,'MM')          "_Time_Month",
        b.LAST_NAME                             "_People_Manager",
        a.LAST_NAME                             "_People_Salesperson",
        grouping(to_char(SALEDATE,'YYYY'))"__Time_Year",
        grouping(to_char(SALEDATE,'Q')) "__Time_Quarter",
        grouping(to_char(SALEDATE,'MM'))        "__Time_Month",
        grouping(b.LAST_NAME)                   "__People_Manager",
        grouping(a.LAST_NAME)                   "__People_Salesperson"
from
        SALE, EMPLOYEES a, EMPLOYEES b
where
        a.EMPLOYEE_ID = SALESPERSON AND
        b.EMPLOYEE_ID = a.MGR
group by
        cube(
                to_char(SALEDATE,'YYYY'),
                to_char(SALEDATE,'Q'),
                to_char(SALEDATE,'MM'),
                b.LAST_NAME,
                a.LAST_NAME
        )
order by
        "_Time_Year","_Time_Quarter","_Time_Month","_People_Manager","_People_Salesperson")
...使用了以下约定:
  • 维度列名:_<维度名>_<维度级别名>。该示例的两个维度是 TimePeople,它们分别包含诸如 MonthManager 这样的维度级别。列显示的顺序很重要。范围最广的级别优先级最高: YearQuarter 的范围广, ManagerSalesperson 的范围广。
  • 摘要列名:__<维度名>_<维度级别名>。额外的下划线将使代码知道该列描述了行的摘要函数(分组)。
(如果您不熟悉 CUBE 分析运算符(它执行此查询中的大多数繁重任务)以及它的特殊 SQL 转换(如 GROUPING),则可能要参考本文档。)

扩展此查询涉及添加新维度级别的值列和相应的 GROUPING 列。例如,要使细粒度数据分析为周分析,必须进行以下更改:

  1. to_char(SALEDATE,'W') "_Time_Week" 添加到内部选择。注意那个单下划线。
  2. to_char(SALEDATE,'W') 添加到 GROUP BY CUBE 子句。
  3. grouping(to_char(SALEDATE,'W')) "__Time_Week" 添加到内部选择。注意那两个下划线。
  4. "_Time_Week" 添加到外部 ORDER BY 子句。
  5. "_Time_Week" 添加到外部选择。
同样,可以执行以上针对 "_Space_Location""_Space_Region""_Space_Country" 的步骤向相应表中添加一个全新的维度。每个其他维度将使每个会话返回给 PHP 的行数加倍。尽管客户端在给定时间将只检查一个小数据段,但用户将感受到一个更长的初始等待时间。

有了查询(也可能使用文本编辑器),您现在就可以查看本示例的 PHP 端。

 

远程控制网关的关键

 

PHPObject 使用一个名为 Gateway.php 的文件处理在 PHP 和 Flash 之间移动串行化对象的所有细节,尽管您可能不需要修改此脚本。但 config.php 包含几个重要值。此处以及您的客户端 Flash 电影中必须有用于基本验证的“密钥”。用于 PHPObject 的类文件(在本示例中为 ChartData.php)也存储在此处。在本示例中,所有东西存储在一个目录中,因此无需指定特定值。
$cfg['classdir'][0]     = "";
$cfg['useKey']          = "secret";
PHPObject 的对象实现为一个包含函数(从驱动电影的 ActionScript 中直接调用)的类;这正是 PHPObject 模型的优势所在。以下是 ChartData.php 中的代码片段。
function updateChart(){

        $this->chartValues = array_values(array_filter($_SESSION['dataSet'],
                                        array("ChartData","filterDataSet")));                       

        $this->determineLabelColumn();       

}
以下是方法调用的代码片段(使用 PHP 在 ActionScript 2.0 脚本 chartExampleActions.as 中定义)。
cd.updateChart();
就这样!至少,这是一个通过 PHPObject 远程控制模型实现的简单部分。

 

Nutshell 中的 ChartData.php

调用此构造函数时, ChartDataclass 的一般行为是从数据库中加载报表数据集,将它放置在会话中并使用一些默认数据填充传递给 Flash 的图表数据。在使用更新的 chartParams 连续调用 updateChart 时, ChartData 将返回不同的数据集片段。

某些辅助函数过滤数据集并创建将使客户端能够下钻并归纳的拓扑结构。类变量中包含数据库连接信息;您必须更改这些变量以匹配本地环境。

 

Nutshell 中的 chartExampleActions.as

 

由于外部 ActionScript 2.0 脚本(与 Java 类文件非常相似)可能只实现类和导入其他类,因此包装类应定义电影应有的行为。从代码重用和更改控制的角度而言,该模式比较适合在 Flash 电影中分布少量代码。

 

专门用于实现动画效果的代码是一个例外;此类代码通常比较简洁并且驱动电影的纯视觉函数。在本文的示例中,movieClip“栏”包含了一些 ActionScript 来制造“渐增栏”效果。该示例中的包装类 chartExampleActions 具有以下重要代码:
PHPObject.defaultGatewayKey = "secret";
PHPObject.defaultGatewayUrl = "http://localhost/oclflash/Gateway.php";
_root.chartData = new PHPObject("ChartData");
该代码设置网关的“密钥”和位置并创建一个 ChartData 实例用于 Flash 电影。当构造函数在 PHP 中成功完成时,它将触发您为实例定义的 onInit 方法:
_root.chartData.onInit = function() {
        chart.throbber._visible = false;
        chart.chartTitle.text = this.valueColumn;
        for(var a in this.axes){
                _root.axis.addItem(a);
        }
        drawChart(this);
}
同样,在对 updateChart 进行连续调用时,ChartData 将引发 onResult 方法:
_root.chartData.onResult = function() {
        _root.chart.throbber._visible = false;
        drawChart(this);
}
另一个重要函数 drawChart 用于实际构建此图表并添加逻辑和交互性。在 Flash 环境中打开 chart.fla 文件后,选择 File->Publish... 将在应用程序目录中创建一个更新版本的 swf。如果要从不同于示例代码预期的位置为应用程序提供服务,则将必须执行该操作。

 

以需要为基础

正如我在前面指出的,PHPObject 在 Flash 和 PHP 之间传递对象的同步副本。由于许多查询可能导致大型的数据集,因此将这些数据集提供给 Flash 通常并不合适。由于您只是一次显示一个结果片段,因此可以在从 Oracle 检索剩余数据后将这些数据存储在 PHP 会话中。虽然在服务器下次处理该对象时可以使用该数据,但不会将其传递给客户端。确保在服务器上启用了 session_autostart,或在 classfile 中指定了 session_register() — 一个更精确的方法,也是此处使用的方法。

此外,可以通过设置一个客户端可见函数的显式列表对 Flash 隐藏一些类函数(客户端将无法调用它们)。在本文的示例中,您只需要公开 updateChart:

public $classMethods = array("updateChart");
此外应记住,任何远程控制解决方案都会为应用程序带来某些安全风险。Flash 不对返回至 PHP 的串行化对象进行全面检查,而这却是 AMFPHP 的一个优点。与任何常规 PHP 脚本一样,PHPObject 类 从不实现一种在数据库中执行任意 SQL 的方法。

 

结论

Flash 提供了一个引人瞩目的交互式 Web 元素部署方法,将 PHP 与 PHPObject 一起使用是一种将 Oracle 数据集成到交互式组件中的高效方法。在采用其他交互方法之前,请试一试该方法;它在简化开发以及支持浏览器方面提供了重要平衡。 Nick Bollweg [ nick.bollweg@gmail.com] 是 Johns Hopkins Medical Institute 的 Sidney Kimmel Cancer Center 的高级程序员,该机构位于马里兰州的 Baltimore 市。

将您的意见发送给我们