下载
 Oracle 数据库 11g
 Symfony
 
   标签
php, database, 全部
 
DBA:PHP

Oracle Symfony 共奏 PHP 小调

作者:Mladen Gogala

Oracle 数据库 11g 与 Symfony Web PHP 框架可以合奏出美妙的乐章,如这一简单的示例应用程序所展示的那样。

2008 年 7 月发布

Symfony 是一款非常受欢迎的模型视图控制器 (MVC) 框架,利用它可以快速高效地创建 Web 应用程序。与许多此类工具一样,它使用了一种称作 Propel 的对象关系映射器 (ORM)。在我担任 DBA 的工作中,不久前曾被指派去修改一个使用 Symfony 框架编写的应用程序,而该应用程序的作者已经离开公司。那时,我是公司里面唯一既懂 PHP 又懂 Oracle 的人,虽然我还要担任 DBA,但这个工作还是自然地落到了我的头上。

长话短说,学习 Symfony 不是问题,该框架简单易用、功能丰富、令我很满意。如果有人想学习 Symfony,该从何处入手呢?Symfony 项目有一个信息丰富、保持完好的网站,上面有大量文档。您会发现,有一本关于 Symfony 的书,还有许多教程 — 遗憾的是,它们都是用 MySQL 数据库写的。其实,这就是我决定写这篇关于 Symfony 和 Oracle 的文章的原因。这篇文章不是十分完善的教程,但我希望它会对那些希望将 Symfony 和 Oracle 结合使用的人有所帮助。

接下来,我会使用 Oracle 数据库 11g 和 Symfony 创建一个小型 Web 应用程序。该应用程序将访问无所不在的 SCOTT 模式,以及同样著名的 EMP 和 DEPT 表。该应用程序虽然没什么意义,但是功能齐全。

基础

Symfony 是一个 MVC 工具,使用名为 Propel 的 ORM。这意味着在开发应用程序阶段,Symfony 会为您做以下事情:

有三种常见的部署拓扑:

  • 将 Oracle 关系数据库管理系统表映射为 PHP5 类。它还会创建基本的创建、检索、更新以及删除 (CRUD) 方法。
  • 使用 Propel 创建的 CRUD 方法创建模块,这些模块使我们能查看和控制数据。

虽然一个人应该既懂 PHP5 又懂 Oracle 才敢从事 PHP5 加 Oracle 的应用程序开发,但所需的编程是极少的。

与任何 Web 应用程序一样,您还需要一台 Web 服务器。本文中使用的 Web 服务器是 Apache:httpd-2.2.3-11.el5_1.centos.3。应用程序软件与测试用的 Oracle 数据库 11g 都安装在 Cntos 5.0 上,因为它与 Red Hat Linux 很相似。PHP5 支持目前使用的所有主要版本。您可以轻松地在 Oracle 数据库 11g 上开发,在 Oracle 数据库 10g 上部署。然而,我必须说一句,Oracle 数据库 11g 比 Oracle 数据库 10g 更适合 Web 应用程序。这是因为 11g 的结果缓存特性允许重用已经执行过的查询结果,而不需要检查重新解析和执行查询的细节。

为了与 PHP5 结合使用,相应的 Apache 模块必须链接并安装好。Symfony 不支持 PHP4。要安装 PHP5 及所有相关模块,一个简单方法是下载并安装 Zend Core for Oracle。

当然,还需要安装 Symfony。本文将不涉及具体的 Symfony 安装,产品网站上的说明已经介绍得相当清楚了。这里只要知道 Symfony 是使用标准 PEAR 实用程序安装的就足够了。Symfony 的最新稳定版本是 1.1.0。

那么,Symfony 是怎样工作的?Symfony 是一个应用程序生成器,因此它里面有一个描述性元素。首先,您需要描述 Oracle 对象。然后,在这些对象上生成应用程序。最后,修改应用程序以符合我们的需要。Symfony 针对每一步都提供了简单的方法。

描述对象

首先向 Symfony 描述 Oracle 模式,为此,您首先需要对用于访问该模式的 Oracle 实例进行描述。完成该任务的组件是 Propel,它是一个 ORM,能够将关系对象描述映射到对象类。针对每个表生成一个类,并针对该类生成所有 CRUD。将这些组件描述给 Symfony(当然,还有 Propel)所使用的语言称作 YAML,它是 XML 的简化版,近来在使用 PHP 和 Perl 这类脚本语言的用户中很流行。YAML 语法极其简单、容错、直观和易用。

