学习使用
RIA Framework Flex
创建
MySQL
管理
UI
PHPMyAdmin
的出现震撼了业界,这毫无疑问。它当然是基于
PHP
的最佳应用程序,因为它将
MySQL
管理界面由命令行的形式改为了
web
浏览器的形式。不过,虽然它的功能很强大,但使用并不太方便,界面也不够美观。因此,我尝试通过
Rich Internet Application
框架设计更理想的
MySQL
前台管理程序。
要达成此目标本可选用
Ajax
。但我不想处理客户端的不兼容问题。当然,
Silverlight
也是不错的选择,但它仍不够成熟。
之所以选择
Adobe Flex
,是因为它拥有富用户接口工具集和方便的
web
服务集成功能,而且它生成的
Flash
应用程序能够以相同方式在任何操作系统中运行。
我学习了很多有关创建应用程序方面的知识:如何为
PHP
程序创建安全的
SQL web
服务;如何通过
Flex
访问
web
服务;如何将
web
服务返回的数据输入数据网格中并显示。在本文中,我将引领读者从前台到后台,逐步创建
MySQL
管理程序。读者从中可了解一些有用的信息,以创建自己的
Rich Internet
应用程序。
创建后台程序
Flex
应用程序擅长与
web
服务通讯,以发出请求及提交数据。因此,首先需要创建一个非常简单的
PHP
脚本,它将以
XML
格式返回数据库列表、表或表中的数据。
清单
1. req.php
<?php
require_once("MDB2.php");
$sql = 'SHOW DATABASES';
if ( $_REQUEST['mode'] == 'getTables' )
$sql = 'SHOW TABLES';
if ( $_REQUEST['mode'] == 'getData' )
$sql = 'SELECT * FROM '.$_REQUEST['table'];
$dsn = 'mysql://root@localhost/'.$_REQUEST['db'];
$mdb2 =& MDB2::factory($dsn);
if (PEAR::isError($mdb2)) { die($mdb2->getMessage()); }
$dom = new DomDocument();
$dom->formatOutput = true;
$root = $dom->createElement( "records" );
$dom->appendChild( $root );
$res =& $mdb2->query( $sql );
if (PEAR::isError($mdb2)) { die($mdb2->getMessage()); }
while ($row = $res->fetchRow(MDB2_FETCHMODE_ASSOC))
{
$rec = $dom->createElement( "record" );
$root->appendChild( $rec );
foreach( array_keys( $row ) as $key ) {
$key_elem = $dom->createElement( $key );
$rec->appendChild( $key_elem );
$key_elem->appendChild( $dom->createTextNode( $row[$key] ) );
}
}
$res->free();
$mdb2->disconnect();
header( "Content-type: text/xml" );
echo $dom->saveXML();
?>
该脚本的第一项工作就是利用
MDB2
库连接数据库。如果没有安装
MDB2
库,则可使用
PEAR
安装该库,如下所示:
% pear install MDB2
%
如果
PEAR
无法正常运行,可访问
http://pear.php.net/mdb2
,然后下载源代码并将其解包到
PHP
的
include
路径下。
MDB2
是通用的数据库适配器层,它已取代了广为使用的
PEAR DB
库。
脚本的第二项工作就是创建
XML DOM Document
对象,该对象将用来创建要输出的
XML
树。从此处开始,它将运行查询,并在
XML
树中添加
row
和
column
作为
XML
标签。最后,该脚本将关闭所有连接,并将
XML
保存到
PHP
输出流中。
选用
XML DOM
对象的原因是,它可避免任何与数据、不对称标签等有关的编码问题以及各种可能使
XML
产生混乱的因素。我可以将调试
XML
数据流的时间节省下来做其他许多更有意义的工作。您一定也会这样做。
将该脚本安装到本地机器上的可运行目录下,然后使用
curl
命令向服务器发出请求。
% curl "http://localhost/sql/req.php"
<?xml version="1.0"?>
<records>
<record>
<database>addresses</database>
</record>
<record>
<database>ajaxdb</database>
</record>
...
%
在本例中,我并未指定数据库或模式,这会要求脚本返回可用数据库的清单。假如
web
服务脚本有权执行该任务,则在
curl
语句后面就会显示执行的结果。在本例中,将以标签的形式显示不同数据库的列表。
该脚本返回的所有数据都带有
<records>
标签,它包含一组
<record>
标签。每个
<record>
标签的名称和内容取决于已执行的
SQL
语句。在本例中,只返回单列命名数据库。
除了使用
curl
命令,还可将
URL
输入浏览器中,然后在加载页面后选择“
View Source
(查看源文件)”。
在下例中,将连接
articles
数据库并获取它的表格列表。结果如下:
% curl ".../req.php?mode=getTables&db=articles"
<?xml version="1.0"?>
<records>
<record>
<tables_in_articles>article</tables_in_articles>
</record>
</records>
%
a
rticles
数据库中只
有一个名为
article
的表格,这并不奇怪。要运行经典的
select * from article
查询以获取所有记录,可使用以下
URL
:
% curl ".../req.php?mode=getData&db=articles&table=article"
<?xml version="1.0"?>
<records>
<record>
<id>1</id>
<title>Apple releases iPhone</title>
<content>Apple Computer is going to release the iPhone...</content>
</record>
<record>
<id>2</id>
<title>Google release Gears</title>
<content>Google, Inc. of Mountain View California has...</content>
</record>
</records>
%
表格中有两条记录:第一条显示
Apple
公司将发布超炫的
IPhone
;第二条显示
Google
公司将发布同样很炫、但用途完全不同的
Gears
系统。
在本地机器上安装了极为强大且灵活的后台程序后,就可以着手为其创建
Flex
前台程序了。
创建用户界面
我想以层的形式创建
Flex
应用程序,首先是用户界面,然后在框架中添加代码以实现互动性。首先,若尚未安装
Flex SDK
则先安装。
Flex SDK
是免费软件,
Flex Builder 2 IDE
也有免费试用版。可从
http://www.flex.org/download
下载
Flex SDK
。
Flex SDK
是免费的,
Flex 3 SDK
也将成为开源软件。
Flex Builder
是一种基于
Eclipse
的开发环境,通过拖放控件即可创建界面,但本例不必使用该工具。我非常喜欢使用标签,因此通常采用代码视图并直接修改
MXML
。
我想在界面顶部放置几个控件并在底部放置一个数据网格,以显示表中的数据。顶部的控件就是两个下拉列表,可在其中选择数据库和表。
该窗体的
MXML
如清单
2
所示。
清单
2. flexmysql1.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="
http://www.adobe.com/2006/mxml
" layout="
vertical
"
>
<mx:VBox
horizontalAlign="
left
"
>
<mx:HBox>
<mx:Label
text="
Database:
"
/>
<mx:ComboBox
id="
selectedDatabase
" width="
381
" height="
21
"
>
</mx:ComboBox>
</mx:HBox>
<mx:HBox>
<mx:Label
text="
Table:
"
/>
<mx:ComboBox
id="
selectedTable
" width="
381
" height="
21
"
>
</mx:ComboBox>
</mx:HBox>
<mx:DataGrid
id="
dg1
" width="
452
"
>
</mx:DataGrid>
</mx:VBox>
</mx:Application>
在
Flex Builder 2
中编译及运行这段代码时,结果如图
1
所示。
图
1.
界面布局
相当整洁,对吧?渐变背景很漂亮,控件也很美观。我只做了极少量的工作。当然,图形设计师也可添加一些修饰,以使其更加美观,例如过渡效果和图像。而我还是喜欢整洁的界面,并要确保它在每台客户机上都具有一致的外观和表现,而
Ajax
应用程序要做到这一点并不容易。
获取数据库清单
补充
Flex
应用程序代码的第一步就是,当应用程序加载后在窗体顶部显示数据库的组合框。相关代码如清单
3
所示。
清单
3. flexmysql2.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="
http://www.adobe.com/2006/mxml
" layout="
vertical
"
initialize="onInitialize()"
>
<mx:Script>
<![CDATA[
import
mx.collections.ArrayCollection;
private static const
SERVICE_BASE:String =
"http://localhost/sql/req.php"
;
public
function
onInitialize():
void
{
myservice.url = SERVICE_BASE;
myservice.send(
null
);
}
public
function
onResult(event:Event):
void
{
selectedDatabase.dataProvider = myservice.lastResult..database.*;
}
]]>
</mx:Script>
<mx:HTTPService
id="
myservice
" result="onResult(event)" resultFormat="
e4x
"
>
</mx:HTTPService>
<mx:VBox
horizontalAlign="
left
"
>
<mx:HBox>
<mx:Label
text="
Database:
"
/>
<mx:ComboBox
id="
selectedDatabase
" width="
381
" height="
21
"
>
</mx:ComboBox>
</mx:HBox>
<mx:HBox>
<mx:Label
text="
Table:
"
/>
<mx:ComboBox
id="
selectedTable
" width="
381
" height="
21
"
>
</mx:ComboBox>
</mx:HBox>
<mx:DataGrid
id="
dg1
" width="
452
"
>
</mx:DataGrid>
</mx:VBox>
</mx:Application>
我省略了与前例类似的部分代码,以缩短代码段长度。差别重点在于
<mx:HTTPService>
标签,它将创建
HTTP Service Flex
对象,而后者将与服务器进行通讯。该服务对象由
onInitialize
方法调用,
而后者在
Flex
应用程序启动时调用。
onInitialize
方法先
设置服务的
URL
,然后开始发出请求。请求完成后,就调用
onResult
方法。
onResult
方法将组合框的
dataProvider
设为
web
服务器的返回结果。
该方法最有价值的部分如下:
myservice.lastResult..database.*
看看这个语句。如果之前不了解
E4X
的作用,我可以稍加解释。
myservice.lastResult
变量实际上是一个
XML
文档。
‘..’
句法等价于
XPath ‘//’
句法。它表示“将具有此名字的任何一个标签给我”,在本例中就是“将任何一个数据库标签给我”。星号表示数据库标签的任何子标签。由于数据库标签只有一个子标签,即数据库名称的文字部分,因此这段代码就表示“将
XML
文档中每个数据库的名称给我”。这个功能真的很好用!
正是由于
ActionScript
的这种
E4X
扩展,
Flex
才能够方便地与
XML
数据源进行通讯。据我所知,还没有其他语言能够如此方便地查询
XML
文档。因此利用强大的
E4X
,就可以在浏览器中运行该应用程序,并得到如图
2
所示的结果。
图
2.
填充数据库名称的数据库组合框
单击该组合框时,将弹出下拉列表,并显示机器中的数据库列表。是的,其中有很多数据库。几乎每篇有关
PHP
、
Flex
、
Rails
或其他技术的文章都会用到数据库,所以我拥有大量的数据库。
创建表视图代码
创建示例
Flex
应用程序的最后一步就是添加表格的下拉菜单,并在数据网格中显示选中表格的数据。该例的完整代码如清单
4
所示。
清单
4. flexmysql.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="
http://www.adobe.com/2006/mxml
" layout="
vertical
"
initialize="onInitialize()"
>
<mx:Script>
<![CDATA[
import
mx.collections.ArrayCollection;
private static const
SERVICE_BASE:String =
"http://localhost/sql/req.php"
;
private
var
loadingDatabases:Boolean =
true
;
private
var
loadingTables:Boolean =
false
;
public
function
onInitialize():
void
{
loadingDatabases =
true
;
myservice.url = SERVICE_BASE;
myservice.send(
null
);
}
public
function
onResult(event:Event):
void
{
if
( loadingDatabases )
{
loadingDatabases =
false
;
selectedDatabase.dataProvider = myservice.lastResult..database.*;
onSelectDatabase();
}
else if
( loadingTables )
{
loadingTables =
false
;
var
tables:Array =
new
Array();
for each
(
var
tablRecord:XML
in
myservice.lastResult..record )
{
for each
(
var
tablCol:XML
in
tablRecord.* )
tables.push( tablCol..*.toString() );
}
selectedTable.dataProvider = tables;
onSelectTable();
}
else
{
var
records:Array =
new
Array();
for each
(
var
record:XML
in
myservice.lastResult..record )
{
var
outRecord:Array =
new
Array();
for each
(
var
column:XML
in
record.* )
outRecord[ column.name() ] = column..*.toString();
records.push( outRecord );
}
var
data:ArrayCollection =
new
ArrayCollection( records );
dg1.dataProvider = data;
}
}
public
function
onSelectDatabase():
void
{
loadingDatabases =
false
;
loadingTables =
true
;
var
url:String = SERVICE_BASE;
url +=
"?mode=getTables&db="
+selectedDatabase.selectedLabel;
myservice.url = url;
myservice.send(
null
);
}
public
function
onSelectTable():
void
{
var
url:String = SERVICE_BASE;
url +=
"?mode=getData&db="
+selectedDatabase.selectedLabel;
url +=
"&table="
+selectedTable.selectedLabel;
myservice.url = url;
myservice.send(
null
);
}
]]>
</mx:Script>
<mx:HTTPService
id="
myservice
"
result="onResult(event)" resultFormat="
e4x
"
>
</mx:HTTPService>
<mx:VBox
horizontalAlign="
left
"
>
<mx:HBox>
<mx:Label
text="
Database:
"
/>
<mx:ComboBox
id="
selectedDatabase
" width="
381
" height="
21
"
change="onSelectDatabase()"
>
</mx:ComboBox>
</mx:HBox>
<mx:HBox>
<mx:Label
text="
Table:
"
/>
<mx:ComboBox
id="
selectedTable
" width="
381
" height="
21
"
change="onSelectTable()"
>
</mx:ComboBox>
</mx:HBox>
<mx:DataGrid
id="
dg1
" width="
452
"
>
</mx:DataGrid>
</mx:VBox>
</mx:Application>
其中有一处重要修改,即添加了
onSelectDatabase()
函数的代码,以获取表格列表,然后将其输入到
onResult()
函数中,还添加了
onSelectTable()
函数,该函数可检索表格中的数据,并在
onResult()
处理器中设置数据网格。
在浏览器中运行该例时,结果如图
3
所示。
图
3.
运行“
show tables
”查询之后的结果
本例中使用了
nasa
数据库,这是我为
NASA Ames
演讲而创建的数据库(我用了“火箭科学”的笑话,因为当时我的听众是一群火箭科学家)。该数据库只有一个名为
mission
的表,其中包含两列,分别代表每项由
NASA
发起但已撤消的任务名称和年份。
在数据网格中单击名称列即可按名称排序,如图
4
所示。
图
4.
显示
mission
表中的数据
然后单击年份列,以按照年份排列数据,如图
5
所示。
图
5.
迪斯科球式查询
在过去几年中,我们似乎并未发起任何任务。
后续步骤
至此,本例已可应用于许多场合。在前台
Flex
应用中,可以添加一些对用户更友好的控件,以添加、删除或更新表格。甚至可以提供数据过滤功能或者编辑功能,以修改表格中的数据。数据网格控件非常强大,可以处理现场编辑任务。也可以用在完全不同的场合,例如使用
Flex
绘图软件包执行数据分析和可视化工作。
总结
PHP
和
Flex
的结合潜力无限。利用
PHP
可以方便地在后台发布
web
服务,可以单独发布,可以与
HTML
前台程序一起发布。
PHPMyAdmin
带有
web
服务接口扩展功能,使任何人都能以
Flex
、
Ajax
、
Silverlight
、桌面小部件或其他任何技术编写前台程序。
Flex
为
PHP
开发人员提供了强大的前台工具。它避开了困扰
Ajax
开发人员的客户端不兼容问题。
Flex 2
并非只能使用特定的服务器技术,因此
Flex
应用程序编译完成后,它就可以部署在任何场合,因为它只是一个
SWF
文件。可以看到,利用简单的
web
服务对象和强大的
E4X
语言扩展,就可以让
Flex
应用程序方便地与几乎任何一种后台程序进行通讯。
读者不妨一试,如果您使用
PHP
和
Flex
创建了有趣的程序,请告诉我,也许我们可以合写一篇文章来介绍它。