闲话少说,我们从项目开始。第一步是创建项目目录,并通过创建子目录结构来对它进行初始化,使用的命令是 symfony init-proj test_proj

mgogala@TheBox> mkdir test_proj 
mgogala@TheBox> cd test_proj
mgogala@TheBox> symfony init-proj test_proj
>> dir+ /home/mgogala/test_proj/doc
>> dir+ /home/mgogala/test_proj/log
>> dir+ /home/mgogala/test_proj/test
>> dir+ /home/mgogala/test_proj/test/functional
>> dir+ /home/mgogala/test_proj/test/bootstrap
>> file+ /home/mgogala/test_proj/test/bootstrap/functional.php
>> file+ /home/mgogala/test_proj/test/bootstrap/unit.php
>> dir+ /home/mgogala/test_proj/test/unit
>> dir+ /home/mgogala/test_proj/config
>> file+ /home/mgogala/test_proj/config/config.php
>> file+ /home/mgogala/test_proj/config/databases.yml
>> file+ /home/mgogala/test_proj/config/properties.ini
>> file+ /home/mgogala/test_proj/config/rsync_exclude.txt
>> file+ /home/mgogala/test_proj/config/schema.yml
>> file+ /home/mgogala/test_proj/config/propel.ini
>> dir+ /home/mgogala/test_proj/cache
>> dir+ /home/mgogala/test_proj/plugins
>> dir+ /home/mgogala/test_proj/data
>> dir+ /home/mgogala/test_proj/data/model
>> dir+ /home/mgogala/test_proj/data/sql
>> file+ /home/mgogala/test_proj/symfony
>> dir+ /home/mgogala/test_proj/batch
>> dir+ /home/mgogala/test_proj/web
>> dir+ /home/mgogala/test_proj/web/images
>> file+ /home/mgogala/test_proj/web/.htaccess
>> dir+ /home/mgogala/test_proj/web/js
>> file+ /home/mgogala/test_proj/web/robots.txt
>> dir+ /home/mgogala/test_proj/web/uploads
>> dir+ /home/mgogala/test_proj/web/uploads/assets
>> dir+ /home/mgogala/test_proj/web/css
>> file+ /home/mgogala/test_proj/web/css/main.css
>> dir+ /home/mgogala/test_proj/lib
>> dir+ /home/mgogala/test_proj/lib/model
>> dir+ /home/mgogala/test_proj/apps
>> tokens /home/mgogala/test_proj/config/properties.ini
>> tokens /home/mgogala/test_proj/config/propel.ini
>> tokens /home/mgogala/test_proj/config/propel.ini
>> tokens /home/mgogala/test_proj/config/config.php
>> chmod 777 /home/mgogala/test_proj/cache
>> chmod 777 /home/mgogala/test_proj/log
>> chmod 777 /home/mgogala/test_proj/web/uploads
>> chmod 777 /home/mgogala/test_proj/symfony
>> chmod 777 web/uploads/assets
mgogala@TheBox>
第一个需要我们注意的子目录当然是 config。config 目录中的重要文件包括 databases.yml、propel.ini 和 schema.yml。

第一个文件是 databases.yml,它向 Symfony 告知 Symfony 需要连接到的 Oracle 实例的位置。该文件如下所示:

all: 
propel:
class: sfPropelDatabase
param:
phptype: oracle
host: localhost
database: test11
username: scott
password: tiger
该文件具有自我说明性,可用作模板。我们还需要为 Propel(即我们指定的 ORM)提供一个描述文件。该配置文件名为 propel.ini,如下所示:

propel.targetPackage    = lib.model 
propel.packageObjectModel = true
propel.project = test_proj
propel.database = oracle
propel.database.createUrl = oracle://scott:tiger@localhost/test11
propel.database.url = oracle://scott:tiger@localhost/test11
propel.addGenericAccessors = true
propel.addGenericMutators = true
propel.addTimeStamp = false

propel.schema.validate = false

; directories
propel.home = .
propel.output.dir = /home/mgogala/test_proj
propel.schema.dir = ${propel.output.dir}/config
propel.conf.dir = ${propel.output.dir}/config
propel.phpconf.dir = ${propel.output.dir}/config
propel.sql.dir = ${propel.output.dir}/data/sql
propel.runtime.conf.file = runtime-conf.xml
propel.php.dir = ${propel.output.dir}
propel.default.schema.basename = schema
.....
该文件与第一个文件非常相似,它配置 Propel 与数据库的连接。这里,最后一个重要文件是 schema.yml,它描述 Oracle 模式。在我们的例子中,这个文件如下所示:

propel: 
_attributes:
package: lib.model
emp:
empno:
type: integer
size: 22
primaryKey: true
autoIncrement: true
ename:
type: varchar(10)
size: 10
job:
type: varchar(9)
size: 9
mgr:
type: integer
size: 22
foreignTable: emp
foreignReference: empno
hiredate:
type: date
size: 7
sal:
type: numeric
size: 22
comm:
type: numeric
size: 22
deptno:
type: integer
size: 22
foreignTable: dept
foreignReference: deptno
onDelete: CASCADE
_indexes:
emp_deptno_i:
deptno
emp_mgr_i:
mgr
dept:
deptno:
deptno:
type: integer
size: 22
primaryKey: true
autoIncrement: true
dname:
type: varchar(14)
size: 14
loc:
type: varchar(13)
size: 13
很明显,这个文件包含了构造我们的应用程序所需要的表和列的描述。主键列的 autoIncrement 属性会创建序列来实现自动增加功能,某些其他数据库自身提供了该特性。显然,只有主键为数字型的情况下,该属性才有意义。Symfony 可以使用有关外键的信息来自动构建值列表。因此产生了一个极大的限制:Symfony 还不支持多列外键。对于每个主键,Symfony 定义了一个借助主键来获取数据的方法。因此,将主键包含在模式描述中是很重要的。

这里可以下载一个小的 Perl 脚本,它可以帮助生成 schema.yml。该脚本本身极其简单,使用如下:

symfony_yaml -u scott/tiger@test11 -t "emp,dept" -f /tmp/schema.yml 
结果是上面所示的文件。Web 应用程序很少使用大量的表;它们通常访问三到四个表。对于 -t 标志来说,列出它们很容易。另外还提供了帮助:

mg> symfony_yaml -h 
symfony_yaml -> Produce YAML description of given tables for Symfony
app. generator. The output can be used as "schema.yml"
configuration file.
USAGE:symfony_yaml -u=<user> -p=<passwd> -t <table1,table2,..>
-f <output file>
OPTIONS: -u Oracle username (standard u/p@d syntax is supported)
-p Password for the above.
-d Database to connect to.
-t Tables to describe.
-ns Do not generate "autoIncrement: true" for the primary key.
-f Output file.
-h This screen.

-------
Username and password are mandatory arguments. Default
for the output file is standard output. For help,
try -help or -h.
现在我们的描述文件已经准备好了,可以通过发出 symfony propel-build-model 命令来生成关系数据库管理系统表到对象类的 Propel 对象映射。

mgogala@TheBox> cd ~/test_proj/ 
mgogala@TheBox> symfony propel-build-model
>> schema converting "/home/mgogala/test_proj/config/schema.yml" to XML
>> schema putting /home/mgogala/test_proj/config/generated-schema.xml
Buildfile: /usr/local/lib/php/symfony/vendor/propel-generator/build.xml
[resolvepath] Resolved /home/mgogala/test_proj/config to /home/mgogala/test_proj/config

propel-project-builder > check-project-or-dir-set:

propel-project-builder > check-project-set:

propel-project-builder > set-project-dir:

propel-project-builder > check-buildprops-exists:

propel-project-builder > check-buildprops-for-propel-gen:

propel-project-builder > check-buildprops:

propel-project-builder > configure:
[echo] Loading project-specific props from /home/mgogala/test_proj/config/propel.ini
[property] Loading /home/mgogala/test_proj/config/propel.ini

propel-project-builder > om:
[phing] Calling Buildfile '/usr/local/lib/php/symfony/vendor/propel-generator/build-propel.xml' with target 'om'
[property] Loading /usr/local/lib/php/symfony/vendor/propel-generator/./default.properties

propel > check-run-only-on-schema-change:

propel > om-check:

propel > om:
[echo] +------------------------------------------+
[echo] | |
[echo] | Generating Peer-based Object Model for |
[echo] | YOUR Propel project! (NEW OM BUILDERS)! |
[echo] | |
[echo] +------------------------------------------+
[phingcall] Calling Buildfile '/usr/local/lib/php/symfony/vendor/propel-generator/build-propel.xml' with target 'om-template'
[property] Loading /usr/local/lib/php/symfony/vendor/propel-generator/./default.properties

propel > om-template:
[propel-om] Target database type: oracle
[propel-om] Target package: lib.model
[propel-om] Using template path: /usr/local/lib/php/symfony/vendor/propel-generator/templates
[propel-om] Output directory: /home/mgogala/test_proj
[propel-om] Processing: generated-schema.xml
[propel-om] Processing Datamodel : JoinedDataModel
[propel-om] - processing database : propel
[propel-om] + emp
[propel-om] -> BaseEmpPeer [builder: SfPeerBuilder]
[propel-om] -> BaseEmp [builder: SfObjectBuilder]
[propel-om] -> EmpMapBuilder [builder: SfMapBuilderBuilder]
[propel-om] -> EmpPeer [builder: SfExtensionPeerBuilder]
[propel-om] -> Emp [builder: SfExtensionObjectBuilder]
[propel-om] + dept
[propel-om] -> BaseDeptPeer [builder: SfPeerBuilder]
[propel-om] -> BaseDept [builder: SfObjectBuilder]
[propel-om] -> DeptMapBuilder [builder: SfMapBuilderBuilder]
[propel-om] -> DeptPeer [builder: SfExtensionPeerBuilder]
[propel-om] -> Dept [builder: SfExtensionObjectBuilder]

BUILD FINISHED

Total time: 0.6661 seconds
>> file- /home/mgogala/test_proj/config/generated-schema.xml
mgogala@TheBox>
模型已生成。如果仔细查看输出,您将发现第一步是将 YAML 文件 schema.yml 转换为一个 XML 文件,最后一步是将关系对象映射为一组对象类。您还可以通过发布 symfony propel-build-sql 命令生成创建 Oracle 对象所需的数据定义语言。

mgogala@TheBox> symfony propel-build-sql 
>> schema converting "/home/mgogala/test_proj/config/schema.yml" to XML
>> schema putting /home/mgogala/test_proj/config/generated-schema.xml
Buildfile: /usr/local/lib/php/symfony/vendor/propel-generator/build.xml
[resolvepath] Resolved /home/mgogala/test_proj/config to /home/mgogala/test_proj/config

propel-project-builder > check-project-or-dir-set:

propel-project-builder > check-project-set:

propel-project-builder > set-project-dir:

propel-project-builder > check-buildprops-exists:

propel-project-builder > check-buildprops-for-propel-gen:

propel-project-builder > check-buildprops:

propel-project-builder > configure:
[echo] Loading project-specific props from /home/mgogala/test_proj/config/propel.ini
[property] Loading /home/mgogala/test_proj/config/propel.ini

propel-project-builder > sql:
[phing] Calling Buildfile '/usr/local/lib/php/symfony/vendor/propel-generator/build-propel.xml' with target 'sql'
[property] Loading /usr/local/lib/php/symfony/vendor/propel-generator/./default.properties

propel > check-run-only-on-schema-change:

propel > sql-check:

propel > pgsql-quoting-check:

propel > sql:
[echo] +------------------------------------------+
[echo] | |
[echo] | Generating SQL for YOUR Propel project! |
[echo] | |
[echo] +------------------------------------------+
[phingcall] Calling Buildfile '/usr/local/lib/php/symfony/vendor/propel-generator/build-propel.xml' with target 'sql-template'
[property] Loading /usr/local/lib/php/symfony/vendor/propel-generator/./default.properties

propel > sql-template:
[propel-sql] Processing: generated-schema.xml
[propel-sql] Writing to SQL file: /home/mgogala/test_proj/data/sql/lib.model.schema.sql
[propel-sql] + emp [builder: OracleDDLBuilder]
[propel-sql] + dept [builder: OracleDDLBuilder]

BUILD FINISHED

Total time: 0.3073 seconds
>> file- /home/mgogala/test_proj/config/generated-schema.xml
mgogala@TheBox>

生成的文件名为 /home/mgogala/test_proj/data/sql/lib.model.schema.sql。它如下所示:

/* ----------------------------------------------------------------------- 
emp
----------------------------------------------------------------------- */

DROP TABLE "emp" CASCADE CONSTRAINTS;

DROP SEQUENCE "emp_SEQ";


CREATE TABLE "emp"
(
"empno" NUMBER(22) NOT NULL,
"ename" VARCHAR2(10),
"job" VARCHAR2(9),
"mgr" NUMBER(22),
"hiredate" DATE(7),
"sal" NUMBER(22),
"comm" NUMBER(22),
"deptno" NUMBER(22)
);
ALTER TABLE "emp"
ADD CONSTRAINT "emp_PK"
PRIMARY KEY ("empno");
CREATE INDEX "emp_deptno_i" ON "emp" ();
CREATE INDEX "emp_mgr_i" ON "emp" ();
CREATE SEQUENCE "emp_SEQ" INCREMENT BY 1 START WITH 1 NOMAXVALUE NOCYCLE NOCACHE ORDER;
CREATE INDEX "emp_deptno_i" ON "emp" ();
CREATE INDEX "emp_mgr_i" ON "emp" ();

ALTER TABLE "emp" ADD CONSTRAINT "emp_FK_1" FOREIGN KEY ("mgr") REFERENCES "emp" ("empno");

ALTER TABLE "emp" ADD CONSTRAINT "emp_FK_2" FOREIGN KEY ("deptno") REFERENCES "dept" ("deptno") ON DELETE CASCADE;
这个生成的脚本仅用于演示目的,运行它的话可能会被其误导。由于大量使用了双引号,因此所有表名称和列名称都将用小写字母生成。换言之,Symfony 不是一个 CASE 工具;它不是用来从 YAML 描述文件开发 Oracle 模式的。另外,请注意生成的 SQL 包含 DROP 语句,这意味着您不应该在已经存在的表上运行它。实现映射的 PHP 文件更加复杂,将在稍后说明。

该脚本的唯一实际作用就是检查 Symfony 的数据模型视图是否与实际情况一致。在我们例子中,是一致的。只有在底层应用程序生成器可以正确描述基础数据模型时,才适合由应用程序生成器生成应用程序。这个通用原则不仅适用于 Symfony,还适用于 Django、Ruby on Rails、Jifty 或者任何其他此类工具。(如果数据模型非常复杂,则需要专业的 CASE 工具,如 Oracle 业务流程分析套件)。Symfony 以及它的相关开源项目适合快速生成相对简单的应用程序,但是它们不能取代专业的 CASE 工具,这些 CASE 工具是企业资源规划或专业财务建模这类事情所需要的。然而,我们的模式却属于“简单的”一类。

您的模式已经描述完毕,可以生成我们的应用程序了。

生成应用程序

首先,您应该通过发出 symfony init-app <应用程序名称> 来生成应用程序框架。将应用程序命名为“frontend”。

mgogala@TheBox> symfony init-app frontend 
>> dir+ /home/mgogala/test_proj/apps/frontend/templates
>> file+ /home/mgogala/test_proj/apps/frontend/templates/layout.php
>> dir+ /home/mgogala/test_proj/apps/frontend/modules
>> dir+ /home/mgogala/test_proj/apps/frontend/config
>> file+ /home/mgogala/test_proj/apps/frontend/config/filters.yml
>> file+ /home/mgogala/test_proj/apps/frontend/config/view.yml
>> file+ /home/mgogala/test_proj/apps/frontend/config/config.php
>> file+ /home/mgogala/test_proj/apps/frontend/config/cache.yml
>> file+ /home/mgogala/test_proj/apps/frontend/config/settings.yml
>> file+ /home/mgogala/test_proj/apps/frontend/config/factories.yml
>> file+ /home/mgogala/test_proj/apps/frontend/config/security.yml
>> file+ /home/mgogala/test_proj/apps/frontend/config/routing.yml
>> file+ /home/mgogala/test_proj/apps/frontend/config/logging.yml
>> file+ /home/mgogala/test_proj/apps/frontend/config/app.yml
>> file+ /home/mgogala/test_proj/apps/frontend/config/i18n.yml
>> dir+ /home/mgogala/test_proj/apps/frontend/i18n
>> dir+ /home/mgogala/test_proj/apps/frontend/lib
>> file+ /home/mgogala/test_proj/apps/frontend/lib/myUser.class.php
>> tokens /home/mgogala/test_proj/apps/frontend/config/settings.yml
>> file+ /home/mgogala/test_proj/web/frontend.php
>> tokens /home/mgogala/test_proj/web/frontend_dev.php
>> tokens /home/mgogala/test_proj/web/frontend.php
>> chmod 777 /home/mgogala/test_proj/cache
>> chmod 777 /home/mgogala/test_proj/log
>> chmod 777 /home/mgogala/test_proj/web/uploads
>> chmod 777 /home/mgogala/test_proj/symfony
>> chmod 777 web/uploads/assets
mgogala@TheBox>
这个命令从项目目录结构之上发布,所有的 Symfony 命令都是这样。现在,您需要生成模块。为此,需要为每个表(在本例中是 EMP 和 DEPT)发出命令 symfony propel-init-admin <应用程序名称> <表名称> <模块名称>

mgogala@TheBox> symfony propel-init-admin frontend emp Emp 
>> dir+ /home/mgogala/test_proj/apps/frontend/modules/emp/config
>> file+ /home/mgogala/test_proj/apps/fr...odules/emp/config/generator.yml
>> dir+ /home/mgogala/test_proj/apps/frontend/modules/emp/actions
>> file+ /home/mgogala/test_proj/apps/fr...s/emp/actions/actions.class.php
>> tokens /home/mgogala/test_proj/apps/fr...odules/emp/config/generator.yml
>> tokens /home/mgogala/test_proj/apps/fr...s/emp/actions/actions.class.php
mgogala@TheBox> symfony propel-init-admin frontend dept Dept
>> dir+ /home/mgogala/test_proj/apps/frontend/modules/dept/config
>> file+ /home/mgogala/test_proj/apps/fr...dules/dept/config/generator.yml
>> dir+ /home/mgogala/test_proj/apps/frontend/modules/dept/actions
>> file+ /home/mgogala/test_proj/apps/fr.../dept/actions/actions.class.php
>> tokens /home/mgogala/test_proj/apps/fr...dules/dept/config/generator.yml
>> tokens /home/mgogala/test_proj/apps/fr.../dept/actions/actions.class.php
就这样:您已经生成了一个简单的应用程序!现在,您在浏览器中访问 http://localhost/emp/list 就可以看到它。当然,这只是一个开始。通过修改每个模块的模块生成器配置文件 generator.yml,您可以设置分页、列名称、列格式,甚至加入搜索部件。该文件位于您项目主目录下的目录中:test_proj/apps/frontend/modules/emp/config。您为每个表生成了一个模块,因此您有一个模块 emp。

这里是一个非常简单的版本:使用它生成下面的基本应用程序:

generator: 
class: sfPropelAdminGenerator
param:
model_class: Emp
theme: default
list:
title: Company Employees
max_per_page: 7
filters: [ ename ]
fields:
hiredate: { params: date_format='MM/dd/yy' }
ename: { name: Employee Name }
修改 generator.yml 文件时要谨慎;它是分层次的且使用空格缩进。针对使用管理生成器,项目网站上有一个不错的教程。

结果如下所示:

这只是一个基本的小应用程序,但是现在您有事可做了 — 而且创建它只需五分钟。

注意页标题是 Company Employees,ENAME 列显示为 Employee Name,HIREDATE 列的格式是 MM/DD/YY,与上面的 generator.yml 文件中指定的一致。本页上只有七个员工,有下一页、上一页、第一页和最后一页的链接。此外,主键字段很清楚地标记为链接。单击这些链接将显示修改表单,可用于修改有问题的记录。还有一个小部件,可以让我们按姓名搜索员工。CREATE 按钮提供 INSERT 功能,帮助您插入新记录。

修改基础 SQL

对象关系映射器将 SQL 语句映射为对象类。这意味着,为了修改我们的程序发布的 SQL 语句,我们必须修改应用程序生成器生成的代码。Symfony 用同样干净的方式生成代码,放入主项目目录的缓存子目录中。我们的映射后的对象类的操作定义在名为 actions.class.php 的文件中,它位于 test_proj/cache/frontend/prod/modules/autoEmp/actions 目录中 — 这是 emp 模块的缓存。该文件是一个 PHP 脚本,包含类定义。通过使用 Symfony 提供的文件,可以覆盖这些类中的方法。

该文件名当然是 actions.class.php,但是它位于应用程序定义树中,在 apps/frontend/modules/emp/actions 目录中,而不是在缓存树中。提供的文件如下所示:

<?php

/**
* emp actions.
*
* @package test_proj
* @subpackage emp
* @author Your name here
* @version SVN: $Id: actions.class.php 2288 2006-10-02 15:22:13Z fabien $
*/
class empActions extends autoempActions
{
}
汗颜之,它是一个空的存根。要修改 SQL 并变更行为,您需要修改这个文件。针对我们的示例程序修改后,该文件如下所示:
<?php
// auto-generated by sfPropelAdmin
// date: 2008/04/11 12:44:09
?>
<?php

/**
* autoEmp actions.
*
* @package ##PROJECT_NAME##
* @subpackage autoEmp
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: actions.class.php 7997 2008-03-20 12:29:34Z noel $
*/
class empActions extends autoempActions
{
public function executeList()
{
$this->processSort();

$this->processFilters();

$this->filters = $this->getUser()->getAttributeHolder()->getAll('sf_admin/emp/filters');

// pager
$this->pager = new sfPropelPager('Emp', 20);
$c = new Criteria();


$c ->addAscendingOrderByColumn(EmpPeer::DEPTNO);
$this->addSortCriteria($c); $this->addFiltersCriteria($c); $this->pager->setCriteria($c); $this->pager->setPage($this->getRequestParameter('page', 1)); $this->pager->init(); } public function addFiltersCriteria($c) { if (isset($this->filters['ename_is_empty'])) { $criterion = $c->getNewCriterion(EmpPeer::ENAME, ''); $criterion->addOr($c->getNewCriterion(EmpPeer::ENAME, null, Criteria::ISNULL)); $c->add($criterion); } else if (isset($this->filters['ename']) && $this->filters['ename'] !== '') {
$c->add(EmpPeer::ENAME, "ENAME LIKE UPPER('".$this->filters['ename']."%')", Criteria::CUSTOM);
} } }
代码是从缓存树中的版本复制过来的,为了提供不同的行为而进行了修改。以黑体显示的代码按 deptno 对输入进行排序,并确保按 ENAME 列进行搜索是不区分大小写的。修改 Criteriaclass 不像看起来那么复杂。像我对筛选器类所做的一样,有很多通过文档详细描述的函数可以用来输入我们自己的 SQL,以修改排序列以及执行许多不同的操作。现在,只剩下最后一件事了:
cd ~/test_proj; symfony cc
这将清空缓存(删除缓存树中的一切),并在下次调用时从应用程序树中重新生成它。 ,现在我们的应用程序已经准备好了。引用 URL http://localhost/emp/list 将自动重新生成应用程序,并由上面的做法覆盖默认行为。

结论

Symfony 是一个大而复杂的应用程序生成器,有很多选项,在一篇相对较小的文章中描述它并不是件容易的任务。大多数工作都通过创建 YAML 描述文件完成,但是肯定会有“一些需要组装的”部分。该工具能与版本控制良好配合,有大量插件选择,并且相对容易学习,能快速上手。目前的版本 1.0.15 有两个主要局限:Propel ORM 的复杂性以及缺少对多列外键的支持。

在不久的将来,Symfony 中的 Propel ORM 将由 Doctrine 取代。Doctrine 的灵感来自于 Java Hibernate 框架以及它的 Hibernate 查询语言 (HQL)。

Symfony 1.1 版目前处于 RC1(第一版候选)阶段。Oracle 数据库 11g 与 Symfony 是一个完美组合,因为它们联合起来,可以轻松创建外观好、容易扩展且只需较少工作量就能满足客户需要的高性能应用程序。我希望您能享受二者结合使用的乐趣。


Mladen Gogala 是一位资深 Oracle DBA,并且是 Easy Oracle PHP (2006) 的作者。他在使用 UNIX 和 Linux 的每种流行方言进行 UNIX 脚本编写、Oracle 调整与 UNIX 系统管理等方面有着丰富的经验。Mladen Gogala 还活跃于 Usenet Oracle 论坛,帮助解决 Oracle 问题。